Skip to content

Add unplayed episode count and refresh number in real time #265

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 8, 2025
9 changes: 4 additions & 5 deletions components/ItemGrid/GridItemMedium.bs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@ sub itemContentChanged()

if not isValid(itemData) then return

if isChainValid(itemData.json, "UserData.Played") and itemData.json.UserData.Played
m.playedIndicator.visible = true
else
m.playedIndicator.visible = false
end if
m.playedIndicator.data = {
played: chainLookupReturn(itemData, "json.UserData.Played", false),
unplayedCount: chainLookupReturn(itemData, "json.UserData.UnplayedItemCount", 0)
}

' Set Series and Episode Number for Extra Text
extraPrefix = string.EMPTY
Expand Down
2 changes: 1 addition & 1 deletion components/ItemGrid/GridItemMedium.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Poster id="itemIcon" width="50" height="50" translation="[5,5]" />
</Rectangle>
<Label id="posterText" width="400" height="300" translation="[5,5]" horizAlign="center" vertAlign="center" ellipsizeOnBoundary="true" wrap="true" />
<PlayedCheckmark id="playedIndicator" color="#00a4dcFF" width="60" height="46" translation="[340, 15]" visible="false" />
<PlayedCheckmark id="playedIndicator" translation="[340, 22]" />
</children>
<interface>
<field id="itemContent" type="node" onChange="itemContentChanged" />
Expand Down
9 changes: 4 additions & 5 deletions components/ItemGrid/GridItemSmall.bs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,10 @@ sub itemContentChanged()

if not isValid(itemData) then return

if isChainValid(itemData, "json.UserData.Played") and itemData.json.UserData.Played
m.playedIndicator.visible = true
else
m.playedIndicator.visible = false
end if
m.playedIndicator.data = {
played: chainLookupReturn(itemData, "json.UserData.Played", false),
unplayedCount: chainLookupReturn(itemData, "json.UserData.UnplayedItemCount", 0)
}

m.itemPoster.uri = itemData.PosterUrl
if isValidAndNotEmpty(itemData.LookupCI("fullNameWithShowTitle"))
Expand Down
2 changes: 1 addition & 1 deletion components/ItemGrid/GridItemSmall.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<Poster id="itemIcon" width="50" height="50" translation="[230,10]" />
<Label id="posterText" width="230" height="345" translation="[5,5]" horizAlign="center" vertAlign="center" ellipsizeOnBoundary="true" wrap="true" />
<PlayedCheckmark id="playedIndicator" color="#00a4dcFF" width="60" height="46" translation="[170, 15]" visible="false" />
<PlayedCheckmark id="playedIndicator" width="60" height="46" translation="[170, 22]" />
</children>
<interface>
<field id="itemContent" type="node" onChange="itemContentChanged" />
Expand Down
44 changes: 44 additions & 0 deletions components/ItemGrid/ItemGrid.bs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ import "pkg:/source/enums/KeyCode.bs"
import "pkg:/source/enums/PosterLoadStatus.bs"
import "pkg:/source/enums/String.bs"
import "pkg:/source/enums/TaskControl.bs"
import "pkg:/source/enums/ViewLoadStatus.bs"
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/deviceCapabilities.bs"
import "pkg:/source/utils/misc.bs"

sub init()
m.top.findNode("VoiceBoxCover").color = ColorPalette.VIEWBACKGROUND
m.loadItemsTask1 = createObject("roSGNode", "LoadItemsTask")

overhang = m.top.getScene().findNode("overhang")
overhang.isVisible = false
Expand Down Expand Up @@ -80,6 +82,8 @@ sub init()
m.alphaMenu = m.alpha.findNode("alphaMenu")

m.top.gridTitles = m.global.session.user.settings["itemgrid.gridTitles"]

m.loadStatus = ViewLoadStatus.INIT
end sub

sub createItemGrid()
Expand Down Expand Up @@ -740,6 +744,7 @@ end sub
'Item Selected
sub onItemSelected()
m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected)
m.top.selectedItem = invalid
end sub

