From ed55fafeb53883e86e33fc39849d24c5c3d3318e Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:34:25 -0500 Subject: [PATCH 01/20] Fix home image size Fixes #1493 --- components/home/HomeRows.bs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 100a41b06..1ae7b93a7 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -188,7 +188,14 @@ sub createLatestInRows(content as dynamic, sizeArray as dynamic) m.homeSectionIndexes.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), m.homeSectionIndexes.count) m.homeSectionIndexes.count++ - sizeArray.Push([464, 331]) + + if LCase(lib.collectionType) = "movies" + sizeArray.Push([188, 331]) + else if LCase(lib.collectionType) = "music" + sizeArray.Push([261, 331]) + else + sizeArray.Push([464, 331]) + end if loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" @@ -482,7 +489,6 @@ sub updateLatestItems(msg) m.homeSectionIndexes.AddReplace(sectionName, rowIndex) m.top.content.insertChild(row, rowIndex) - updateSizeArray(itemSize, rowIndex) return end if From 0a7d74d291f79d38843c09f1795b5eb3763defea Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:05:20 -0500 Subject: [PATCH 02/20] Revert "Fix home image size" This reverts commit ed55fafeb53883e86e33fc39849d24c5c3d3318e. --- components/home/HomeRows.bs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 1ae7b93a7..100a41b06 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -188,14 +188,7 @@ sub createLatestInRows(content as dynamic, sizeArray as dynamic) m.homeSectionIndexes.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), m.homeSectionIndexes.count) m.homeSectionIndexes.count++ - - if LCase(lib.collectionType) = "movies" - sizeArray.Push([188, 331]) - else if LCase(lib.collectionType) = "music" - sizeArray.Push([261, 331]) - else - sizeArray.Push([464, 331]) - end if + sizeArray.Push([464, 331]) loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" @@ -489,6 +482,7 @@ sub updateLatestItems(msg) m.homeSectionIndexes.AddReplace(sectionName, rowIndex) m.top.content.insertChild(row, rowIndex) + updateSizeArray(itemSize, rowIndex) return end if From 35dfa54a29e39cc0fd8666c74d11e21579d5ab96 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:14:35 -0500 Subject: [PATCH 03/20] Rework how we keep track of row item sizes --- components/home/HomeRows.bs | 200 +++++++++++++++++++----------------- 1 file changed, 103 insertions(+), 97 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 100a41b06..56ebdec7e 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -12,9 +12,7 @@ sub init() m.top.rowLabelOffset = [0, 20] m.top.showRowCounter = [true] - m.homeSectionIndexes = { - count: 0 - } + m.homeSections = {} updateSize() @@ -67,13 +65,12 @@ sub onLibrariesLoaded() m.LoadLibrariesTask.content = [] content = CreateObject("roSGNode", "ContentNode") - sizeArray = [] loadedSections = 0 ' Add sections in order based on user settings for i = 0 to 6 sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()]) - sectionLoaded = addHomeSection(content, sizeArray, sectionName) + sectionLoaded = addHomeSection(content, sectionName) ' Count how many sections with data are loaded if sectionLoaded then loadedSections++ @@ -88,9 +85,10 @@ sub onLibrariesLoaded() end for ' Favorites isn't an option on Web settings, so we must manually add it for now - addHomeSection(content, sizeArray, "favorites") + addHomeSection(content, "favorites") + + setRowItemSizes() - m.top.rowItemSize = sizeArray m.top.content = content end sub @@ -98,57 +96,71 @@ end sub sub removeHomeSection(sectionType as string) sectionName = LCase(sectionType) - removedSectionIndex = m.homeSectionIndexes[sectionName] + removedSection = m.homeSections[sectionName] - if not isValid(removedSectionIndex) then return + if not isValid(removedSection) then return + if not isValid(removedSection.index) then return - for each section in m.homeSectionIndexes - if m.homeSectionIndexes[section] > removedSectionIndex - m.homeSectionIndexes[section]-- + for each section in m.homeSections + if m.homeSections[section].index > removedSection.index + m.homeSections[section].index-- end if end for - m.homeSectionIndexes.Delete(sectionName) + m.homeSections.Delete(sectionName) + m.top.content.removeChildIndex(removedSection.index) + + setRowItemSizes() +end sub + +' setRowItemSizes: Loops through all home sections and sets the correct item sizes per row +' +sub setRowItemSizes() + newSizeArray = CreateObject("roArray", m.homeSections.count(), false) + + for each section in m.homeSections + newSizeArray[m.homeSections[section].index] = m.homeSections[section].imagesize + end for - m.top.content.removeChildIndex(removedSectionIndex) + m.top.rowItemSize = newSizeArray end sub ' Adds a new home section to the home rows. ' Returns a boolean indicating whether the section was handled. -function addHomeSection(content as dynamic, sizeArray as dynamic, sectionName as string) as boolean +function addHomeSection(content as dynamic, sectionName as string) as boolean ' Poster size library items if sectionName = "livetv" - createLiveTVRow(content, sizeArray) + createLiveTVRow(content) return true end if ' Poster size library items if sectionName = "smalllibrarytiles" - createLibraryRow(content, sizeArray) + createLibraryRow(content) return true end if ' Continue Watching items if sectionName = "resume" - createContinueWatchingRow(content, sizeArray) + createContinueWatchingRow(content) return true end if ' Next Up items if sectionName = "nextup" - createNextUpRow(content, sizeArray) + createNextUpRow(content) return true end if ' Latest items in each library if sectionName = "latestmedia" - createLatestInRows(content, sizeArray) + createLatestInRows(content) return true end if ' Favorite Items if sectionName = "favorites" - createFavoritesRow(content, sizeArray) + createFavoritesRow(content) return true end if @@ -156,17 +168,17 @@ function addHomeSection(content as dynamic, sizeArray as dynamic, sectionName as end function ' Create a row displaying the user's libraries -sub createLibraryRow(content as dynamic, sizeArray as dynamic) +sub createLibraryRow(content as dynamic) ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return mediaRow = content.CreateChild("HomeRow") mediaRow.title = tr("My Media") - m.homeSectionIndexes.AddReplace("library", m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ - - sizeArray.push([464, 331]) + m.homeSections.AddReplace("library", { + imageSize: [464, 331], + index: m.homeSections.count() + }) filteredMedia = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.MyMediaExcludes) for each item in filteredMedia @@ -175,7 +187,7 @@ sub createLibraryRow(content as dynamic, sizeArray as dynamic) end sub ' Create a row displaying latest items in each of the user's libraries -sub createLatestInRows(content as dynamic, sizeArray as dynamic) +sub createLatestInRows(content as dynamic) ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return @@ -186,9 +198,18 @@ sub createLatestInRows(content as dynamic, sizeArray as dynamic) latestInRow = content.CreateChild("HomeRow") latestInRow.title = tr("Latest in") + " " + lib.name + " >" - m.homeSectionIndexes.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ - sizeArray.Push([464, 331]) + imagesize = [464, 331] + + if LCase(lib.collectionType) = "movies" + imagesize = [188, 331] + else if LCase(lib.collectionType) = "music" + imagesize = [261, 331] + end if + + m.homeSections.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), { + imageSize: imagesize, + index: m.homeSections.count() + }) loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" @@ -205,24 +226,26 @@ sub createLatestInRows(content as dynamic, sizeArray as dynamic) end sub ' Create a row displaying the live tv now on section -sub createLiveTVRow(content as dynamic, sizeArray as dynamic) +sub createLiveTVRow(content as dynamic) contentRow = content.CreateChild("HomeRow") contentRow.title = tr("On Now") - m.homeSectionIndexes.AddReplace("livetv", m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ - sizeArray.push([464, 331]) + m.homeSections.AddReplace("livetv", { + imageSize: [464, 331], + index: m.homeSections.count() + }) m.LoadOnNowTask.observeField("content", "updateOnNowItems") m.LoadOnNowTask.control = "RUN" end sub ' Create a row displaying items the user can continue watching -sub createContinueWatchingRow(content as dynamic, sizeArray as dynamic) +sub createContinueWatchingRow(content as dynamic) continueWatchingRow = content.CreateChild("HomeRow") continueWatchingRow.title = tr("Continue Watching") - m.homeSectionIndexes.AddReplace("resume", m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ - sizeArray.push([464, 331]) + m.homeSections.AddReplace("resume", { + imageSize: [464, 331], + index: m.homeSections.count() + }) ' Load the Continue Watching Data m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") @@ -230,12 +253,13 @@ sub createContinueWatchingRow(content as dynamic, sizeArray as dynamic) end sub ' Create a row displaying next episodes up to watch -sub createNextUpRow(content as dynamic, sizeArray as dynamic) +sub createNextUpRow(content as dynamic) nextUpRow = content.CreateChild("HomeRow") nextUpRow.title = tr("Next Up >") - m.homeSectionIndexes.AddReplace("nextup", m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ - sizeArray.push([464, 331]) + m.homeSections.AddReplace("nextup", { + imageSize: [464, 331], + index: m.homeSections.count() + }) ' Load the Next Up Data m.LoadNextUpTask.observeField("content", "updateNextUpItems") @@ -243,13 +267,14 @@ sub createNextUpRow(content as dynamic, sizeArray as dynamic) end sub ' Create a row displaying items from the user's favorites list -sub createFavoritesRow(content as dynamic, sizeArray as dynamic) +sub createFavoritesRow(content as dynamic) favoritesRow = content.CreateChild("HomeRow") favoritesRow.title = tr("Favorites") - sizeArray.Push([464, 331]) - m.homeSectionIndexes.AddReplace("favorites", m.homeSectionIndexes.count) - m.homeSectionIndexes.count++ + m.homeSections.AddReplace("favorites", { + imageSize: [464, 331], + index: m.homeSections.count() + }) ' Load the Favorites Data m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") @@ -259,25 +284,25 @@ end sub ' Update home row data sub updateHomeRows() ' If resume section exists, reload row's data - if m.homeSectionIndexes.doesExist("resume") + if m.homeSections.doesExist("resume") m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") m.LoadContinueWatchingTask.control = "RUN" end if ' If next up section exists, reload row's data - if m.homeSectionIndexes.doesExist("nextup") + if m.homeSections.doesExist("nextup") m.LoadNextUpTask.observeField("content", "updateNextUpItems") m.LoadNextUpTask.control = "RUN" end if ' If favorites section exists, reload row's data - if m.homeSectionIndexes.doesExist("favorites") + if m.homeSections.doesExist("favorites") m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") m.LoadFavoritesTask.control = "RUN" end if ' If live tv's on now section exists, reload row's data - if m.homeSectionIndexes.doesExist("livetv") + if m.homeSections.doesExist("livetv") m.LoadOnNowTask.observeField("content", "updateOnNowItems") m.LoadOnNowTask.control = "RUN" end if @@ -285,7 +310,7 @@ sub updateHomeRows() ' If latest in library section exists, reload row's data hasLatestHomeSection = false - for each section in m.homeSectionIndexes + for each section in m.homeSections if LCase(Left(section, 6)) = "latest" hasLatestHomeSection = true exit for @@ -295,6 +320,7 @@ sub updateHomeRows() if hasLatestHomeSection updateLatestInRows() end if + end sub sub updateFavoritesItems() @@ -304,7 +330,7 @@ sub updateFavoritesItems() if itemData = invalid then return - rowIndex = m.homeSectionIndexes.favorites + rowIndex = m.homeSections.favorites.index if itemData.count() < 1 removeHomeSection("favorites") @@ -359,7 +385,7 @@ sub updateContinueWatchingItems() end for ' replace the old row - m.top.content.replaceChild(row, m.homeSectionIndexes.resume) + m.top.content.replaceChild(row, m.homeSections.resume.index) end sub sub updateNextUpItems() @@ -383,7 +409,7 @@ sub updateNextUpItems() end for ' replace the old row - m.top.content.replaceChild(row, m.homeSectionIndexes.nextup) + m.top.content.replaceChild(row, m.homeSections.nextup.index) end if end sub @@ -449,22 +475,23 @@ sub updateLatestItems(msg) row.appendChild(item) end for - rowIndex = m.homeSectionIndexes[sectionName] + if isValid(m.homeSections[sectionName]) + rowIndex = m.homeSections[sectionName].index - ' Replace the old row - if isValid(rowIndex) - updateSizeArray(itemSize, rowIndex, "replace") - m.top.content.replaceChild(row, rowIndex) - return + ' Replace the old row + if isValid(rowIndex) + m.top.content.replaceChild(row, rowIndex) + return + end if end if ' Determine highest index of a Lastest In section so we can append the new section after it highestLatestHomeSectionIndex = 0 - for each section in m.homeSectionIndexes + for each section in m.homeSections if LCase(Left(section, 6)) = "latest" - if m.homeSectionIndexes[section] > highestLatestHomeSectionIndex - highestLatestHomeSectionIndex = m.homeSectionIndexes[section] + if m.homeSections[section].index > highestLatestHomeSectionIndex + highestLatestHomeSectionIndex = m.homeSections[section].index end if end if end for @@ -473,16 +500,21 @@ sub updateLatestItems(msg) rowIndex = highestLatestHomeSectionIndex + 1 ' Advance all the indexes greater than or equal than our new row - for each section in m.homeSectionIndexes - if m.homeSectionIndexes[section] >= rowIndex - m.homeSectionIndexes[section]++ + for each section in m.homeSections + if m.homeSections[section].index >= rowIndex + m.homeSections[section].index++ end if end for - m.homeSectionIndexes.AddReplace(sectionName, rowIndex) + m.homeSections.AddReplace(sectionName, { + imageSize: itemSize, + index: rowIndex + }) m.top.content.insertChild(row, rowIndex) - updateSizeArray(itemSize, rowIndex) + + ' We've inserted a new row, we must set the row sizes again to ensure they're correct + setRowItemSizes() return end if @@ -502,7 +534,7 @@ sub updateOnNowItems() ' remake row using the new data row = CreateObject("roSGNode", "HomeRow") row.title = tr("On Now") - itemSize = [464, 331] + 'itemSize = [464, 331] row.imageWidth = 464 for each item in itemData row.usePoster = false @@ -510,7 +542,7 @@ sub updateOnNowItems() item.thumbnailURL = item.json.imageURL row.usePoster = true row.imageWidth = 180 - itemSize = [188, 331] + 'itemSize = [188, 331] end if item.usePoster = row.usePoster item.imageWidth = row.imageWidth @@ -518,35 +550,9 @@ sub updateOnNowItems() end for ' replace the old row - updateSizeArray(itemSize, m.homeSectionIndexes.livetv, "replace") - m.top.content.replaceChild(row, m.homeSectionIndexes.livetv) - - end if -end sub + m.top.content.replaceChild(row, m.homeSections.livetv.index) -sub updateSizeArray(rowItemSize, rowIndex = invalid, action = "insert") - sizeArray = m.top.rowItemSize - ' append by default - if rowIndex = invalid - rowIndex = sizeArray.count() end if - - newSizeArray = [] - for i = 0 to sizeArray.count() - if rowIndex = i - if action = "replace" - newSizeArray.Push(rowItemSize) - else if action = "insert" - newSizeArray.Push(rowItemSize) - if isValid(sizeArray[i]) - newSizeArray.Push(sizeArray[i]) - end if - end if - else if isValid(sizeArray[i]) - newSizeArray.Push(sizeArray[i]) - end if - end for - m.top.rowItemSize = newSizeArray end sub sub itemSelected() From 142419ce66f88c705fc4306b30725497900ffbe6 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:58:21 -0500 Subject: [PATCH 04/20] Add sections to home view on update as needed --- components/home/HomeRows.bs | 71 +++++++++++++------------------------ 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 56ebdec7e..25acd3ac0 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -58,14 +58,14 @@ sub updateSize() m.top.visible = true end sub -sub onLibrariesLoaded() - ' save data for other functions - m.libraryData = m.LoadLibrariesTask.content - m.LoadLibrariesTask.unobserveField("content") - m.LoadLibrariesTask.content = [] +' processUserSections: Loop through user's chosen home section settings and generate the content for each row +' +' @return {dynamic} content node filled with child nodes for each row +function processUserSections() as dynamic + m.homeSections = {} - content = CreateObject("roSGNode", "ContentNode") loadedSections = 0 + content = CreateObject("roSGNode", "ContentNode") ' Add sections in order based on user settings for i = 0 to 6 @@ -76,8 +76,8 @@ sub onLibrariesLoaded() if sectionLoaded then loadedSections++ ' If 2 sections with data are loaded or we're at the end of the web client section data, consider the home view loaded - if loadedSections = 2 or i = 6 - if not m.global.app_loaded + if not m.global.app_loaded + if loadedSections = 2 or i = 6 m.top.signalBeacon("AppLaunchComplete") ' Roku Performance monitoring m.global.app_loaded = true end if @@ -87,6 +87,20 @@ sub onLibrariesLoaded() ' Favorites isn't an option on Web settings, so we must manually add it for now addHomeSection(content, "favorites") + return content +end function + + +' onLibrariesLoaded: Handler when LoadLibrariesTask returns data +' +sub onLibrariesLoaded() + ' save data for other functions + m.libraryData = m.LoadLibrariesTask.content + m.LoadLibrariesTask.unobserveField("content") + m.LoadLibrariesTask.content = [] + + content = processUserSections() + setRowItemSizes() m.top.content = content @@ -283,44 +297,9 @@ end sub ' Update home row data sub updateHomeRows() - ' If resume section exists, reload row's data - if m.homeSections.doesExist("resume") - m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") - m.LoadContinueWatchingTask.control = "RUN" - end if - - ' If next up section exists, reload row's data - if m.homeSections.doesExist("nextup") - m.LoadNextUpTask.observeField("content", "updateNextUpItems") - m.LoadNextUpTask.control = "RUN" - end if - - ' If favorites section exists, reload row's data - if m.homeSections.doesExist("favorites") - m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") - m.LoadFavoritesTask.control = "RUN" - end if - - ' If live tv's on now section exists, reload row's data - if m.homeSections.doesExist("livetv") - m.LoadOnNowTask.observeField("content", "updateOnNowItems") - m.LoadOnNowTask.control = "RUN" - end if - - ' If latest in library section exists, reload row's data - hasLatestHomeSection = false - - for each section in m.homeSections - if LCase(Left(section, 6)) = "latest" - hasLatestHomeSection = true - exit for - end if - end for - - if hasLatestHomeSection - updateLatestInRows() - end if - + content = processUserSections() + setRowItemSizes() + m.top.content = content end sub sub updateFavoritesItems() From a5af2555bf8a62274a38c75157e08c75ef7376cd Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:23:04 -0500 Subject: [PATCH 05/20] Reset focus to selected item when returning to home view --- components/home/HomeRows.bs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 25acd3ac0..9ab208768 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -333,6 +333,8 @@ sub updateFavoritesItems() ' replace the old row m.top.content.replaceChild(row, rowIndex) + ' Set focus on previously focused item + setFocusToPreviousFocusedItem() end if end sub @@ -365,6 +367,8 @@ sub updateContinueWatchingItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.resume.index) + ' Set focus on previously focused item + setFocusToPreviousFocusedItem() end sub sub updateNextUpItems() @@ -389,6 +393,8 @@ sub updateNextUpItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.nextup.index) + ' Set focus on previously focused item + setFocusToPreviousFocusedItem() end if end sub @@ -460,6 +466,10 @@ sub updateLatestItems(msg) ' Replace the old row if isValid(rowIndex) m.top.content.replaceChild(row, rowIndex) + + ' Set focus on previously focused item + setFocusToPreviousFocusedItem() + return end if end if @@ -499,6 +509,16 @@ sub updateLatestItems(msg) end if end sub +' setFocusToPreviousFocusedItem: Sets the cursor focus to the row and item previously selected +' +sub setFocusToPreviousFocusedItem() + if isValid(m.selectedRowItem) + if isValid(m.homeSections[m.selectedRowItem[0]]) + m.top.jumpToRowItem = [m.homeSections[m.selectedRowItem[0]].index, m.selectedRowItem[1]] + end if + end if +end sub + sub updateOnNowItems() itemData = m.LoadOnNowTask.content m.LoadOnNowTask.unobserveField("content") @@ -530,11 +550,19 @@ sub updateOnNowItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.livetv.index) + ' Set focus on previously focused item + setFocusToPreviousFocusedItem() end if end sub sub itemSelected() + for each section in m.homeSections + if m.homeSections[section].index = m.top.rowItemSelected[0] + m.selectedRowItem = [section, m.top.rowItemSelected[1]] + end if + end for + m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) 'Prevent the selected item event from double firing From 06af8b203019b5e8e7453ed6e2b1072260ded035 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 22 Nov 2023 20:55:41 -0500 Subject: [PATCH 06/20] Don't allow Roku's component reuse to mess up library fonts --- components/home/HomeItem.bs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/components/home/HomeItem.bs b/components/home/HomeItem.bs index f83be55ad..ff84644d2 100644 --- a/components/home/HomeItem.bs +++ b/components/home/HomeItem.bs @@ -65,6 +65,10 @@ sub itemContentChanged() ' Format the Data based on the type of Home Data if itemData.type = "CollectionFolder" or itemData.type = "UserView" or itemData.type = "Channel" + m.itemText.font.size = 35 + m.itemText.height = 64 + m.itemText.horizAlign = "center" + m.itemText.vertAlign = "bottom" m.itemText.text = itemData.name m.itemPoster.uri = itemData.widePosterURL return From 867667f5168d1619f290682c6ad1a6db8cba32d1 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Thu, 23 Nov 2023 08:52:44 -0500 Subject: [PATCH 07/20] Add setting to match web's home sections --- .vscode/settings.json | 2 +- components/ImageSizes.bs | 5 +++ components/home/HomeRows.bs | 75 ++++++++++++++++++++++++------------ locale/en_US/translations.ts | 10 +++++ settings/settings.json | 7 ++++ source/utils/misc.bs | 3 ++ source/utils/session.bs | 14 +++++++ 7 files changed, 90 insertions(+), 26 deletions(-) create mode 100644 components/ImageSizes.bs diff --git a/.vscode/settings.json b/.vscode/settings.json index a005ef427..746c772b1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,4 +18,4 @@ "docs/api/**": true }, "brightscriptcomment.addExtraAtStartAndEnd": false -} +} \ No newline at end of file diff --git a/components/ImageSizes.bs b/components/ImageSizes.bs new file mode 100644 index 000000000..2371a30fc --- /dev/null +++ b/components/ImageSizes.bs @@ -0,0 +1,5 @@ +namespace imageSizes + const WIDE_POSTER = [464, 331] + const MOVIE_POSTER = [188, 331] + const MUSIC_ALBUM = [261, 331] +end namespace diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 9ab208768..f5895e88c 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,4 +1,9 @@ import "pkg:/source/utils/misc.bs" +import "pkg:/components/ImageSizes.bs" + +' The maximum number of seconds we will show the loading spinner and delay the user from using the home view while the content loads +' We use this to wait for the rows to load so we can reset focus to the row/item once it loads +const MAX_TIME_HOME_LOADING_SPINNER_SHOWN = 1 sub init() m.top.itemComponentName = "HomeItem" @@ -14,6 +19,11 @@ sub init() m.homeSections = {} + m.loadingTimer = createObject("roSGNode", "Timer") + m.loadingTimer.duration = MAX_TIME_HOME_LOADING_SPINNER_SHOWN + m.loadingTimer.repeat = true + m.loadingTimer.observeField("fire", "stopLoadingSpinner") + updateSize() m.top.setfocus(true) @@ -190,7 +200,7 @@ sub createLibraryRow(content as dynamic) mediaRow.title = tr("My Media") m.homeSections.AddReplace("library", { - imageSize: [464, 331], + imageSize: imageSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -212,12 +222,12 @@ sub createLatestInRows(content as dynamic) latestInRow = content.CreateChild("HomeRow") latestInRow.title = tr("Latest in") + " " + lib.name + " >" - imagesize = [464, 331] + imagesize = imageSizes.WIDE_POSTER if LCase(lib.collectionType) = "movies" - imagesize = [188, 331] + imagesize = imageSizes.MOVIE_POSTER else if LCase(lib.collectionType) = "music" - imagesize = [261, 331] + imagesize = imageSizes.MUSIC_ALBUM end if m.homeSections.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), { @@ -244,7 +254,7 @@ sub createLiveTVRow(content as dynamic) contentRow = content.CreateChild("HomeRow") contentRow.title = tr("On Now") m.homeSections.AddReplace("livetv", { - imageSize: [464, 331], + imageSize: imageSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -257,7 +267,7 @@ sub createContinueWatchingRow(content as dynamic) continueWatchingRow = content.CreateChild("HomeRow") continueWatchingRow.title = tr("Continue Watching") m.homeSections.AddReplace("resume", { - imageSize: [464, 331], + imageSize: imageSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -271,7 +281,7 @@ sub createNextUpRow(content as dynamic) nextUpRow = content.CreateChild("HomeRow") nextUpRow.title = tr("Next Up >") m.homeSections.AddReplace("nextup", { - imageSize: [464, 331], + imageSize: imageSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -286,7 +296,7 @@ sub createFavoritesRow(content as dynamic) favoritesRow.title = tr("Favorites") m.homeSections.AddReplace("favorites", { - imageSize: [464, 331], + imageSize: imageSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -297,6 +307,7 @@ end sub ' Update home row data sub updateHomeRows() + startMediaLoadingSpinner() content = processUserSections() setRowItemSizes() m.top.content = content @@ -375,6 +386,7 @@ sub updateNextUpItems() itemData = m.LoadNextUpTask.content m.LoadNextUpTask.unobserveField("content") m.LoadNextUpTask.content = [] + m.LoadNextUpTask.control = "STOP" if itemData = invalid then return @@ -444,14 +456,14 @@ sub updateLatestItems(msg) row.usePoster = true ' Handle specific types with different item widths if node.metadata.contentType = "movies" - row.imageWidth = 180 - itemSize = [188, 331] + row.imageWidth = imageSizes.MOVIE_POSTER[0] + itemSize = imageSizes.MOVIE_POSTER else if node.metadata.contentType = "music" - row.imageWidth = 261 - itemSize = [261, 331] + row.imageWidth = imageSizes.MUSIC_ALBUM[0] + itemSize = imageSizes.MUSIC_ALBUM else - row.imageWidth = 464 - itemSize = [464, 331] + row.imageWidth = imageSizes.WIDE_POSTER[0] + itemSize = imageSizes.WIDE_POSTER end if for each item in itemData @@ -512,9 +524,21 @@ end sub ' setFocusToPreviousFocusedItem: Sets the cursor focus to the row and item previously selected ' sub setFocusToPreviousFocusedItem() + m.loadingTimer.control = "start" + if isValid(m.selectedRowItem) - if isValid(m.homeSections[m.selectedRowItem[0]]) - m.top.jumpToRowItem = [m.homeSections[m.selectedRowItem[0]].index, m.selectedRowItem[1]] + ' Set focus to row if it exists + itemRow = m.top.content.getChild(m.top.rowItemSelected[0]) + if isValid(itemRow) + m.top.jumpToItem = m.top.rowItemSelected[0] + + ' Set focus to column if it exists + itemColumn = itemRow.getChild(m.top.rowItemSelected[1]) + if isValid(itemColumn) + m.top.jumpToRowItem = [m.selectedRowItem[0], m.selectedRowItem[1]] + m.loadingTimer.control = "stop" + stopLoadingSpinner() + end if end if end if end sub @@ -533,16 +557,18 @@ sub updateOnNowItems() ' remake row using the new data row = CreateObject("roSGNode", "HomeRow") row.title = tr("On Now") - 'itemSize = [464, 331] - row.imageWidth = 464 + row.imageWidth = imageSizes.WIDE_POSTER[0] for each item in itemData row.usePoster = false + if (not isValid(item.thumbnailURL) or item.thumbnailURL = "") and isValid(item.json) and isValid(item.json.imageURL) item.thumbnailURL = item.json.imageURL row.usePoster = true - row.imageWidth = 180 - 'itemSize = [188, 331] + row.imageWidth = imageSizes.MOVIE_POSTER[0] + + m.homeSections.livetv.imageSize = imageSizes.MOVIE_POSTER end if + item.usePoster = row.usePoster item.imageWidth = row.imageWidth row.appendChild(item) @@ -553,15 +579,14 @@ sub updateOnNowItems() ' Set focus on previously focused item setFocusToPreviousFocusedItem() + ' We may now have different poster sizes. Reset the row item sizes + setRowItemSizes() + end if end sub sub itemSelected() - for each section in m.homeSections - if m.homeSections[section].index = m.top.rowItemSelected[0] - m.selectedRowItem = [section, m.top.rowItemSelected[1]] - end if - end for + m.selectedRowItem = m.top.rowItemSelected m.top.selectedItem = m.top.content.getChild(m.top.rowItemSelected[0]).getChild(m.top.rowItemSelected[1]) diff --git a/locale/en_US/translations.ts b/locale/en_US/translations.ts index eccdff59e..54af561bf 100644 --- a/locale/en_US/translations.ts +++ b/locale/en_US/translations.ts @@ -1231,5 +1231,15 @@ No Chapter Data Found Message shown in OSD when no chapter data is returned by the API + + Use Web's Home Section Arrangement + Use Web's Home Section Arrangement + User Setting - Setting title + + + Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect. + Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect. + User Setting - Setting description + \ No newline at end of file diff --git a/settings/settings.json b/settings/settings.json index 497202f62..bbe713860 100644 --- a/settings/settings.json +++ b/settings/settings.json @@ -231,6 +231,13 @@ "settingName": "ui.home.splashBackground", "type": "bool", "default": "false" + }, + { + "title": "Use Web's Home Section Arrangement", + "description": "Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect.", + "settingName": "ui.home.useWebSectionArrangement", + "type": "bool", + "default": "false" } ] }, diff --git a/source/utils/misc.bs b/source/utils/misc.bs index 3cb48ed96..e9d2c5f80 100644 --- a/source/utils/misc.bs +++ b/source/utils/misc.bs @@ -459,6 +459,9 @@ sub startLoadingSpinner() end sub sub startMediaLoadingSpinner() + if not isValid(m.scene) + m.scene = m.top.getScene() + end if dialog = createObject("roSGNode", "ProgressDialog") dialog.id = "invisibiledialog" dialog.visible = false diff --git a/source/utils/session.bs b/source/utils/session.bs index d252661b0..14518d355 100644 --- a/source/utils/session.bs +++ b/source/utils/session.bs @@ -226,6 +226,20 @@ namespace session userPreferences = customPrefs rowTypes = [] + ' If this is a first time user, set the useWebSectionArrangement setting to true + ' This way the home view for upgrading users is not changed without them opting in + if not isValid(m.global.app.lastRunVersion) + set_user_setting("ui.home.useWebSectionArrangement", "true") + end if + + useWebSectionArrangement = m.global.session.user.settings["ui.home.useWebSectionArrangement"] + + if isValid(useWebSectionArrangement) + if not useWebSectionArrangement + userPreferences.delete("homesection0") + end if + end if + ' If user has no section preferences, use default settings if not userPreferences.doesExist("homesection0") userPreferences = { From 40925199d46657ee60c3c111bf6d1978e0eb44fc Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 25 Nov 2023 08:25:31 -0500 Subject: [PATCH 08/20] Review Updates & Bug Fix Fix Roku component reuse bug Don't repeat loadingTimer Move ImageSizes enum to source folder Update setting text & translation Check selectedRowItem is valid and not empty --- components/home/HomeItem.bs | 1 + components/home/HomeRows.bs | 33 +++++++++---------- locale/en_US/translations.ts | 8 ++--- settings/settings.json | 6 ++-- .../constants}/ImageSizes.bs | 4 ++- source/migrations.bs | 8 +++++ source/utils/session.bs | 6 ---- 7 files changed, 35 insertions(+), 31 deletions(-) rename {components => source/constants}/ImageSizes.bs (54%) diff --git a/components/home/HomeItem.bs b/components/home/HomeItem.bs index ff84644d2..882f6b5f5 100644 --- a/components/home/HomeItem.bs +++ b/components/home/HomeItem.bs @@ -28,6 +28,7 @@ end sub sub itemContentChanged() + m.unplayedCount.visible = false itemData = m.top.itemContent if itemData = invalid then return diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index f5895e88c..a611ebcf1 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,5 +1,5 @@ import "pkg:/source/utils/misc.bs" -import "pkg:/components/ImageSizes.bs" +import "pkg:/source/constants/ImageSizes.bs" ' The maximum number of seconds we will show the loading spinner and delay the user from using the home view while the content loads ' We use this to wait for the rows to load so we can reset focus to the row/item once it loads @@ -21,7 +21,6 @@ sub init() m.loadingTimer = createObject("roSGNode", "Timer") m.loadingTimer.duration = MAX_TIME_HOME_LOADING_SPINNER_SHOWN - m.loadingTimer.repeat = true m.loadingTimer.observeField("fire", "stopLoadingSpinner") updateSize() @@ -308,6 +307,7 @@ end sub ' Update home row data sub updateHomeRows() startMediaLoadingSpinner() + m.loadingTimer.control = "start" content = processUserSections() setRowItemSizes() m.top.content = content @@ -454,6 +454,7 @@ sub updateLatestItems(msg) row = CreateObject("roSGNode", "HomeRow") row.title = tr("Latest in") + " " + node.metadata.title + " >" row.usePoster = true + ' Handle specific types with different item widths if node.metadata.contentType = "movies" row.imageWidth = imageSizes.MOVIE_POSTER[0] @@ -524,21 +525,19 @@ end sub ' setFocusToPreviousFocusedItem: Sets the cursor focus to the row and item previously selected ' sub setFocusToPreviousFocusedItem() - m.loadingTimer.control = "start" - - if isValid(m.selectedRowItem) - ' Set focus to row if it exists - itemRow = m.top.content.getChild(m.top.rowItemSelected[0]) - if isValid(itemRow) - m.top.jumpToItem = m.top.rowItemSelected[0] - - ' Set focus to column if it exists - itemColumn = itemRow.getChild(m.top.rowItemSelected[1]) - if isValid(itemColumn) - m.top.jumpToRowItem = [m.selectedRowItem[0], m.selectedRowItem[1]] - m.loadingTimer.control = "stop" - stopLoadingSpinner() - end if + if not isValidAndNotEmpty(m.selectedRowItem) then return + + ' Set focus to row if it exists + itemRow = m.top.content.getChild(m.selectedRowItem[0]) + if isValid(itemRow) + m.top.jumpToItem = m.selectedRowItem[0] + + ' Set focus to column if it exists + itemColumn = itemRow.getChild(m.selectedRowItem[1]) + if isValid(itemColumn) + m.top.jumpToRowItem = [m.selectedRowItem[0], m.selectedRowItem[1]] + m.loadingTimer.control = "stop" + stopLoadingSpinner() end if end if end sub diff --git a/locale/en_US/translations.ts b/locale/en_US/translations.ts index 54af561bf..1fe478489 100644 --- a/locale/en_US/translations.ts +++ b/locale/en_US/translations.ts @@ -1232,13 +1232,13 @@ Message shown in OSD when no chapter data is returned by the API - Use Web's Home Section Arrangement - Use Web's Home Section Arrangement + Use Web Client's Home Section Arrangement + Use Web Client's Home Section Arrangement User Setting - Setting title - Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect. - Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect. + Make the arrangement of the Roku home view sections match the web client's home screen. Jellyfin will need to be closed and reopened for change to take effect. + Make the arrangement of the Roku home view sections match the web client's home screen. Jellyfin will need to be closed and reopened for change to take effect. User Setting - Setting description diff --git a/settings/settings.json b/settings/settings.json index bbe713860..9c33a6b01 100644 --- a/settings/settings.json +++ b/settings/settings.json @@ -233,11 +233,11 @@ "default": "false" }, { - "title": "Use Web's Home Section Arrangement", - "description": "Make the arrangement of the Roku home view sections match the web's home screen. Jellyfin will need to be closed and reopened for change to take effect.", + "title": "Use Web Client's Home Section Arrangement", + "description": "Make the arrangement of the Roku home view sections match the web client's home screen. Jellyfin will need to be closed and reopened for change to take effect.", "settingName": "ui.home.useWebSectionArrangement", "type": "bool", - "default": "false" + "default": "true" } ] }, diff --git a/components/ImageSizes.bs b/source/constants/ImageSizes.bs similarity index 54% rename from components/ImageSizes.bs rename to source/constants/ImageSizes.bs index 2371a30fc..2e3df0b77 100644 --- a/components/ImageSizes.bs +++ b/source/constants/ImageSizes.bs @@ -1,5 +1,7 @@ +' @fileoverview Constants for various image sizes. + namespace imageSizes const WIDE_POSTER = [464, 331] - const MOVIE_POSTER = [188, 331] + const MOVIE_POSTER = [180, 331] const MUSIC_ALBUM = [261, 331] end namespace diff --git a/source/migrations.bs b/source/migrations.bs index 70cec93f9..201ffc66c 100644 --- a/source/migrations.bs +++ b/source/migrations.bs @@ -72,6 +72,14 @@ sub runRegistryUserMigrations() m.wasMigrated = true print `Running Registry Migration for ${CLIENT_VERSION_REQUIRING_BASE_MIGRATION} for userid: ${section}` + ' If this is an existing user, set the useWebSectionArrangement setting to false + ' This way the home view for upgrading users is not changed without them opting in + useWebSectionArrangement = registry_read("ui.home.useWebSectionArrangement", section) + + if not isValid(useWebSectionArrangement) + registry_write("ui.home.useWebSectionArrangement", "false", section) + end if + ' no longer saving password to registry registry_delete("password", section) ' av1 playback no longer hidden behind user setting diff --git a/source/utils/session.bs b/source/utils/session.bs index 14518d355..f6eee976d 100644 --- a/source/utils/session.bs +++ b/source/utils/session.bs @@ -226,12 +226,6 @@ namespace session userPreferences = customPrefs rowTypes = [] - ' If this is a first time user, set the useWebSectionArrangement setting to true - ' This way the home view for upgrading users is not changed without them opting in - if not isValid(m.global.app.lastRunVersion) - set_user_setting("ui.home.useWebSectionArrangement", "true") - end if - useWebSectionArrangement = m.global.session.user.settings["ui.home.useWebSectionArrangement"] if isValid(useWebSectionArrangement) From 47781b77d7c834217026646f24606c11b93eb5a3 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sun, 26 Nov 2023 15:48:50 -0500 Subject: [PATCH 09/20] Fix 1st run setting --- source/migrations.bs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/migrations.bs b/source/migrations.bs index 201ffc66c..19182e90e 100644 --- a/source/migrations.bs +++ b/source/migrations.bs @@ -74,9 +74,8 @@ sub runRegistryUserMigrations() ' If this is an existing user, set the useWebSectionArrangement setting to false ' This way the home view for upgrading users is not changed without them opting in - useWebSectionArrangement = registry_read("ui.home.useWebSectionArrangement", section) - - if not isValid(useWebSectionArrangement) + if not hasUserVersion + print "useWebSectionArrangement set to false" registry_write("ui.home.useWebSectionArrangement", "false", section) end if From f1da07ea6e47550c86a5c987c04d6abd199721bd Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Mon, 27 Nov 2023 17:14:19 -0500 Subject: [PATCH 10/20] Rename ImageSizes file to match actual use --- components/home/HomeRows.bs | 36 +++++++++---------- .../{ImageSizes.bs => HomeRowItemSizes.bs} | 4 +-- 2 files changed, 20 insertions(+), 20 deletions(-) rename source/constants/{ImageSizes.bs => HomeRowItemSizes.bs} (58%) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index a611ebcf1..ff2abb236 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,5 +1,5 @@ import "pkg:/source/utils/misc.bs" -import "pkg:/source/constants/ImageSizes.bs" +import "pkg:/source/constants/HomeRowItemSizes.bs" ' The maximum number of seconds we will show the loading spinner and delay the user from using the home view while the content loads ' We use this to wait for the rows to load so we can reset focus to the row/item once it loads @@ -199,7 +199,7 @@ sub createLibraryRow(content as dynamic) mediaRow.title = tr("My Media") m.homeSections.AddReplace("library", { - imageSize: imageSizes.WIDE_POSTER, + imageSize: homeRowItemSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -221,12 +221,12 @@ sub createLatestInRows(content as dynamic) latestInRow = content.CreateChild("HomeRow") latestInRow.title = tr("Latest in") + " " + lib.name + " >" - imagesize = imageSizes.WIDE_POSTER + imagesize = homeRowItemSizes.WIDE_POSTER if LCase(lib.collectionType) = "movies" - imagesize = imageSizes.MOVIE_POSTER + imagesize = homeRowItemSizes.MOVIE_POSTER else if LCase(lib.collectionType) = "music" - imagesize = imageSizes.MUSIC_ALBUM + imagesize = homeRowItemSizes.MUSIC_ALBUM end if m.homeSections.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), { @@ -253,7 +253,7 @@ sub createLiveTVRow(content as dynamic) contentRow = content.CreateChild("HomeRow") contentRow.title = tr("On Now") m.homeSections.AddReplace("livetv", { - imageSize: imageSizes.WIDE_POSTER, + imageSize: homeRowItemSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -266,7 +266,7 @@ sub createContinueWatchingRow(content as dynamic) continueWatchingRow = content.CreateChild("HomeRow") continueWatchingRow.title = tr("Continue Watching") m.homeSections.AddReplace("resume", { - imageSize: imageSizes.WIDE_POSTER, + imageSize: homeRowItemSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -280,7 +280,7 @@ sub createNextUpRow(content as dynamic) nextUpRow = content.CreateChild("HomeRow") nextUpRow.title = tr("Next Up >") m.homeSections.AddReplace("nextup", { - imageSize: imageSizes.WIDE_POSTER, + imageSize: homeRowItemSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -295,7 +295,7 @@ sub createFavoritesRow(content as dynamic) favoritesRow.title = tr("Favorites") m.homeSections.AddReplace("favorites", { - imageSize: imageSizes.WIDE_POSTER, + imageSize: homeRowItemSizes.WIDE_POSTER, index: m.homeSections.count() }) @@ -457,14 +457,14 @@ sub updateLatestItems(msg) ' Handle specific types with different item widths if node.metadata.contentType = "movies" - row.imageWidth = imageSizes.MOVIE_POSTER[0] - itemSize = imageSizes.MOVIE_POSTER + row.imageWidth = homeRowItemSizes.MOVIE_POSTER[0] + itemSize = homeRowItemSizes.MOVIE_POSTER else if node.metadata.contentType = "music" - row.imageWidth = imageSizes.MUSIC_ALBUM[0] - itemSize = imageSizes.MUSIC_ALBUM + row.imageWidth = homeRowItemSizes.MUSIC_ALBUM[0] + itemSize = homeRowItemSizes.MUSIC_ALBUM else - row.imageWidth = imageSizes.WIDE_POSTER[0] - itemSize = imageSizes.WIDE_POSTER + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + itemSize = homeRowItemSizes.WIDE_POSTER end if for each item in itemData @@ -556,16 +556,16 @@ sub updateOnNowItems() ' remake row using the new data row = CreateObject("roSGNode", "HomeRow") row.title = tr("On Now") - row.imageWidth = imageSizes.WIDE_POSTER[0] + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] for each item in itemData row.usePoster = false if (not isValid(item.thumbnailURL) or item.thumbnailURL = "") and isValid(item.json) and isValid(item.json.imageURL) item.thumbnailURL = item.json.imageURL row.usePoster = true - row.imageWidth = imageSizes.MOVIE_POSTER[0] + row.imageWidth = homeRowItemSizes.MOVIE_POSTER[0] - m.homeSections.livetv.imageSize = imageSizes.MOVIE_POSTER + m.homeSections.livetv.imageSize = homeRowItemSizes.MOVIE_POSTER end if item.usePoster = row.usePoster diff --git a/source/constants/ImageSizes.bs b/source/constants/HomeRowItemSizes.bs similarity index 58% rename from source/constants/ImageSizes.bs rename to source/constants/HomeRowItemSizes.bs index 2e3df0b77..9ee0690a3 100644 --- a/source/constants/ImageSizes.bs +++ b/source/constants/HomeRowItemSizes.bs @@ -1,6 +1,6 @@ -' @fileoverview Constants for various image sizes. +' @fileoverview Constants for rowItemSize on the home view -namespace imageSizes +namespace homeRowItemSizes const WIDE_POSTER = [464, 331] const MOVIE_POSTER = [180, 331] const MUSIC_ALBUM = [261, 331] From b185c08c0cd45f8739c733d5454f493b79a58b51 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Mon, 27 Nov 2023 20:08:16 -0500 Subject: [PATCH 11/20] Fix 1st time setting bug Fix by Cewert --- source/migrations.bs | 5 ----- source/utils/session.bs | 5 ++++- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/source/migrations.bs b/source/migrations.bs index 19182e90e..58660b813 100644 --- a/source/migrations.bs +++ b/source/migrations.bs @@ -84,11 +84,6 @@ sub runRegistryUserMigrations() ' av1 playback no longer hidden behind user setting registry_delete("playback.av1", section) end if - - ' update lastRunVersion if needed - if hasUserVersion and lastRunVersion <> m.global.app.version - registry_write("LastRunVersion", m.global.app.version, section) - end if end if end for end sub diff --git a/source/utils/session.bs b/source/utils/session.bs index f6eee976d..c87f3c496 100644 --- a/source/utils/session.bs +++ b/source/utils/session.bs @@ -156,8 +156,11 @@ namespace session ' grab lastRunVersion for this user lastRunVersion = get_user_setting("LastRunVersion") - if lastRunVersion <> invalid + if isValid(lastRunVersion) and lastRunVersion = m.global.app.version + ' Don't update the registry, only update the global session session.user.Update("LastRunVersion", lastRunVersion) + else + set_user_setting("LastRunVersion", m.global.app.version) end if ' update user session settings with values from registry From d6b50440d4f6b1ba4817f7263012389dc9ec7c82 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Wed, 29 Nov 2023 16:06:54 -0500 Subject: [PATCH 12/20] Fix refresh delay --- components/home/HomeRows.bs | 245 ++++++++++++++++-------------------- 1 file changed, 109 insertions(+), 136 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index ff2abb236..f3a4aa2c8 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,10 +1,6 @@ import "pkg:/source/utils/misc.bs" import "pkg:/source/constants/HomeRowItemSizes.bs" -' The maximum number of seconds we will show the loading spinner and delay the user from using the home view while the content loads -' We use this to wait for the rows to load so we can reset focus to the row/item once it loads -const MAX_TIME_HOME_LOADING_SPINNER_SHOWN = 1 - sub init() m.top.itemComponentName = "HomeItem" ' how many rows are visible on the screen @@ -19,10 +15,6 @@ sub init() m.homeSections = {} - m.loadingTimer = createObject("roSGNode", "Timer") - m.loadingTimer.duration = MAX_TIME_HOME_LOADING_SPINNER_SHOWN - m.loadingTimer.observeField("fire", "stopLoadingSpinner") - updateSize() m.top.setfocus(true) @@ -71,8 +63,6 @@ end sub ' ' @return {dynamic} content node filled with child nodes for each row function processUserSections() as dynamic - m.homeSections = {} - loadedSections = 0 content = CreateObject("roSGNode", "ContentNode") @@ -124,13 +114,14 @@ sub removeHomeSection(sectionType as string) if not isValid(removedSection) then return if not isValid(removedSection.index) then return + m.homeSections.Delete(sectionName) + for each section in m.homeSections if m.homeSections[section].index > removedSection.index m.homeSections[section].index-- end if end for - m.homeSections.Delete(sectionName) m.top.content.removeChildIndex(removedSection.index) setRowItemSizes() @@ -198,15 +189,31 @@ sub createLibraryRow(content as dynamic) mediaRow = content.CreateChild("HomeRow") mediaRow.title = tr("My Media") + sectionIndex = m.homeSections.count() + + isUpdate = false + + if m.homeSections.doesExist("library") + sectionIndex = m.homeSections.library.index + isUpdate = true + end if + m.homeSections.AddReplace("library", { imageSize: homeRowItemSizes.WIDE_POSTER, - index: m.homeSections.count() + index: sectionIndex }) filteredMedia = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.MyMediaExcludes) for each item in filteredMedia mediaRow.appendChild(item) end for + + if isUpdate + m.top.content.replaceChild(mediaRow, m.homeSections.library.index) + return + end if + + content.appendChild(mediaRow) end sub ' Create a row displaying latest items in each of the user's libraries @@ -218,8 +225,16 @@ sub createLatestInRows(content as dynamic) filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes) for each lib in filteredLatest if lib.collectionType <> "boxsets" and lib.collectionType <> "livetv" and lib.json.CollectionType <> "Program" - latestInRow = content.CreateChild("HomeRow") - latestInRow.title = tr("Latest in") + " " + lib.name + " >" + + sectionName = "latestin" + LCase(lib.name).Replace(" ", "") + + if not m.homeSections.doesExist(sectionName) + latestInRow = content.CreateChild("HomeRow") + latestInRow.title = tr("Latest in") + " " + lib.name + " >" + sectionIndex = m.homeSections.count() + else + sectionIndex = m.homeSections[sectionName].index + end if imagesize = homeRowItemSizes.WIDE_POSTER @@ -229,9 +244,9 @@ sub createLatestInRows(content as dynamic) imagesize = homeRowItemSizes.MUSIC_ALBUM end if - m.homeSections.AddReplace("latestin" + LCase(lib.name).Replace(" ", ""), { + m.homeSections.AddReplace(sectionName, { imageSize: imagesize, - index: m.homeSections.count() + index: sectionIndex }) loadLatest = createObject("roSGNode", "LoadItemsTask") @@ -250,11 +265,20 @@ end sub ' Create a row displaying the live tv now on section sub createLiveTVRow(content as dynamic) - contentRow = content.CreateChild("HomeRow") - contentRow.title = tr("On Now") + if not m.homeSections.doesExist("livetv") + contentRow = content.CreateChild("HomeRow") + contentRow.title = tr("On Now") + end if + + sectionIndex = m.homeSections.count() + + if m.homeSections.doesExist("livetv") + sectionIndex = m.homeSections.livetv.index + end if + m.homeSections.AddReplace("livetv", { imageSize: homeRowItemSizes.WIDE_POSTER, - index: m.homeSections.count() + index: sectionIndex }) m.LoadOnNowTask.observeField("content", "updateOnNowItems") @@ -263,11 +287,19 @@ end sub ' Create a row displaying items the user can continue watching sub createContinueWatchingRow(content as dynamic) - continueWatchingRow = content.CreateChild("HomeRow") - continueWatchingRow.title = tr("Continue Watching") + if not m.homeSections.doesExist("resume") + continueWatchingRow = content.CreateChild("HomeRow") + continueWatchingRow.title = tr("Continue Watching") + end if + sectionIndex = m.homeSections.count() + + if m.homeSections.doesExist("resume") + sectionIndex = m.homeSections.resume.index + end if + m.homeSections.AddReplace("resume", { imageSize: homeRowItemSizes.WIDE_POSTER, - index: m.homeSections.count() + index: sectionIndex }) ' Load the Continue Watching Data @@ -277,11 +309,19 @@ end sub ' Create a row displaying next episodes up to watch sub createNextUpRow(content as dynamic) - nextUpRow = content.CreateChild("HomeRow") - nextUpRow.title = tr("Next Up >") + if not m.homeSections.doesExist("nextup") + nextUpRow = content.CreateChild("HomeRow") + nextUpRow.title = tr("Next Up >") + end if + sectionIndex = m.homeSections.count() + + if m.homeSections.doesExist("nextup") + sectionIndex = m.homeSections.nextup.index + end if + m.homeSections.AddReplace("nextup", { imageSize: homeRowItemSizes.WIDE_POSTER, - index: m.homeSections.count() + index: sectionIndex }) ' Load the Next Up Data @@ -291,12 +331,20 @@ end sub ' Create a row displaying items from the user's favorites list sub createFavoritesRow(content as dynamic) - favoritesRow = content.CreateChild("HomeRow") - favoritesRow.title = tr("Favorites") + if not m.homeSections.doesExist("favorites") + favoritesRow = content.CreateChild("HomeRow") + favoritesRow.title = tr("Favorites") + end if + + sectionIndex = m.homeSections.count() + + if m.homeSections.doesExist("favorites") + sectionIndex = m.homeSections.favorites.index + end if m.homeSections.AddReplace("favorites", { imageSize: homeRowItemSizes.WIDE_POSTER, - index: m.homeSections.count() + index: sectionIndex }) ' Load the Favorites Data @@ -306,11 +354,8 @@ end sub ' Update home row data sub updateHomeRows() - startMediaLoadingSpinner() - m.loadingTimer.control = "start" - content = processUserSections() + processUserSections() setRowItemSizes() - m.top.content = content end sub sub updateFavoritesItems() @@ -342,11 +387,19 @@ sub updateFavoritesItems() row.appendChild(item) end for - ' replace the old row - m.top.content.replaceChild(row, rowIndex) - ' Set focus on previously focused item - setFocusToPreviousFocusedItem() + if isValid(m.top.content.getChild(rowIndex)) + m.top.content.replaceChild(row, rowIndex) + else + for each section in m.homeSections + if m.homeSections[section].index >= m.top.content.getChildCount() + m.homeSections[section].index++ + end if + end for + + m.homeSections.favorites.index = m.top.content.getChildCount() + m.top.content.insertChild(row, m.top.content.getChildCount()) + end if end if end sub @@ -378,8 +431,6 @@ sub updateContinueWatchingItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.resume.index) - ' Set focus on previously focused item - setFocusToPreviousFocusedItem() end sub sub updateNextUpItems() @@ -405,36 +456,9 @@ sub updateNextUpItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.nextup.index) - ' Set focus on previously focused item - setFocusToPreviousFocusedItem() end if end sub -' Iterate over user's libraries and update data for each Latest In section -sub updateLatestInRows() - ' Ensure we have data - if not isValidAndNotEmpty(m.libraryData) then return - - ' Load new data for each library - filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes) - for each lib in filteredLatest - if lib.collectionType <> "boxsets" and lib.collectionType <> "livetv" and lib.json.CollectionType <> "Program" - loadLatest = createObject("roSGNode", "LoadItemsTask") - loadLatest.itemsToLoad = "latest" - loadLatest.itemId = lib.id - - metadata = { - "title": lib.name, - "contentType": lib.json.CollectionType - } - - loadLatest.metadata = metadata - loadLatest.observeField("content", "updateLatestItems") - loadLatest.control = "RUN" - end if - end for -end sub - sub updateLatestItems(msg) itemData = msg.GetData() @@ -455,90 +479,41 @@ sub updateLatestItems(msg) row.title = tr("Latest in") + " " + node.metadata.title + " >" row.usePoster = true - ' Handle specific types with different item widths - if node.metadata.contentType = "movies" - row.imageWidth = homeRowItemSizes.MOVIE_POSTER[0] - itemSize = homeRowItemSizes.MOVIE_POSTER - else if node.metadata.contentType = "music" - row.imageWidth = homeRowItemSizes.MUSIC_ALBUM[0] - itemSize = homeRowItemSizes.MUSIC_ALBUM - else - row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] - itemSize = homeRowItemSizes.WIDE_POSTER - end if - for each item in itemData item.usePoster = row.usePoster - item.imageWidth = row.imageWidth + item.imageWidth = m.homeSections[sectionName].imageSize[0] row.appendChild(item) end for - if isValid(m.homeSections[sectionName]) - rowIndex = m.homeSections[sectionName].index + rowIndex = m.homeSections[sectionName].index + if isValid(rowIndex) and isValid(m.top.content.getChild(rowIndex)) ' Replace the old row - if isValid(rowIndex) - m.top.content.replaceChild(row, rowIndex) - - ' Set focus on previously focused item - setFocusToPreviousFocusedItem() - - return - end if - end if - - ' Determine highest index of a Lastest In section so we can append the new section after it - highestLatestHomeSectionIndex = 0 + m.top.content.replaceChild(row, rowIndex) + else + firstLatestHomeSectionIndex = m.homeSections.count() - 1 - for each section in m.homeSections - if LCase(Left(section, 6)) = "latest" - if m.homeSections[section].index > highestLatestHomeSectionIndex - highestLatestHomeSectionIndex = m.homeSections[section].index + for each section in m.homeSections + if LCase(Left(section, 6)) = "latest" + if m.homeSections[section].index < firstLatestHomeSectionIndex + firstLatestHomeSectionIndex = m.homeSections[section].index + end if end if - end if - end for - - ' We have data for a section that doesn't currently exist - rowIndex = highestLatestHomeSectionIndex + 1 + end for - ' Advance all the indexes greater than or equal than our new row - for each section in m.homeSections - if m.homeSections[section].index >= rowIndex - m.homeSections[section].index++ - end if - end for - - m.homeSections.AddReplace(sectionName, { - imageSize: itemSize, - index: rowIndex - }) + for each section in m.homeSections + if m.homeSections[section].index >= firstLatestHomeSectionIndex + m.homeSections[section].index++ + end if + end for - m.top.content.insertChild(row, rowIndex) + m.homeSections[sectionName].index = firstLatestHomeSectionIndex + m.top.content.insertChild(row, firstLatestHomeSectionIndex) + end if - ' We've inserted a new row, we must set the row sizes again to ensure they're correct setRowItemSizes() - return - end if -end sub -' setFocusToPreviousFocusedItem: Sets the cursor focus to the row and item previously selected -' -sub setFocusToPreviousFocusedItem() - if not isValidAndNotEmpty(m.selectedRowItem) then return - - ' Set focus to row if it exists - itemRow = m.top.content.getChild(m.selectedRowItem[0]) - if isValid(itemRow) - m.top.jumpToItem = m.selectedRowItem[0] - - ' Set focus to column if it exists - itemColumn = itemRow.getChild(m.selectedRowItem[1]) - if isValid(itemColumn) - m.top.jumpToRowItem = [m.selectedRowItem[0], m.selectedRowItem[1]] - m.loadingTimer.control = "stop" - stopLoadingSpinner() - end if end if end sub @@ -575,8 +550,6 @@ sub updateOnNowItems() ' replace the old row m.top.content.replaceChild(row, m.homeSections.livetv.index) - ' Set focus on previously focused item - setFocusToPreviousFocusedItem() ' We may now have different poster sizes. Reset the row item sizes setRowItemSizes() From 383e61f230d9e5fb37b72d46b227f3712effde13 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Fri, 1 Dec 2023 23:05:15 -0500 Subject: [PATCH 13/20] Rewrite index tracking. Reduce/remove flicker. --- components/home/Home.bs | 11 +- components/home/Home.xml | 6 +- components/home/HomeRow.xml | 1 + components/home/HomeRows.bs | 590 ++++++++++++++++++++---------------- 4 files changed, 343 insertions(+), 265 deletions(-) diff --git a/components/home/Home.bs b/components/home/Home.bs index 5c1f39f35..33b3c8606 100644 --- a/components/home/Home.bs +++ b/components/home/Home.bs @@ -9,6 +9,10 @@ sub init() m.top.optionsAvailable = true m.postTask = createObject("roSGNode", "PostTask") + m.homeRows = m.top.findNode("homeRows") + + m.fadeInFocusBitmap = m.top.findNode("fadeInFocusBitmap") + if m.global.session.user.settings["ui.home.splashBackground"] = true m.backdrop = m.top.findNode("backdrop") m.backdrop.uri = buildURL("/Branding/Splashscreen?format=jpg&foregroundLayer=0.15&fillWidth=1280&width=1280&fillHeight=720&height=720&tag=splash") @@ -16,11 +20,14 @@ sub init() end sub sub refresh() - m.top.findNode("homeRows").callFunc("updateHomeRows") + m.homeRows.focusBitmapBlendColor = "0xFFFFFFFF" + m.homeRows.callFunc("updateHomeRows") end sub sub loadLibraries() - m.top.findNode("homeRows").callFunc("loadLibraries") + m.homeRows.focusBitmapBlendColor = "0xFFFFFF00" + m.homeRows.callFunc("loadLibraries") + m.fadeInFocusBitmap.control = "start" end sub ' JFScreen hook that gets ran as needed. diff --git a/components/home/Home.xml b/components/home/Home.xml index 9ce89fcf5..4e06e0013 100644 --- a/components/home/Home.xml +++ b/components/home/Home.xml @@ -2,8 +2,12 @@ - + + + + + diff --git a/components/home/HomeRow.xml b/components/home/HomeRow.xml index c846e3f20..8d1db2cc4 100644 --- a/components/home/HomeRow.xml +++ b/components/home/HomeRow.xml @@ -2,6 +2,7 @@ + \ No newline at end of file diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index f3a4aa2c8..d1b3be413 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,6 +1,8 @@ import "pkg:/source/utils/misc.bs" import "pkg:/source/constants/HomeRowItemSizes.bs" +const FOCUS_RESIZE_WAIT_TIME = 2 + sub init() m.top.itemComponentName = "HomeItem" ' how many rows are visible on the screen @@ -11,9 +13,14 @@ sub init() m.top.showRowLabel = [true] m.top.rowLabelOffset = [0, 20] - m.top.showRowCounter = [true] + ' Hide the row counter to prevent flicker. We'll show it once loading timer fires + m.top.showRowCounter = [false] + + m.top.content = CreateObject("roSGNode", "ContentNode") - m.homeSections = {} + m.loadingTimer = createObject("roSGNode", "Timer") + m.loadingTimer.duration = FOCUS_RESIZE_WAIT_TIME + m.loadingTimer.observeField("fire", "loadingTimerComplete") updateSize() @@ -25,7 +32,7 @@ sub init() m.LoadLibrariesTask = createObject("roSGNode", "LoadItemsTask") m.LoadLibrariesTask.observeField("content", "onLibrariesLoaded") - ' set up tesk nodes for other rows + ' set up task nodes for other rows m.LoadContinueWatchingTask = createObject("roSGNode", "LoadItemsTask") m.LoadContinueWatchingTask.itemsToLoad = "continue" @@ -56,20 +63,21 @@ sub updateSize() ' spacing between items in a row m.top.rowItemSpacing = [20, 0] + ' Default size to wide poster, the most used size + m.top.rowItemSize = homeRowItemSizes.WIDE_POSTER + m.top.visible = true end sub ' processUserSections: Loop through user's chosen home section settings and generate the content for each row ' -' @return {dynamic} content node filled with child nodes for each row -function processUserSections() as dynamic +sub processUserSections() loadedSections = 0 - content = CreateObject("roSGNode", "ContentNode") ' Add sections in order based on user settings for i = 0 to 6 sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()]) - sectionLoaded = addHomeSection(content, sectionName) + sectionLoaded = addHomeSection(sectionName) ' Count how many sections with data are loaded if sectionLoaded then loadedSections++ @@ -83,12 +91,12 @@ function processUserSections() as dynamic end if end for - ' Favorites isn't an option on Web settings, so we must manually add it for now - addHomeSection(content, "favorites") - - return content -end function + ' Favorites isn't an option in Web settings, so we manually add it to the end for now + addHomeSection("favorites") + ' Start the timer for creating the content rows before we set the cursor size + m.loadingTimer.control = "start" +end sub ' onLibrariesLoaded: Handler when LoadLibrariesTask returns data ' @@ -98,126 +106,159 @@ sub onLibrariesLoaded() m.LoadLibrariesTask.unobserveField("content") m.LoadLibrariesTask.content = [] - content = processUserSections() - - setRowItemSizes() - - m.top.content = content + processUserSections() end sub -' Removes a home section from the home rows -sub removeHomeSection(sectionType as string) - sectionName = LCase(sectionType) - - removedSection = m.homeSections[sectionName] +' getOriginalSectionIndex: Gets the index of a section from user settings and adds count of currently known latest media sections +' +' @param {string} sectionName - Name of section we're looking up +' +' @return {integer} indicating index of section taking latest media sections into account +function getOriginalSectionIndex(sectionName as string) as integer + searchSectionName = LCase(sectionName).Replace(" ", "") - if not isValid(removedSection) then return - if not isValid(removedSection.index) then return + sectionIndex = 0 + indexLatestMediaSection = 0 - m.homeSections.Delete(sectionName) + for i = 0 to 6 + settingSectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()]) + if settingSectionName = "latestmedia" + indexLatestMediaSection = i + end if - for each section in m.homeSections - if m.homeSections[section].index > removedSection.index - m.homeSections[section].index-- + if settingSectionName = searchSectionName + sectionIndex = i end if end for - m.top.content.removeChildIndex(removedSection.index) + ' If the latest media section is before the section we're searching for, then we need to account for how many latest media rows there are + addLatestMediaSectionCount = (indexLatestMediaSection < sectionIndex) + + if addLatestMediaSectionCount + for i = sectionIndex to m.top.content.getChildCount() - 1 + sectionToTest = m.top.content.getChild(i) + if LCase(Left(sectionToTest.title, 6)) = "latest" + sectionIndex++ + end if + end for + end if + + return sectionIndex +end function + +' removeHomeSection: Removes a home section from the home rows +' +' @param {string} sectionToRemove - Title property of section we're removing +sub removeHomeSection(sectionTitleToRemove as string) + if not isValid(sectionTitleToRemove) then return + + sectionTitle = LCase(sectionTitleToRemove).Replace(" ", "") + if not sectionExists(sectionTitle) then return + + sectionIndexToRemove = getSectionIndex(sectionTitle) - setRowItemSizes() + m.top.content.removeChildIndex(sectionIndexToRemove) end sub -' setRowItemSizes: Loops through all home sections and sets the correct item sizes per row +' setRowItemSize: Loops through all home sections and sets the correct item sizes per row ' -sub setRowItemSizes() - newSizeArray = CreateObject("roArray", m.homeSections.count(), false) +sub setRowItemSize() + if not isValid(m.top.content) then return - for each section in m.homeSections - newSizeArray[m.homeSections[section].index] = m.homeSections[section].imagesize + homeSections = m.top.content.getChildren(-1, 0) + newSizeArray = CreateObject("roArray", homeSections.count(), false) + + for i = 0 to homeSections.count() - 1 + newSizeArray[i] = isValid(homeSections[i].cursorSize) ? homeSections[i].cursorSize : homeRowItemSizes.WIDE_POSTER end for m.top.rowItemSize = newSizeArray end sub -' Adds a new home section to the home rows. -' Returns a boolean indicating whether the section was handled. -function addHomeSection(content as dynamic, sectionName as string) as boolean +' loadingTimerComplete: Event handler for when loading wait time has expired +' +sub loadingTimerComplete() + ' Show the row counter to prevent flicker + m.top.showRowCounter = [true] +end sub + +' addHomeSection: Adds a new home section to the home rows. +' +' @param {string} sectionType - Type of section to add +' @return {boolean} indicating if the section was handled +function addHomeSection(sectionType as string) as boolean ' Poster size library items - if sectionName = "livetv" - createLiveTVRow(content) + if sectionType = "livetv" + createLiveTVRow() return true end if ' Poster size library items - if sectionName = "smalllibrarytiles" - createLibraryRow(content) + if sectionType = "smalllibrarytiles" + createLibraryRow() return true end if ' Continue Watching items - if sectionName = "resume" - createContinueWatchingRow(content) + if sectionType = "resume" + createContinueWatchingRow() return true end if ' Next Up items - if sectionName = "nextup" - createNextUpRow(content) + if sectionType = "nextup" + createNextUpRow() return true end if ' Latest items in each library - if sectionName = "latestmedia" - createLatestInRows(content) + if sectionType = "latestmedia" + createLatestInRows() return true end if ' Favorite Items - if sectionName = "favorites" - createFavoritesRow(content) + if sectionType = "favorites" + createFavoritesRow() return true end if return false end function -' Create a row displaying the user's libraries -sub createLibraryRow(content as dynamic) +' createLibraryRow: Creates a row displaying the user's libraries +' +sub createLibraryRow() ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return - mediaRow = content.CreateChild("HomeRow") - mediaRow.title = tr("My Media") - - sectionIndex = m.homeSections.count() - - isUpdate = false - - if m.homeSections.doesExist("library") - sectionIndex = m.homeSections.library.index - isUpdate = true - end if + sectionName = tr("My Media") - m.homeSections.AddReplace("library", { - imageSize: homeRowItemSizes.WIDE_POSTER, - index: sectionIndex - }) + row = CreateObject("roSGNode", "HomeRow") + row.title = sectionName + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + row.cursorSize = homeRowItemSizes.WIDE_POSTER filteredMedia = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.MyMediaExcludes) for each item in filteredMedia - mediaRow.appendChild(item) + row.appendChild(item) end for - if isUpdate - m.top.content.replaceChild(mediaRow, m.homeSections.library.index) + ' Row already exists, replace it with new content + if sectionExists(sectionName) + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() return end if - content.appendChild(mediaRow) + ' Row does not exist, insert it into the home view + m.top.content.insertChild(row, getOriginalSectionIndex("smalllibrarytiles")) + setRowItemSize() end sub -' Create a row displaying latest items in each of the user's libraries -sub createLatestInRows(content as dynamic) +' createLatestInRows: Creates a row displaying latest items in each of the user's libraries +' +sub createLatestInRows() ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return @@ -226,29 +267,21 @@ sub createLatestInRows(content as dynamic) for each lib in filteredLatest if lib.collectionType <> "boxsets" and lib.collectionType <> "livetv" and lib.json.CollectionType <> "Program" - sectionName = "latestin" + LCase(lib.name).Replace(" ", "") + if not sectionExists(tr("Latest in") + " " + lib.name + " >") + imagesize = homeRowItemSizes.WIDE_POSTER - if not m.homeSections.doesExist(sectionName) - latestInRow = content.CreateChild("HomeRow") - latestInRow.title = tr("Latest in") + " " + lib.name + " >" - sectionIndex = m.homeSections.count() - else - sectionIndex = m.homeSections[sectionName].index - end if - - imagesize = homeRowItemSizes.WIDE_POSTER + if LCase(lib.collectionType) = "movies" + imagesize = homeRowItemSizes.MOVIE_POSTER + else if LCase(lib.collectionType) = "music" + imagesize = homeRowItemSizes.MUSIC_ALBUM + end if - if LCase(lib.collectionType) = "movies" - imagesize = homeRowItemSizes.MOVIE_POSTER - else if LCase(lib.collectionType) = "music" - imagesize = homeRowItemSizes.MUSIC_ALBUM + row = CreateObject("roSGNode", "HomeRow") + row.title = tr("Latest in") + " " + lib.name + " >" + row.imageWidth = imagesize[0] + row.cursorSize = imagesize end if - m.homeSections.AddReplace(sectionName, { - imageSize: imagesize, - index: sectionIndex - }) - loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" loadLatest.itemId = lib.id @@ -263,101 +296,105 @@ sub createLatestInRows(content as dynamic) end for end sub -' Create a row displaying the live tv now on section -sub createLiveTVRow(content as dynamic) - if not m.homeSections.doesExist("livetv") - contentRow = content.CreateChild("HomeRow") - contentRow.title = tr("On Now") - end if +' sectionExists: Checks if passed section exists in home row content +' +' @param {string} sectionTitle - Title of section we're checking for +' +' @return {boolean} indicating if the section currently exists in the home row content +function sectionExists(sectionTitle as string) as boolean + if not isValid(sectionTitle) then return false + if not isValid(m.top.content) then return false - sectionIndex = m.homeSections.count() + searchSectionTitle = LCase(sectionTitle).Replace(" ", "") - if m.homeSections.doesExist("livetv") - sectionIndex = m.homeSections.livetv.index - end if + homeSections = m.top.content.getChildren(-1, 0) + + for each section in homeSections + if LCase(section.title).Replace(" ", "") = searchSectionTitle + return true + end if + end for - m.homeSections.AddReplace("livetv", { - imageSize: homeRowItemSizes.WIDE_POSTER, - index: sectionIndex - }) + return false +end function - m.LoadOnNowTask.observeField("content", "updateOnNowItems") - m.LoadOnNowTask.control = "RUN" -end sub +' getSectionIndex: Returns index of requested section in home row content +' +' @param {string} sectionTitle - Title of section we're checking for +' +' @return {integer} indicating index of request section +function getSectionIndex(sectionTitle as string) as integer + if not isValid(sectionTitle) then return false + if not isValid(m.top.content) then return false -' Create a row displaying items the user can continue watching -sub createContinueWatchingRow(content as dynamic) - if not m.homeSections.doesExist("resume") - continueWatchingRow = content.CreateChild("HomeRow") - continueWatchingRow.title = tr("Continue Watching") - end if - sectionIndex = m.homeSections.count() + searchSectionTitle = LCase(sectionTitle).Replace(" ", "") - if m.homeSections.doesExist("resume") - sectionIndex = m.homeSections.resume.index - end if + homeSections = m.top.content.getChildren(-1, 0) - m.homeSections.AddReplace("resume", { - imageSize: homeRowItemSizes.WIDE_POSTER, - index: sectionIndex - }) + sectionIndex = homeSections.count() + i = 0 + for each section in homeSections + if LCase(section.title).Replace(" ", "") = searchSectionTitle + sectionIndex = i + exit for + end if + i++ + end for + + return sectionIndex +end function + +' createLiveTVRow: Creates a row displaying the live tv now on section +' +sub createLiveTVRow() + m.LoadOnNowTask.observeField("content", "updateOnNowItems") + m.LoadOnNowTask.control = "RUN" +end sub + +' createContinueWatchingRow: Creates a row displaying items the user can continue watching +' +sub createContinueWatchingRow() ' Load the Continue Watching Data m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") m.LoadContinueWatchingTask.control = "RUN" end sub -' Create a row displaying next episodes up to watch -sub createNextUpRow(content as dynamic) - if not m.homeSections.doesExist("nextup") - nextUpRow = content.CreateChild("HomeRow") - nextUpRow.title = tr("Next Up >") - end if - sectionIndex = m.homeSections.count() - - if m.homeSections.doesExist("nextup") - sectionIndex = m.homeSections.nextup.index +' createNextUpRow: Creates a row displaying next episodes up to watch +' +sub createNextUpRow() + sectionName = tr("Next Up") + ">" + + if not sectionExists(sectionName) + nextUpRow = m.top.content.CreateChild("HomeRow") + nextUpRow.title = sectionName + nextUpRow.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + nextUpRow.cursorSize = homeRowItemSizes.WIDE_POSTER end if - m.homeSections.AddReplace("nextup", { - imageSize: homeRowItemSizes.WIDE_POSTER, - index: sectionIndex - }) - ' Load the Next Up Data m.LoadNextUpTask.observeField("content", "updateNextUpItems") m.LoadNextUpTask.control = "RUN" end sub -' Create a row displaying items from the user's favorites list -sub createFavoritesRow(content as dynamic) - if not m.homeSections.doesExist("favorites") - favoritesRow = content.CreateChild("HomeRow") - favoritesRow.title = tr("Favorites") - end if - - sectionIndex = m.homeSections.count() - - if m.homeSections.doesExist("favorites") - sectionIndex = m.homeSections.favorites.index - end if - - m.homeSections.AddReplace("favorites", { - imageSize: homeRowItemSizes.WIDE_POSTER, - index: sectionIndex - }) - +' createFavoritesRow: Creates a row displaying items from the user's favorites list +' +sub createFavoritesRow() ' Load the Favorites Data m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") m.LoadFavoritesTask.control = "RUN" end sub -' Update home row data +' updateHomeRows: Update function exposed to outside components +' sub updateHomeRows() + ' Hide the row counter to prevent flicker. We'll show it once loading timer fires + m.top.showRowCounter = [false] processUserSections() - setRowItemSizes() end sub +' updateFavoritesItems: Processes LoadFavoritesTask content. Removes, Creates, or Updates favorites row as needed +' sub updateFavoritesItems() itemData = m.LoadFavoritesTask.content m.LoadFavoritesTask.unobserveField("content") @@ -365,44 +402,43 @@ sub updateFavoritesItems() if itemData = invalid then return - rowIndex = m.homeSections.favorites.index + sectionName = tr("Favorites") if itemData.count() < 1 - removeHomeSection("favorites") + removeHomeSection(sectionName) return - else - ' remake row using the new data - row = CreateObject("roSGNode", "HomeRow") - row.title = tr("Favorites") - - for each item in itemData - usePoster = true + end if - if lcase(item.type) = "episode" or lcase(item.type) = "audio" or lcase(item.type) = "musicartist" - usePoster = false - end if + ' remake row using the new data + row = CreateObject("roSGNode", "HomeRow") + row.title = sectionName + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + row.cursorSize = homeRowItemSizes.WIDE_POSTER - item.usePoster = usePoster - item.imageWidth = row.imageWidth - row.appendChild(item) - end for + for each item in itemData + usePoster = true - if isValid(m.top.content.getChild(rowIndex)) - m.top.content.replaceChild(row, rowIndex) - else + if lcase(item.type) = "episode" or lcase(item.type) = "audio" or lcase(item.type) = "musicartist" + usePoster = false + end if - for each section in m.homeSections - if m.homeSections[section].index >= m.top.content.getChildCount() - m.homeSections[section].index++ - end if - end for + item.usePoster = usePoster + item.imageWidth = row.imageWidth + row.appendChild(item) + end for - m.homeSections.favorites.index = m.top.content.getChildCount() - m.top.content.insertChild(row, m.top.content.getChildCount()) - end if + if sectionExists(sectionName) + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() + return end if + + m.top.content.insertChild(row, getSectionIndex(sectionName)) + setRowItemSize() end sub +' updateContinueWatchingItems: Processes LoadContinueWatchingTask content. Removes, Creates, or Updates continue watching row as needed +' sub updateContinueWatchingItems() itemData = m.LoadContinueWatchingTask.content m.LoadContinueWatchingTask.unobserveField("content") @@ -410,14 +446,20 @@ sub updateContinueWatchingItems() if itemData = invalid then return + sectionName = tr("Continue Watching") + if itemData.count() < 1 - removeHomeSection("resume") + removeHomeSection(sectionName) return end if + sectionName = tr("Continue Watching") + ' remake row using the new data row = CreateObject("roSGNode", "HomeRow") - row.title = tr("Continue Watching") + row.title = sectionName + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + row.cursorSize = homeRowItemSizes.WIDE_POSTER for each item in itemData if isValid(item.json) and isValid(item.json.UserData) and isValid(item.json.UserData.PlayedPercentage) @@ -429,10 +471,20 @@ sub updateContinueWatchingItems() row.appendChild(item) end for - ' replace the old row - m.top.content.replaceChild(row, m.homeSections.resume.index) + ' Row already exists, replace it with new content + if sectionExists(sectionName) + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() + return + end if + + ' Row does not exist, insert it into the home view + m.top.content.insertChild(row, getOriginalSectionIndex("resume")) + setRowItemSize() end sub +' updateNextUpItems: Processes LoadNextUpTask content. Removes, Creates, or Updates next up row as needed +' sub updateNextUpItems() itemData = m.LoadNextUpTask.content m.LoadNextUpTask.unobserveField("content") @@ -441,24 +493,40 @@ sub updateNextUpItems() if itemData = invalid then return + sectionName = tr("Next Up") + " >" + if itemData.count() < 1 - removeHomeSection("nextup") + removeHomeSection(sectionName) return - else - ' remake row using the new data - row = CreateObject("roSGNode", "HomeRow") - row.title = tr("Next Up") + " >" - for each item in itemData - item.usePoster = row.usePoster - item.imageWidth = row.imageWidth - row.appendChild(item) - end for + end if + + ' remake row using the new data + row = CreateObject("roSGNode", "HomeRow") + row.title = tr("Next Up") + " >" + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + row.cursorSize = homeRowItemSizes.WIDE_POSTER - ' replace the old row - m.top.content.replaceChild(row, m.homeSections.nextup.index) + for each item in itemData + item.usePoster = row.usePoster + item.imageWidth = row.imageWidth + row.appendChild(item) + end for + + ' Row already exists, replace it with new content + if sectionExists(sectionName) + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() + return end if + + ' Row does not exist, insert it into the home view + m.top.content.insertChild(row, getSectionIndex(sectionName)) + setRowItemSize() end sub +' updateLatestItems: Processes LoadItemsTask content. Removes, Creates, or Updates latest in {library} row as needed +' +' @param {dynamic} msg - LoadItemsTask sub updateLatestItems(msg) itemData = msg.GetData() @@ -468,55 +536,46 @@ sub updateLatestItems(msg) if itemData = invalid then return - sectionName = "latestin" + LCase(node.metadata.title).Replace(" ", "") + sectionName = tr("Latest in") + " " + node.metadata.title + " >" if itemData.count() < 1 removeHomeSection(sectionName) return - else - ' remake row using new data - row = CreateObject("roSGNode", "HomeRow") - row.title = tr("Latest in") + " " + node.metadata.title + " >" - row.usePoster = true - - for each item in itemData - item.usePoster = row.usePoster - item.imageWidth = m.homeSections[sectionName].imageSize[0] - row.appendChild(item) - end for - - rowIndex = m.homeSections[sectionName].index - - if isValid(rowIndex) and isValid(m.top.content.getChild(rowIndex)) - ' Replace the old row - m.top.content.replaceChild(row, rowIndex) - else - firstLatestHomeSectionIndex = m.homeSections.count() - 1 - - for each section in m.homeSections - if LCase(Left(section, 6)) = "latest" - if m.homeSections[section].index < firstLatestHomeSectionIndex - firstLatestHomeSectionIndex = m.homeSections[section].index - end if - end if - end for + end if - for each section in m.homeSections - if m.homeSections[section].index >= firstLatestHomeSectionIndex - m.homeSections[section].index++ - end if - end for + imagesize = homeRowItemSizes.WIDE_POSTER - m.homeSections[sectionName].index = firstLatestHomeSectionIndex - m.top.content.insertChild(row, firstLatestHomeSectionIndex) - end if + if LCase(node.metadata.contentType) = "movies" + imagesize = homeRowItemSizes.MOVIE_POSTER + else if LCase(node.metadata.contentType) = "music" + imagesize = homeRowItemSizes.MUSIC_ALBUM + end if - setRowItemSizes() + ' remake row using new data + row = CreateObject("roSGNode", "HomeRow") + row.title = sectionName + row.imageWidth = imagesize[0] + row.cursorSize = imagesize + for each item in itemData + item.usePoster = row.usePoster + item.imageWidth = row.imageWidth + row.appendChild(item) + end for + if sectionExists(sectionName) + ' Row already exists, replace it with new content + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() + return end if + + m.top.content.insertChild(row, getOriginalSectionIndex("latestmedia")) + setRowItemSize() end sub +' updateOnNowItems: Processes LoadOnNowTask content. Removes, Creates, or Updates latest in on now row as needed +' sub updateOnNowItems() itemData = m.LoadOnNowTask.content m.LoadOnNowTask.unobserveField("content") @@ -524,37 +583,44 @@ sub updateOnNowItems() if itemData = invalid then return + sectionName = tr("On Now") + if itemData.count() < 1 - removeHomeSection("livetv") + removeHomeSection(sectionName) return - else - ' remake row using the new data - row = CreateObject("roSGNode", "HomeRow") - row.title = tr("On Now") - row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] - for each item in itemData - row.usePoster = false - - if (not isValid(item.thumbnailURL) or item.thumbnailURL = "") and isValid(item.json) and isValid(item.json.imageURL) - item.thumbnailURL = item.json.imageURL - row.usePoster = true - row.imageWidth = homeRowItemSizes.MOVIE_POSTER[0] - - m.homeSections.livetv.imageSize = homeRowItemSizes.MOVIE_POSTER - end if + end if - item.usePoster = row.usePoster - item.imageWidth = row.imageWidth - row.appendChild(item) - end for + ' remake row using the new data + row = CreateObject("roSGNode", "HomeRow") + row.title = tr("On Now") + row.imageWidth = homeRowItemSizes.WIDE_POSTER[0] + row.cursorSize = homeRowItemSizes.WIDE_POSTER - ' replace the old row - m.top.content.replaceChild(row, m.homeSections.livetv.index) + for each item in itemData + row.usePoster = false - ' We may now have different poster sizes. Reset the row item sizes - setRowItemSizes() + if (not isValid(item.thumbnailURL) or item.thumbnailURL = "") and isValid(item.json) and isValid(item.json.imageURL) + item.thumbnailURL = item.json.imageURL + row.usePoster = true + row.imageWidth = homeRowItemSizes.MOVIE_POSTER[0] + row.cursorSize = homeRowItemSizes.MOVIE_POSTER + end if + item.usePoster = row.usePoster + item.imageWidth = row.imageWidth + row.appendChild(item) + end for + + ' Row already exists, replace it with new content + if sectionExists(sectionName) + m.top.content.replaceChild(row, getSectionIndex(sectionName)) + setRowItemSize() + return end if + + ' Row does not exist, insert it into the home view + m.top.content.insertChild(row, getOriginalSectionIndex("livetv")) + setRowItemSize() end sub sub itemSelected() From 9cea33dbc7b13dc7d00f422a6ce7021f43bde474 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 08:29:42 -0500 Subject: [PATCH 14/20] Removed dead code. Fix Latest in TV Shows posters --- components/home/HomeRows.bs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index d1b3be413..a4f09e454 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -266,22 +266,6 @@ sub createLatestInRows() filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes) for each lib in filteredLatest if lib.collectionType <> "boxsets" and lib.collectionType <> "livetv" and lib.json.CollectionType <> "Program" - - if not sectionExists(tr("Latest in") + " " + lib.name + " >") - imagesize = homeRowItemSizes.WIDE_POSTER - - if LCase(lib.collectionType) = "movies" - imagesize = homeRowItemSizes.MOVIE_POSTER - else if LCase(lib.collectionType) = "music" - imagesize = homeRowItemSizes.MUSIC_ALBUM - end if - - row = CreateObject("roSGNode", "HomeRow") - row.title = tr("Latest in") + " " + lib.name + " >" - row.imageWidth = imagesize[0] - row.cursorSize = imagesize - end if - loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" loadLatest.itemId = lib.id @@ -556,6 +540,7 @@ sub updateLatestItems(msg) row.title = sectionName row.imageWidth = imagesize[0] row.cursorSize = imagesize + row.usePoster = true for each item in itemData item.usePoster = row.usePoster From 551df567e70282f21be864f3016dd5b86ad3ce6b Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 08:47:35 -0500 Subject: [PATCH 15/20] Rename loading timer const --- components/home/HomeRows.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index a4f09e454..a672783dc 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -1,7 +1,7 @@ import "pkg:/source/utils/misc.bs" import "pkg:/source/constants/HomeRowItemSizes.bs" -const FOCUS_RESIZE_WAIT_TIME = 2 +const LOADING_WAIT_TIME = 2 sub init() m.top.itemComponentName = "HomeItem" @@ -19,7 +19,7 @@ sub init() m.top.content = CreateObject("roSGNode", "ContentNode") m.loadingTimer = createObject("roSGNode", "Timer") - m.loadingTimer.duration = FOCUS_RESIZE_WAIT_TIME + m.loadingTimer.duration = LOADING_WAIT_TIME m.loadingTimer.observeField("fire", "loadingTimerComplete") updateSize() From 685a623607807c2cce60a7b4ada5ec647b97e684 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 18:30:33 -0500 Subject: [PATCH 16/20] Add valid check to contentType Value can be invalid for trailer libraries --- components/home/HomeRows.bs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index a672783dc..29cb6d986 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -529,10 +529,12 @@ sub updateLatestItems(msg) imagesize = homeRowItemSizes.WIDE_POSTER - if LCase(node.metadata.contentType) = "movies" - imagesize = homeRowItemSizes.MOVIE_POSTER - else if LCase(node.metadata.contentType) = "music" - imagesize = homeRowItemSizes.MUSIC_ALBUM + if isValid(node.metadata.contentType) + if LCase(node.metadata.contentType) = "movies" + imagesize = homeRowItemSizes.MOVIE_POSTER + else if LCase(node.metadata.contentType) = "music" + imagesize = homeRowItemSizes.MUSIC_ALBUM + end if end if ' remake row using new data From fe0f02bbcc50017e8486b0fad07b91ac4f9e0e75 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 19:31:09 -0500 Subject: [PATCH 17/20] Defensive code for if no custom prefs returned --- source/utils/session.bs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/source/utils/session.bs b/source/utils/session.bs index e5604c02d..a468a5605 100644 --- a/source/utils/session.bs +++ b/source/utils/session.bs @@ -223,6 +223,17 @@ namespace session unset_user_setting("display.livetv.landing") end if else + ' User has no custom prefs. Save default home section values. + session.user.SaveUserHomeSections({ + homesection0: "smalllibrarytiles", + homesection1: "resume", + homesection2: "nextup", + homesection3: "latestmedia", + homesection4: "livetv", + homesection5: "none", + homesection6: "none" + }) + unset_user_setting("display.livetv.landing") end if end sub From 687d51892b5c09db8d45ade71e2603fc93e5d39c Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 19:34:46 -0500 Subject: [PATCH 18/20] Set row item size after removing row --- components/home/HomeRows.bs | 1 + 1 file changed, 1 insertion(+) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 29cb6d986..dddaad6cd 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -158,6 +158,7 @@ sub removeHomeSection(sectionTitleToRemove as string) sectionIndexToRemove = getSectionIndex(sectionTitle) m.top.content.removeChildIndex(sectionIndexToRemove) + setRowItemSize() end sub ' setRowItemSize: Loops through all home sections and sets the correct item sizes per row From 2832799c82097f9a7dc3516353a000a7e96f3d9a Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 2 Dec 2023 22:10:25 -0500 Subject: [PATCH 19/20] Create short circuit if content loads faster than wait time --- components/home/HomeRows.bs | 51 ++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index dddaad6cd..894e5e47e 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -72,6 +72,7 @@ end sub ' processUserSections: Loop through user's chosen home section settings and generate the content for each row ' sub processUserSections() + m.expectedRowCount = 0 loadedSections = 0 ' Add sections in order based on user settings @@ -174,13 +175,21 @@ sub setRowItemSize() end for m.top.rowItemSize = newSizeArray + + ' If we have the expected number of content rows, stop the loading timer and run the complete function + if m.expectedRowCount = homeSections.count() + m.loadingTimer.control = "stop" + loadingTimerComplete() + end if end sub ' loadingTimerComplete: Event handler for when loading wait time has expired ' sub loadingTimerComplete() - ' Show the row counter to prevent flicker - m.top.showRowCounter = [true] + if not m.top.showRowCounter[0] + ' Show the row counter to prevent flicker + m.top.showRowCounter = [true] + end if end sub ' addHomeSection: Adds a new home section to the home rows. @@ -233,6 +242,8 @@ sub createLibraryRow() ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return + m.expectedRowCount++ + sectionName = tr("My Media") row = CreateObject("roSGNode", "HomeRow") @@ -271,6 +282,8 @@ sub createLatestInRows() loadLatest.itemsToLoad = "latest" loadLatest.itemId = lib.id + m.expectedRowCount++ + metadata = { "title": lib.name } metadata.Append({ "contentType": lib.json.CollectionType }) loadLatest.metadata = metadata @@ -333,6 +346,7 @@ end function ' createLiveTVRow: Creates a row displaying the live tv now on section ' sub createLiveTVRow() + m.expectedRowCount++ m.LoadOnNowTask.observeField("content", "updateOnNowItems") m.LoadOnNowTask.control = "RUN" end sub @@ -340,6 +354,7 @@ end sub ' createContinueWatchingRow: Creates a row displaying items the user can continue watching ' sub createContinueWatchingRow() + m.expectedRowCount++ ' Load the Continue Watching Data m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") m.LoadContinueWatchingTask.control = "RUN" @@ -348,6 +363,7 @@ end sub ' createNextUpRow: Creates a row displaying next episodes up to watch ' sub createNextUpRow() + m.expectedRowCount++ sectionName = tr("Next Up") + ">" if not sectionExists(sectionName) @@ -365,6 +381,7 @@ end sub ' createFavoritesRow: Creates a row displaying items from the user's favorites list ' sub createFavoritesRow() + m.expectedRowCount++ ' Load the Favorites Data m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") m.LoadFavoritesTask.control = "RUN" @@ -385,11 +402,15 @@ sub updateFavoritesItems() m.LoadFavoritesTask.unobserveField("content") m.LoadFavoritesTask.content = [] - if itemData = invalid then return + if itemData = invalid + m.expectedRowCount-- + return + end if sectionName = tr("Favorites") if itemData.count() < 1 + m.expectedRowCount-- removeHomeSection(sectionName) return end if @@ -429,11 +450,15 @@ sub updateContinueWatchingItems() m.LoadContinueWatchingTask.unobserveField("content") m.LoadContinueWatchingTask.content = [] - if itemData = invalid then return + if not isValid(itemData) + m.expectedRowCount-- + return + end if sectionName = tr("Continue Watching") if itemData.count() < 1 + m.expectedRowCount-- removeHomeSection(sectionName) return end if @@ -476,11 +501,15 @@ sub updateNextUpItems() m.LoadNextUpTask.content = [] m.LoadNextUpTask.control = "STOP" - if itemData = invalid then return + if itemData = invalid + m.expectedRowCount-- + return + end if sectionName = tr("Next Up") + " >" if itemData.count() < 1 + m.expectedRowCount-- removeHomeSection(sectionName) return end if @@ -519,11 +548,15 @@ sub updateLatestItems(msg) node.unobserveField("content") node.content = [] - if itemData = invalid then return + if itemData = invalid + m.expectedRowCount-- + return + end if sectionName = tr("Latest in") + " " + node.metadata.title + " >" if itemData.count() < 1 + m.expectedRowCount-- removeHomeSection(sectionName) return end if @@ -569,11 +602,15 @@ sub updateOnNowItems() m.LoadOnNowTask.unobserveField("content") m.LoadOnNowTask.content = [] - if itemData = invalid then return + if not isValid(itemData) + m.expectedRowCount-- + return + end if sectionName = tr("On Now") if itemData.count() < 1 + m.expectedRowCount-- removeHomeSection(sectionName) return end if From 7e7ac107afcce46ecf3bfa56efb1891d0f263abd Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:18:59 -0500 Subject: [PATCH 20/20] Create expected & processed counts. Hook short circuit to their values Code by cewert --- components/home/HomeRows.bs | 93 ++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 52 deletions(-) diff --git a/components/home/HomeRows.bs b/components/home/HomeRows.bs index 894e5e47e..b888da392 100644 --- a/components/home/HomeRows.bs +++ b/components/home/HomeRows.bs @@ -72,13 +72,33 @@ end sub ' processUserSections: Loop through user's chosen home section settings and generate the content for each row ' sub processUserSections() - m.expectedRowCount = 0 - loadedSections = 0 + m.expectedRowCount = 1 ' the favorites row is hardcoded to always show atm + m.processedRowCount = 0 + + ' calculate expected row count by processing homesections + for i = 0 to 6 + sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()]) + if sectionName = "latestmedia" + ' expect 1 row per filtered media library + m.filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes) + for each latestLibrary in m.filteredLatest + if latestLibrary.collectionType <> "boxsets" and latestLibrary.collectionType <> "livetv" and latestLibrary.json.CollectionType <> "Program" + m.expectedRowCount++ + end if + end for + else if sectionName <> "none" + m.expectedRowCount++ + end if + end for - ' Add sections in order based on user settings + ' Add home sections in order based on user settings + loadedSections = 0 for i = 0 to 6 sectionName = LCase(m.global.session.user.settings["homesection" + i.toStr()]) - sectionLoaded = addHomeSection(sectionName) + sectionLoaded = false + if sectionName <> "none" + sectionLoaded = addHomeSection(sectionName) + end if ' Count how many sections with data are loaded if sectionLoaded then loadedSections++ @@ -173,11 +193,10 @@ sub setRowItemSize() for i = 0 to homeSections.count() - 1 newSizeArray[i] = isValid(homeSections[i].cursorSize) ? homeSections[i].cursorSize : homeRowItemSizes.WIDE_POSTER end for - m.top.rowItemSize = newSizeArray - ' If we have the expected number of content rows, stop the loading timer and run the complete function - if m.expectedRowCount = homeSections.count() + ' If we have processed the expected number of content rows, stop the loading timer and run the complete function + if m.expectedRowCount = m.processedRowCount m.loadingTimer.control = "stop" loadingTimerComplete() end if @@ -233,17 +252,19 @@ function addHomeSection(sectionType as string) as boolean return true end if + ' This section type isn't supported. + ' Count it as processed since we aren't going to do anything else with it + m.processedRowCount++ return false end function ' createLibraryRow: Creates a row displaying the user's libraries ' sub createLibraryRow() + m.processedRowCount++ ' Ensure we have data if not isValidAndNotEmpty(m.libraryData) then return - m.expectedRowCount++ - sectionName = tr("My Media") row = CreateObject("roSGNode", "HomeRow") @@ -275,15 +296,12 @@ sub createLatestInRows() if not isValidAndNotEmpty(m.libraryData) then return ' create a "Latest In" row for each library - filteredLatest = filterNodeArray(m.libraryData, "id", m.global.session.user.configuration.LatestItemsExcludes) - for each lib in filteredLatest + for each lib in m.filteredLatest if lib.collectionType <> "boxsets" and lib.collectionType <> "livetv" and lib.json.CollectionType <> "Program" loadLatest = createObject("roSGNode", "LoadItemsTask") loadLatest.itemsToLoad = "latest" loadLatest.itemId = lib.id - m.expectedRowCount++ - metadata = { "title": lib.name } metadata.Append({ "contentType": lib.json.CollectionType }) loadLatest.metadata = metadata @@ -346,7 +364,6 @@ end function ' createLiveTVRow: Creates a row displaying the live tv now on section ' sub createLiveTVRow() - m.expectedRowCount++ m.LoadOnNowTask.observeField("content", "updateOnNowItems") m.LoadOnNowTask.control = "RUN" end sub @@ -354,7 +371,6 @@ end sub ' createContinueWatchingRow: Creates a row displaying items the user can continue watching ' sub createContinueWatchingRow() - m.expectedRowCount++ ' Load the Continue Watching Data m.LoadContinueWatchingTask.observeField("content", "updateContinueWatchingItems") m.LoadContinueWatchingTask.control = "RUN" @@ -363,7 +379,6 @@ end sub ' createNextUpRow: Creates a row displaying next episodes up to watch ' sub createNextUpRow() - m.expectedRowCount++ sectionName = tr("Next Up") + ">" if not sectionExists(sectionName) @@ -381,7 +396,6 @@ end sub ' createFavoritesRow: Creates a row displaying items from the user's favorites list ' sub createFavoritesRow() - m.expectedRowCount++ ' Load the Favorites Data m.LoadFavoritesTask.observeField("content", "updateFavoritesItems") m.LoadFavoritesTask.control = "RUN" @@ -398,19 +412,14 @@ end sub ' updateFavoritesItems: Processes LoadFavoritesTask content. Removes, Creates, or Updates favorites row as needed ' sub updateFavoritesItems() + m.processedRowCount++ itemData = m.LoadFavoritesTask.content m.LoadFavoritesTask.unobserveField("content") m.LoadFavoritesTask.content = [] - if itemData = invalid - m.expectedRowCount-- - return - end if - sectionName = tr("Favorites") - if itemData.count() < 1 - m.expectedRowCount-- + if not isValidAndNotEmpty(itemData) removeHomeSection(sectionName) return end if @@ -446,19 +455,14 @@ end sub ' updateContinueWatchingItems: Processes LoadContinueWatchingTask content. Removes, Creates, or Updates continue watching row as needed ' sub updateContinueWatchingItems() + m.processedRowCount++ itemData = m.LoadContinueWatchingTask.content m.LoadContinueWatchingTask.unobserveField("content") m.LoadContinueWatchingTask.content = [] - if not isValid(itemData) - m.expectedRowCount-- - return - end if - sectionName = tr("Continue Watching") - if itemData.count() < 1 - m.expectedRowCount-- + if not isValidAndNotEmpty(itemData) removeHomeSection(sectionName) return end if @@ -496,20 +500,15 @@ end sub ' updateNextUpItems: Processes LoadNextUpTask content. Removes, Creates, or Updates next up row as needed ' sub updateNextUpItems() + m.processedRowCount++ itemData = m.LoadNextUpTask.content m.LoadNextUpTask.unobserveField("content") m.LoadNextUpTask.content = [] m.LoadNextUpTask.control = "STOP" - if itemData = invalid - m.expectedRowCount-- - return - end if - sectionName = tr("Next Up") + " >" - if itemData.count() < 1 - m.expectedRowCount-- + if not isValidAndNotEmpty(itemData) removeHomeSection(sectionName) return end if @@ -542,21 +541,16 @@ end sub ' ' @param {dynamic} msg - LoadItemsTask sub updateLatestItems(msg) + m.processedRowCount++ itemData = msg.GetData() node = msg.getRoSGNode() node.unobserveField("content") node.content = [] - if itemData = invalid - m.expectedRowCount-- - return - end if - sectionName = tr("Latest in") + " " + node.metadata.title + " >" - if itemData.count() < 1 - m.expectedRowCount-- + if not isValidAndNotEmpty(itemData) removeHomeSection(sectionName) return end if @@ -598,19 +592,14 @@ end sub ' updateOnNowItems: Processes LoadOnNowTask content. Removes, Creates, or Updates latest in on now row as needed ' sub updateOnNowItems() + m.processedRowCount++ itemData = m.LoadOnNowTask.content m.LoadOnNowTask.unobserveField("content") m.LoadOnNowTask.content = [] - if not isValid(itemData) - m.expectedRowCount-- - return - end if - sectionName = tr("On Now") - if itemData.count() < 1 - m.expectedRowCount-- + if not isValidAndNotEmpty(itemData) removeHomeSection(sectionName) return end if