import "pkg:/source/utils/misc.bs" sub init() m.EPGLaunchCompleteSignaled = false m.scheduleGrid = m.top.findNode("scheduleGrid") m.detailsPane = m.top.findNode("detailsPane") m.detailsPane.observeField("watchSelectedChannel", "onWatchChannelSelected") m.detailsPane.observeField("recordSelectedChannel", "onRecordChannelSelected") m.detailsPane.observeField("recordSeriesSelectedChannel", "onRecordSeriesChannelSelected") m.gridStartDate = CreateObject("roDateTime") m.scheduleGrid.contentStartTime = m.gridStartDate.AsSeconds() - 1800 m.gridEndDate = createObject("roDateTime") m.gridEndDate.FromSeconds(m.gridStartDate.AsSeconds() + (24 * 60 * 60)) m.scheduleGrid.observeField("programFocused", "onProgramFocused") m.scheduleGrid.observeField("programSelected", "onProgramSelected") m.scheduleGrid.observeField("leftEdgeTargetTime", "onGridScrolled") m.scheduleGrid.channelInfoWidth = 350 m.gridMoveAnimation = m.top.findNode("gridMoveAnimation") m.gridMoveAnimationPosition = m.top.findNode("gridMoveAnimationPosition") m.LoadChannelsTask = createObject("roSGNode", "LoadChannelsTask") m.LoadChannelsTask.observeField("channels", "onChannelsLoaded") m.LoadChannelsTask.control = "RUN" m.top.lastFocus = m.scheduleGrid m.channelIndex = {} end sub sub channelFilterSet() m.scheduleGrid.jumpToChannel = 0 if m.top.filter <> invalid and m.LoadChannelsTask.filter <> m.top.filter if m.LoadChannelsTask.state = "run" then m.LoadChannelsTask.control = "stop" m.LoadChannelsTask.filter = m.top.filter m.LoadChannelsTask.control = "RUN" end if end sub 'Voice Search set sub channelsearchTermSet() m.scheduleGrid.jumpToChannel = 0 'Reset filter if user says all if LCase(m.top.searchTerm) = LCase(tr("all")) or m.LoadChannelsTask.searchTerm = LCase(tr("all")) m.top.searchTerm = " " m.LoadChannelsTask.searchTerm = " " startLoadingSpinner() m.LoadChannelsTask.control = "RUN" 'filter if the searterm is not invalid else if m.top.searchTerm <> invalid and LCase(m.LoadChannelsTask.searchTerm) <> LCase(m.top.searchTerm) if m.LoadChannelsTask.state = "run" then m.LoadChannelsTask.control = "stop" m.LoadChannelsTask.searchTerm = m.top.searchTerm startLoadingSpinner() m.LoadChannelsTask.control = "RUN" end if end sub ' Initial list of channels loaded sub onChannelsLoaded() gridData = createObject("roSGNode", "ContentNode") counter = 0 channelIdList = "" 'if search returns channels if m.LoadChannelsTask.channels.count() > 0 for each item in m.LoadChannelsTask.channels gridData.appendChild(item) m.channelIndex[item.Id] = counter counter = counter + 1 channelIdList = channelIdList + item.Id + "," end for m.scheduleGrid.content = gridData m.LoadScheduleTask = createObject("roSGNode", "LoadScheduleTask") m.LoadScheduleTask.observeField("schedule", "onScheduleLoaded") m.LoadScheduleTask.startTime = m.gridStartDate.ToISOString() m.LoadScheduleTask.endTime = m.gridEndDate.ToISOString() m.LoadScheduleTask.channelIds = channelIdList m.LoadScheduleTask.control = "RUN" m.LoadProgramDetailsTask = createObject("roSGNode", "LoadProgramDetailsTask") m.LoadProgramDetailsTask.observeField("programDetails", "onProgramDetailsLoaded") m.scheduleGrid.setFocus(true) if m.EPGLaunchCompleteSignaled = false m.top.signalBeacon("EPGLaunchComplete") ' Required Roku Performance monitoring m.EPGLaunchCompleteSignaled = true end if m.LoadChannelsTask.channels = [] end if end sub ' When LoadScheduleTask completes (initial or more data) and we have a schedule to display sub onScheduleLoaded() ' make sure we actually have a schedule (i.e. filter by favorites, but no channels have been favorited) if m.scheduleGrid.content.GetChildCount() <= 0 return end if for each item in m.LoadScheduleTask.schedule channel = m.scheduleGrid.content.GetChild(m.channelIndex[item.ChannelId]) if channel.PosterUrl <> "" item.channelLogoUri = channel.PosterUrl end if if channel.Title <> "" item.channelName = channel.Title end if channel.appendChild(item) end for m.scheduleGrid.showLoadingDataFeedback = false m.scheduleGrid.setFocus(true) m.LoadScheduleTask.schedule = [] stopLoadingSpinner() end sub sub onProgramFocused() m.top.watchChannel = invalid ' Make sure we have channels (i.e. filter set to favorite yet there are none) if m.scheduleGrid.content.getChildCount() <= 0 channel = invalid else channel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) end if m.detailsPane.channel = channel m.top.focusedChannel = channel ' Exit if Channels not yet loaded if channel = invalid or channel.getChildCount() = 0 m.detailsPane.programDetails = invalid return end if prog = channel.GetChild(m.scheduleGrid.programFocusedDetails.focusIndex) if prog <> invalid and prog.fullyLoaded = false m.LoadProgramDetailsTask.programId = prog.Id m.LoadProgramDetailsTask.channelIndex = m.scheduleGrid.programFocusedDetails.focusChannelIndex m.LoadProgramDetailsTask.programIndex = m.scheduleGrid.programFocusedDetails.focusIndex m.LoadProgramDetailsTask.control = "RUN" end if m.detailsPane.programDetails = prog end sub ' Update the Program Details with full information sub onProgramDetailsLoaded() if m.LoadProgramDetailsTask.programDetails = invalid then return channel = m.scheduleGrid.content.GetChild(m.LoadProgramDetailsTask.programDetails.channelIndex) ' If TV Show does not have its own image, use the channel logo if m.LoadProgramDetailsTask.programDetails.PosterUrl = invalid or m.LoadProgramDetailsTask.programDetails.PosterUrl = "" m.LoadProgramDetailsTask.programDetails.PosterUrl = channel.PosterUrl end if channel.ReplaceChild(m.LoadProgramDetailsTask.programDetails, m.LoadProgramDetailsTask.programDetails.programIndex) m.LoadProgramDetailsTask.programDetails = invalid m.scheduleGrid.showLoadingDataFeedback = false end sub sub onProgramSelected() ' If there is no program data - view the channel if m.detailsPane.programDetails = invalid m.top.watchChannel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) return end if ' Move Grid Down focusProgramDetails(true) end sub ' Move the TV Guide Grid down or up depending whether details are selected sub focusProgramDetails(setFocused) h = m.detailsPane.height if h < 400 then h = 400 h = h + 160 + 80 if setFocused = true m.gridMoveAnimationPosition.keyValue = [[0, 600], [0, h]] m.detailsPane.setFocus(true) m.detailsPane.hasFocus = true m.top.lastFocus = m.detailsPane else m.detailsPane.hasFocus = false m.gridMoveAnimationPosition.keyValue = [[0, h], [0, 600]] m.scheduleGrid.setFocus(true) m.top.lastFocus = m.scheduleGrid end if m.gridMoveAnimation.control = "start" end sub ' Handle user selecting "Watch Channel" from Program Details sub onWatchChannelSelected() if m.detailsPane.watchSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.top.watchChannel = m.detailsPane.channel end sub ' As user scrolls grid, check if more data requries to be loaded sub onGridScrolled() ' If we're within 12 hours of end of grid, load next 24hrs of data if m.scheduleGrid.leftEdgeTargetTime + (12 * 60 * 60) > m.gridEndDate.AsSeconds() ' Ensure the task is not already (still) running, if m.LoadScheduleTask.state <> "run" m.LoadScheduleTask.startTime = m.gridEndDate.ToISOString() m.gridEndDate.FromSeconds(m.gridEndDate.AsSeconds() + (24 * 60 * 60)) m.LoadScheduleTask.endTime = m.gridEndDate.ToISOString() m.LoadScheduleTask.control = "RUN" end if end if end sub ' Handle user selecting "Record Channel" from Program Details sub onRecordChannelSelected() if m.detailsPane.recordSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.scheduleGrid.showLoadingDataFeedback = true m.RecordProgramTask = createObject("roSGNode", "RecordProgramTask") m.RecordProgramTask.programDetails = m.detailsPane.programDetails m.RecordProgramTask.recordSeries = false m.RecordProgramTask.observeField("recordOperationDone", "onRecordOperationDone") m.RecordProgramTask.control = "RUN" end sub ' Handle user selecting "Record Series" from Program Details sub onRecordSeriesChannelSelected() if m.detailsPane.recordSeriesSelectedChannel = false then return ' Set focus back to grid before showing channel, to ensure grid has focus when we return focusProgramDetails(false) m.scheduleGrid.showLoadingDataFeedback = true m.RecordProgramTask = createObject("roSGNode", "RecordProgramTask") m.RecordProgramTask.programDetails = m.detailsPane.programDetails m.RecordProgramTask.recordSeries = true m.RecordProgramTask.observeField("recordOperationDone", "onRecordOperationDone") m.RecordProgramTask.control = "RUN" end sub sub onRecordOperationDone() if m.RecordProgramTask.recordSeries = true and m.LoadScheduleTask.state <> "run" m.LoadScheduleTask.control = "RUN" else ' This reloads just the details for the currently selected program, so that we don't have to ' reload the entire grid... channel = m.scheduleGrid.content.GetChild(m.scheduleGrid.programFocusedDetails.focusChannelIndex) prog = channel.GetChild(m.scheduleGrid.programFocusedDetails.focusIndex) m.LoadProgramDetailsTask.programId = prog.Id m.LoadProgramDetailsTask.channelIndex = m.scheduleGrid.programFocusedDetails.focusChannelIndex m.LoadProgramDetailsTask.programIndex = m.scheduleGrid.programFocusedDetails.focusIndex m.LoadProgramDetailsTask.control = "RUN" end if end sub function onKeyEvent(key as string, press as boolean) as boolean if not press then return false detailsGrp = m.top.findNode("detailsPane") gridGrp = m.top.findNode("scheduleGrid") if key = "back" and detailsGrp.isInFocusChain() focusProgramDetails(false) detailsGrp.setFocus(false) gridGrp.setFocus(true) return true else if key = "back" m.LoadChannelsTask.control = "stop" m.global.sceneManager.callFunc("popScene") return true end if return false end function