sub alphaSelectedChanged()
Expand Down Expand Up @@ -1015,3 +1020,42 @@ sub onPlaylistDataLoaded()
dialogData = [tr("Delete Playlist")]
m.global.sceneManager.callFunc("optionDialog", "libraryitem", m.getPlaylistDataTask.LookupCI("selectedItemTitle") ?? tr("Options"), [], dialogData, { id: m.getPlaylistDataTask.LookupCI("playlistID") })
end sub

sub OnScreenShown()
group = m.global.sceneManager.callFunc("getActiveScene")

if isValid(m.top.lastFocus)
m.top.lastFocus.setFocus(true)
group.lastFocus = m.top.lastFocus
else
m.top.setFocus(true)
group.lastFocus = m.top
end if

if isStringEqual(m.loadStatus, ViewLoadStatus.INIT)
m.loadStatus = ViewLoadStatus.FIRSTLOAD
return
end if

focusedItem = getItemFocused()

if isValid(focusedItem)
m.loadItemsTask1.itemId = focusedItem.LookupCI("id")
m.loadItemsTask1.observeField("content", "onItemDataLoaded")
m.loadItemsTask1.itemsToLoad = "metaData"
m.loadItemsTask1.control = TaskControl.RUN
end if
end sub

sub onItemDataLoaded()
itemData = m.loadItemsTask1.content
m.loadItemsTask1.unobserveField("content")
m.loadItemsTask1.content = []

if not isValidAndNotEmpty(itemData) then return

focusedItem = getItemFocused()
if not isValid(focusedItem) then return

focusedItem.callFunc("setWatched", chainLookupReturn(itemData[0], "json.UserData.Played", false), chainLookupReturn(itemData[0], "json.UserData.UnplayedItemCount", 0))
end sub
2 changes: 1 addition & 1 deletion components/ItemGrid/ItemGrid.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="ItemGrid" extends="JFGroup">
<component name="ItemGrid" extends="JFScreen">
<children>
<VoiceTextEditBox id="VoiceBox" visible="true" width="40" translation="[52, 120]" />
<Rectangle id="VoiceBoxCover" height="240" width="100" translation="[25, 75]" />
Expand Down
2 changes: 1 addition & 1 deletion components/ItemGrid/LoadItemsTask2.bs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ sub loadItems()
SortBy: sort_field,
SortOrder: sort_order,
recursive: m.top.recursive,
Fields: "Overview",
Fields: "Overview, RecursiveItemCount",
StudioIds: m.top.studioIds,
genreIds: m.top.genreIds
}
Expand Down
29 changes: 27 additions & 2 deletions components/Libraries/VisualLibraryScene.bs
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ sub init()
m.view = "presentation"

m.loadItemsTask1 = createObject("roSGNode", "LoadItemsTask")
m.loadItemsTask1.observeField("content", "onMyListLoaded")
m.loadItemsTask1.itemsToLoad = "isInMyList"

m.loadItemsTask = createObject("roSGNode", "LoadItemsTask2")
m.loadLogoTask = createObject("roSGNode", "LoadItemsTask2")
Expand All @@ -150,12 +148,35 @@ sub OnScreenShown()
if isValid(m.top.lastFocus)
m.top.lastFocus.setFocus(true)
group.lastFocus = m.top.lastFocus

focusedItem = getItemFocused()

if isValid(focusedItem)
m.loadItemsTask1.itemId = focusedItem.LookupCI("id")
m.loadItemsTask1.observeField("content", "onItemDataLoaded")
m.loadItemsTask1.itemsToLoad = "metaData"
m.loadItemsTask1.control = TaskControl.RUN
end if

else
m.top.setFocus(true)
group.lastFocus = m.top
end if
end sub

sub onItemDataLoaded()
itemData = m.loadItemsTask1.content
m.loadItemsTask1.unobserveField("content")
m.loadItemsTask1.content = []

if not isValidAndNotEmpty(itemData) then return

focusedItem = getItemFocused()
if not isValid(focusedItem) then return

