Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/unstable' into rename-files
Browse files Browse the repository at this point in the history
  • Loading branch information
cewert committed Nov 11, 2023
2 parents 323b147 + 1e57180 commit a592bd8
Show file tree
Hide file tree
Showing 330 changed files with 10,433 additions and 2,073 deletions.
21 changes: 11 additions & 10 deletions .github/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@ changelog:
categories:
- title: 🆕 New Features
labels:
- "new feature"
- title: 🔨 Updated Features
labels:
- "updated feature"
- "new-feature"
- title: ⚙️ New Settings
labels:
- "new setting"
- title: 🔧 Updated Settings
labels:
- "updated setting"
- "new-setting"
- title: 🐛 Bug Fixes
labels:
- "bug fix"
- "bug-fix"
- title: 🧹 Code Cleanup
labels:
- "code cleanup"
- "code-cleanup"
- title: 💻 Dev Improvements
labels:
- "dev-improvement"
- title: 📝 Documentation
labels:
- "documentation"
- title: ⭐ Additional Updates
labels:
- "*"
exclude:
labels:
- dependencies
- ignore-changelog
1 change: 1 addition & 0 deletions .github/workflows/auto-close-stale-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
with:
days-before-issue-stale: -1
days-before-issue-close: -1
stale-pr-label: stale
stale-pr-message: "This pull request has been inactive for 21 days and will be automatically closed in 7 days if there is no further activity."
close-pr-message: "This pull request has been closed because it has been inactive for 28 days. You may submit a new pull request if desired."
days-before-pr-stale: 21
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/automations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,6 @@ jobs:
- name: Check all PRs for merge conflicts ⛔
uses: eps1lon/actions-label-merge-conflict@releases/2.x
with:
dirtyLabel: "merge conflict"
dirtyLabel: "merge-conflict"
commentOnDirty: "This pull request has merge conflicts. Please resolve the conflicts so the PR can be reviewed. Thanks!"
repoToken: ${{ secrets.JF_BOT_TOKEN }}
39 changes: 39 additions & 0 deletions components/Clock.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import "pkg:/source/utils/misc.brs"

sub init()

' If hideclick setting is checked, exit without setting any variables
if m.global.session.user.settings["ui.design.hideclock"]
return
end if

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

m.currentTimeTimer = m.top.findNode("currentTimeTimer")
m.dateTimeObject = CreateObject("roDateTime")

m.currentTimeTimer.observeField("fire", "onCurrentTimeTimerFire")
m.currentTimeTimer.control = "start"

' Default to 12 hour clock
m.format = "short-h12"

' If user has selected a 24 hour clock, update date display format
if LCase(m.global.device.clockFormat) = "24h"
m.format = "short-h24"
end if
end sub


' onCurrentTimeTimerFire: Code that runs every time the currentTimeTimer fires
'
sub onCurrentTimeTimerFire()
' Refresh time variable
m.dateTimeObject.Mark()

' Convert to local time zone
m.dateTimeObject.ToLocalTime()