focusedItem.callFunc("setWatched", chainLookupReturn(itemData[0], "json.UserData.Played", false), chainLookupReturn(itemData[0], "json.UserData.UnplayedItemCount", 0))
end sub

'
'Load initial set of Data
sub loadInitialItems()
Expand Down Expand Up @@ -1055,6 +1076,7 @@ end sub
'Item Selected
sub onItemSelected()
m.top.selectedItem = m.itemGrid.content.getChild(m.itemGrid.itemSelected)
m.top.selectedItem = invalid
end sub

'
Expand Down Expand Up @@ -1638,6 +1660,8 @@ function onKeyEvent(key as string, press as boolean) as boolean
if not isValid(focusedItem) then return false

m.loadItemsTask1.itemId = focusedItem.LookupCI("id")
m.loadItemsTask1.observeField("content", "onMyListLoaded")
m.loadItemsTask1.itemsToLoad = "isInMyList"
m.loadItemsTask1.control = TaskControl.RUN
return true
end if
Expand All @@ -1648,6 +1672,7 @@ end function
sub onMyListLoaded()
isInMyListData = m.loadItemsTask1.content
m.loadItemsTask1.content = []
m.loadItemsTask1.unobserveField("content")

if not isValidAndNotEmpty(isInMyListData) then return

Expand Down
48 changes: 16 additions & 32 deletions components/ListPoster.bs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import "pkg:/source/enums/ColorPalette.bs"
import "pkg:/source/enums/ViewLoadStatus.bs"
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"

Expand All @@ -6,25 +8,12 @@ sub init()
m.staticTitle = m.top.findNode("staticTitle")
m.series = m.top.findNode("Series")
m.poster = m.top.findNode("poster")
m.unplayedCount = m.top.findNode("unplayedCount")
m.unplayedEpisodeCount = m.top.findNode("unplayedEpisodeCount")
m.playedIndicator = m.top.findNode("playedIndicator")
m.checkmark = m.top.findNode("checkmark")
m.checkmark.width = 90
m.checkmark.height = 60
m.loadStatus = ViewLoadStatus.INIT

m.backdrop = m.top.findNode("backdrop")

' Randomize the background colors
backdropColor = "#00a4db" ' set default in case global var is invalid
localGlobal = m.global

if isValid(localGlobal) and isValid(localGlobal.constants) and isValid(localGlobal.constants.poster_bg_pallet)
posterBackgrounds = localGlobal.constants.poster_bg_pallet
backdropColor = posterBackgrounds[rnd(posterBackgrounds.count()) - 1]
end if

m.backdrop.color = backdropColor
m.backdrop.color = ColorPalette.DARKGREY
updateSize()
end sub

Expand All @@ -34,11 +23,7 @@ sub updateSize()
image = m.top.itemContent.image
end if

if image = invalid
m.backdrop.visible = true
else
m.backdrop.visible = false
end if
m.backdrop.visible = not isValid(image)

' TODO - abstract this in case the parent doesnt have itemSize
maxSize = m.top.getParent().itemSize
Expand Down Expand Up @@ -66,18 +51,10 @@ sub itemContentChanged() as void
itemData = m.top.itemContent
m.title.text = itemData.title

if m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] = false
if isValid(itemData.json.UserData) and isValid(itemData.json.UserData.UnplayedItemCount)
if itemData.json.UserData.UnplayedItemCount > 0
m.unplayedCount.visible = true
m.unplayedEpisodeCount.text = itemData.json.UserData.UnplayedItemCount
end if
end if
end if

if isValid(itemData.json) and isValid(itemData.json.UserData) and isValid(itemData.json.UserData.Played) and itemData.json.UserData.Played
m.playedIndicator.visible = true
end if
m.playedIndicator.data = {
played: chainLookupReturn(itemData, "json.UserData.Played", false),
unplayedCount: chainLookupReturn(itemData, "json.UserData.UnplayedItemCount", 0)
}

if itemData.json.lookup("Type") = "Episode" and isValid(itemData.json.IndexNumber)
m.title.text = StrI(itemData.json.IndexNumber) + ". " + m.title.text
Expand All @@ -90,6 +67,7 @@ sub itemContentChanged() as void
else
m.series.visible = false
end if