' Format time as requested
m.clockTime.text = m.dateTimeObject.asTimeStringLoc(m.format)
end sub
9 changes: 9 additions & 0 deletions components/Clock.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Clock" extends="Group">
<children>
<Label id="clockTime" font="font:SmallSystemFont" horizAlign="right" vertAlign="center" height="64" width="200" />
<Timer id="currentTimeTimer" repeat="true" duration="1" />
</children>
<interface>
</interface>
</component>
1 change: 1 addition & 0 deletions components/ItemGrid/LoadVideoContentTask.bs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ sub LoadItems_AddVideoContent(video as object, mediaSourceId as dynamic, audio_s
video.content.contenttype = "episode"
end if

video.chapters = meta.json.Chapters
video.content.title = meta.title
video.showID = meta.showID

Expand Down
13 changes: 5 additions & 8 deletions components/data/SceneManager.bs
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,6 @@ sub popScene()
if group <> invalid
registerOverhangData(group)

if group.subtype() = "Home"
currentTime = CreateObject("roDateTime").AsSeconds()
if group.timeLastRefresh = invalid or (currentTime - group.timeLastRefresh) > 20
group.timeLastRefresh = currentTime
group.callFunc("refresh")
end if
end if

group.visible = true

m.content.replaceChild(group, 0)
Expand Down Expand Up @@ -143,6 +135,11 @@ end function
' Clear all content from group stack
sub clearScenes()
if m.content <> invalid then m.content.removeChildrenIndex(m.content.getChildCount(), 0)
for each group in m.groups
if LCase(group.subtype()) = "jfscreen"
group.callFunc("OnScreenHidden")
end if
end for
m.groups = []
end sub

Expand Down
32 changes: 32 additions & 0 deletions components/home/Home.bs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import "pkg:/source/api/baserequest.bs"
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"
import "pkg:/source/utils/deviceCapabilities.bs"

sub init()
m.isFirstRun = true
m.top.overhangTitle = "Home"
m.top.optionsAvailable = true
m.postTask = createObject("roSGNode", "PostTask")

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")
Expand All @@ -18,3 +22,31 @@ end sub
sub loadLibraries()
m.top.findNode("homeRows").callFunc("loadLibraries")
end sub

' JFScreen hook that gets ran as needed.
' Used to update the focus, the state of the data, and tells the server about the device profile
sub OnScreenShown()
if isValid(m.top.lastFocus)
m.top.lastFocus.setFocus(true)
else
m.top.setFocus(true)
end if

refresh()

' post the device profile the first time this screen is loaded
if m.isFirstRun
m.isFirstRun = false
m.postTask.arrayData = getDeviceCapabilities()
m.postTask.apiUrl = "/Sessions/Capabilities/Full"
m.postTask.control = "RUN"
m.postTask.observeField("responseCode", "postFinished")
end if
end sub

' Triggered by m.postTask after completing a post.
' Empty the task data when finished.
sub postFinished()
m.postTask.unobserveField("responseCode")
m.postTask.callFunc("empty")
end sub
3 changes: 1 addition & 2 deletions components/home/Home.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Home" extends="JFGroup">
<component name="Home" extends="JFScreen">
<children>
<Poster id="backdrop" loadDisplayMode="scaleToZoom" width="1920" height="1200" />
<HomeRows id="homeRows" />
Expand All @@ -8,7 +8,6 @@
<interface>
<field id="selectedItem" alias="homeRows.selectedItem" />
<field id="quickPlayNode" alias="homeRows.quickPlayNode" />
<field id="timeLastRefresh" type="integer" />
<function name="refresh" />
<function name="loadLibraries" />
</interface>
Expand Down
21 changes: 21 additions & 0 deletions components/settings/settings.bs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"
import "pkg:/source/roku_modules/log/LogMixin.brs"
' post device profile
import "pkg:/source/utils/deviceCapabilities.brs"

sub init()
m.log = log.Logger("Settings")
Expand All @@ -27,6 +29,8 @@ sub init()
m.boolSetting.observeField("checkedItem", "boolSettingChanged")
m.radioSetting.observeField("checkedItem", "radioSettingChanged")

m.postTask = createObject("roSGNode", "PostTask")

' Load Configuration Tree
m.configTree = GetConfigTree()
LoadMenu({ children: m.configTree })
Expand Down Expand Up @@ -201,6 +205,23 @@ sub radioSettingChanged()
set_user_setting(selectedSetting.settingName, m.radioSetting.content.getChild(m.radioSetting.checkedItem).id)
end sub

' JFScreen hook that gets ran as needed.
' Assumes settings were changed and they affect the device profile.
' Posts a new device profile to the server using the task thread
sub OnScreenHidden()
m.postTask.arrayData = getDeviceCapabilities()
m.postTask.apiUrl = "/Sessions/Capabilities/Full"
m.postTask.control = "RUN"
m.postTask.observeField("responseCode", "postFinished")
end sub

' Triggered by m.postTask after completing a post.
' Empty the task data when finished.
sub postFinished()
m.postTask.unobserveField("responseCode")
m.postTask.callFunc("empty")
end sub

' Returns true if any of the data entry forms are in focus
function isFormInFocus() as boolean
if isValid(m.settingDetail.focusedChild) or m.radioSetting.hasFocus() or m.boolSetting.hasFocus() or m.integerSetting.hasFocus()
Expand Down
2 changes: 1 addition & 1 deletion components/settings/settings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<component name="Settings" extends="JFGroup">
<component name="Settings" extends="JFScreen">
<children>

<Label id="path" translation="[95,175]" font="font:SmallestBoldSystemFont" />
Expand Down
79 changes: 79 additions & 0 deletions components/tasks/PostTask.bs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import "pkg:/source/api/baserequest.brs"
import "pkg:/source/utils/misc.brs"

sub init()
m.top.functionName = "postItems"
end sub

' Main function for PostTask.
' Posts either an array of data
' or a string of data to an API endpoint.
' Saves the response information
sub postItems()
if m.top.apiUrl = ""
print "ERROR in PostTask. Invalid API URL provided"
return
end if
if m.top.arrayData.count() > 0 and m.top.stringData = ""
print "PostTask Started - Posting array to " + m.top.apiUrl
req = APIRequest(m.top.apiUrl)
req.SetRequest("POST")
httpResponse = asyncPost(req, FormatJson(m.top.arrayData))
m.top.responseCode = httpResponse
print "PostTask Finished. " + m.top.apiUrl + " Response = " + httpResponse.toStr()
else if m.top.arrayData.count() = 0 and m.top.stringData <> ""
print "PostTask Started - Posting string(" + m.top.stringData + ") to " + m.top.apiUrl
req = APIRequest(m.top.apiUrl)
req.SetRequest("POST")
httpResponse = asyncPost(req, m.top.stringData)
m.top.responseCode = httpResponse
print "PostTask Finished. " + m.top.apiUrl + " Response = " + httpResponse.toStr()
else
print "ERROR processing data for PostTask"
end if
end sub

' Post data and wait for response code
function asyncPost(req, data = "" as string) as integer
' response code 0 means there was an error
respCode = 0

req.setMessagePort(CreateObject("roMessagePort"))
req.AddHeader("Content-Type", "application/json")
req.AsyncPostFromString(data)
' wait up to m.top.timeoutSeconds for a response
' NOTE: wait() uses milliseconds - multiply by 1000 to convert
resp = wait(m.top.timeoutSeconds * 1000, req.GetMessagePort())

respString = resp.GetString()
if isValidAndNotEmpty(respString)
m.top.responseBody = ParseJson(respString)
print "m.top.responseBody=", m.top.responseBody
end if

respCode = resp.GetResponseCode()
if respCode < 0
' there was an unexpected error
m.top.failureReason = resp.GetFailureReason()
else if respCode >= 200 and respCode < 300
' save response headers if they're available
m.top.responseHeaders = resp.GetResponseHeaders()
end if

return respCode
end function

' Revert PostTask to default state
sub empty()
' These should match the defaults set in PostTask.xml
m.top.apiUrl = ""
m.top.timeoutSeconds = 30

m.top.arrayData = {}
m.top.stringData = ""

m.top.responseCode = invalid
m.top.responseBody = {}
m.top.responseHeaders = {}
m.top.failureReason = ""
end sub
18 changes: 18 additions & 0 deletions components/tasks/PostTask.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>

<component name="PostTask" extends="Task">
<interface>
<field id="apiUrl" type="string" />
<field id="timeoutSeconds" type="integer" value="30" />

<field id="arrayData" type="assocarray" value="{}" />
<field id="stringData" type="string" value="" />

<field id="responseCode" type="integer" />
<field id="responseBody" type="assocarray" value="{}" />
<field id="responseHeaders" type="assocarray" value="{}" />
<field id="failureReason" type="string" value="" />

<function name="empty" />
</interface>
</component>
Loading

0 comments on commit a592bd8

Please sign in to comment.