m.staticTitle.text = m.title.text

imageUrl = itemData.posterURL
Expand All @@ -104,7 +82,13 @@ sub itemContentChanged() as void

m.poster.uri = imageUrl

if not isStringEqual(m.loadStatus, ViewLoadStatus.INIT) then return

updateSize()

if isStringEqual(m.loadStatus, ViewLoadStatus.INIT)
m.loadStatus = ViewLoadStatus.FIRSTLOAD
end if
end sub

'
Expand Down
5 changes: 1 addition & 4 deletions components/ListPoster.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
<Rectangle id="backdrop" />
<ScrollingLabel id="Series" horizAlign="center" font="font:SmallSystemFont" repeatCount="0" visible="false" />
<Poster id="poster" translation="[2,0]" loadDisplayMode="scaleToFit">
<Rectangle id="unplayedCount" visible="false" width="90" height="60" color="#00a4dcFF" translation="[102, 0]">
<Label id="unplayedEpisodeCount" width="90" height="60" font="font:MediumBoldSystemFont" horizAlign="center" vertAlign="center" />
</Rectangle>
<PlayedCheckmark id="playedIndicator" color="#00a4dcFF" width="90" height="60" translation="[102, 0]" visible="false" />
<PlayedCheckmark id="playedIndicator" translation="[135, 0]" />
</Poster>
<ScrollingLabel id="title" horizAlign="center" font="font:SmallSystemFont" repeatCount="0" visible="false" />
<Label id="staticTitle" horizAlign="center" font="font:SmallSystemFont" wrap="false" />
Expand Down
44 changes: 42 additions & 2 deletions components/PlayedCheckmark.bs
Original file line number Diff line number Diff line change
@@ -1,4 +1,44 @@
import "pkg:/source/enums/ColorPalette.bs"
import "pkg:/source/utils/misc.bs"

sub init()
checkmark = m.top.findNode("checkmark")
checkmark.font.size = 48
m.top.width = 60
m.top.height = 50

m.unplayedNumber = m.top.findNode("unplayedNumber")

m.checkmark = m.top.findNode("checkmark")
m.checkmark.font.size = 48

m.top.color = ColorPalette.TRANSPARENT
m.checkmark.visible = false
m.unplayedNumber.visible = false
end sub

sub onDataChange()
m.top.color = ColorPalette.TRANSPARENT
m.checkmark.visible = false
m.unplayedNumber.visible = false

if not isValidAndNotEmpty(m.top.data) then return

if chainLookupReturn(m.top.data, "unplayedCount", 0) > 0
if m.global.session.user.settings["ui.tvshows.disableUnwatchedEpisodeCount"] then return

unplayedCount = m.top.data.unplayedCount.ToStr()
unplayedCountLength = len(unplayedCount)

m.unplayedNumber.font.size = unplayedCountLength = 4 ? 25 : 30

m.top.color = ColorPalette.TRIADBLUE
m.unplayedNumber.visible = true
m.unplayedNumber.text = unplayedCount
return
end if

if chainLookupReturn(m.top.data, "played", false)
m.top.color = ColorPalette.TRIADBLUE
m.checkmark.visible = true
return
end if
end sub
22 changes: 21 additions & 1 deletion components/PlayedCheckmark.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="PlayedCheckmark" extends="Rectangle">
<children>
<Label id="checkmark" width="60" height="50" font="font:MediumBoldSystemFont" horizAlign="center" vertAlign="bottom" text="✓" />
<Label
id="checkmark"
width="60"
height="50"
font="font:MediumBoldSystemFont"
horizAlign="center"
vertAlign="center"
text="✓"
visible="false" />

<Label
id="unplayedNumber"
width="60"
height="50"
font="font:MediumBoldSystemFont"
horizAlign="center"
vertAlign="center"
visible="false" />
</children>
<interface>
<field id="data" type="assocarray" onChange="onDataChange" />
</interface>
</component>
Loading