components_liveTv_ProgramDetails.bs

import "pkg:/source/utils/config.bs"
import "pkg:/source/utils/misc.bs"

sub init()

  ' Max "Overview" lines to show in Preview and Detail
  m.maxPreviewLines = 5
  m.maxDetailLines = 14

  m.detailsView = m.top.findNode("detailsView")
  m.noInfoView = m.top.findNode("noInformation")

  m.programName = m.top.findNode("programName")
  m.episodeTitle = m.top.findNode("episodeTitle")
  m.episodeNumber = m.top.findNode("episodeNumber")
  m.overview = m.top.findNode("overview")

  m.episodeDetailsGroup = m.top.findNode("episodeDetailsGroup")
  m.isLiveGroup = m.top.findNode("isLive")
  m.isRepeatGroup = m.top.findNode("isRepeat")

  m.broadcastDetails = m.top.findNode("broadcastDetails")
  m.duration = m.top.findNode("duration")
  m.channelName = m.top.findNode("channelName")
  m.image = m.top.findNode("image")
  m.favorite = m.top.findNode("favorite")

  m.viewChannelFocusAnimationOpacity = m.top.findNode("viewChannelFocusAnimationOpacity")
  m.recordFocusAnimationOpacity = m.top.findNode("recordFocusAnimationOpacity")
  m.recordSeriesFocusAnimationOpacity = m.top.findNode("recordSeriesFocusAnimationOpacity")
  m.focusAnimation = m.top.findNode("focusAnimation")

  m.viewChannelButton = m.top.findNode("viewChannelButton")
  m.recordButton = m.top.findNode("recordButton")
  m.recordSeriesButton = m.top.findNode("recordSeriesButton")

  m.viewChannelOutline = m.top.findNode("viewChannelOutline")
  m.recordOutline = m.top.findNode("recordOutline")
  m.recordSeriesOutline = m.top.findNode("recordSeriesOutline")

  m.viewChannelLabel = m.top.findNode("viewChannelButtonLabel")
  m.recordLabel = m.top.findNode("recordButtonLabel")
  m.recordSeriesLabel = m.top.findNode("recordSeriesButtonLabel")

  m.viewChannelButtonBackground = m.top.findNode("viewChannelButtonBackground")
  m.recordButtonBackground = m.top.findNode("recordButtonBackground")
  m.recordSeriesButtonBackground = m.top.findNode("recordSeriesButtonBackground")

  m.focusAnimation.observeField("state", "onAnimationComplete")

  setupLabels()
end sub


' Set up Live and Repeat label sizes
sub setupLabels()

  boundingRect = m.top.findNode("isLiveText").boundingRect()
  isLiveBackground = m.top.findNode("isLiveBackground")
  isLiveBackground.width = boundingRect.width + 16
  isLiveBackground.height = boundingRect.height + 8
  m.episodeDetailsGroup.removeChildIndex(0)

  boundingRect = m.top.findNode("isRepeatText").boundingRect()
  isRepeatBackground = m.top.findNode("isRepeatBackground")
  isRepeatBackground.width = boundingRect.width + 16
  isRepeatBackground.height = boundingRect.height + 8
  m.episodeDetailsGroup.removeChildIndex(0)

  m.viewChannelLabel.text = tr("View Channel")
  boundingRect = m.viewChannelButton.boundingRect()
  viewButtonBackground = m.top.findNode("viewChannelButtonBackground")
  viewButtonBackground.width = boundingRect.width + 20
  viewButtonBackground.height = boundingRect.height + 20
  m.viewChannelOutline.width = viewButtonBackground.width
  m.viewChannelOutline.height = viewButtonBackground.height

  m.recordLabel.text = tr("Record")
  boundingRect = m.recordButton.boundingRect()
  recordButtonBackground = m.top.findNode("recordButtonBackground")
  recordButtonBackground.width = boundingRect.width + 20
  recordButtonBackground.height = boundingRect.height + 20
  m.recordOutline.width = recordButtonBackground.width
  m.recordOutline.height = recordButtonBackground.height

  m.recordSeriesLabel.text = tr("Record Series")
  boundingRect = m.recordSeriesButton.boundingRect()
  recordSeriesButtonBackground = m.top.findNode("recordSeriesButtonBackground")
  recordSeriesButtonBackground.width = boundingRect.width + 20
  recordSeriesButtonBackground.height = boundingRect.height + 20
  m.recordSeriesOutline.width = recordSeriesButtonBackground.width
  m.recordSeriesOutline.height = recordSeriesButtonBackground.height

  m.userCanRecord = m.global.session.user.settings["livetv.canrecord"]
  if m.userCanRecord = false
    m.recordButton.visible = false
    m.recordSeriesButton.visible = false
  end if
end sub

sub updateLabels(recordText = tr("Record"), recordSeriesText = tr("Record Series"))
  m.recordLabel.text = recordText
  m.recordSeriesLabel.text = recordSeriesText

  boundingRect = m.recordButton.boundingRect()
  recordButtonBackground = m.top.findNode("recordButtonBackground")
  recordButtonBackground.width = boundingRect.width
  recordButtonBackground.height = boundingRect.height
  m.recordOutline.width = recordButtonBackground.width
  m.recordOutline.height = recordButtonBackground.height

  boundingRect = m.recordSeriesButton.boundingRect()
  recordSeriesButtonBackground = m.top.findNode("recordSeriesButtonBackground")
  recordSeriesButtonBackground.width = boundingRect.width
  recordSeriesButtonBackground.height = boundingRect.height
  m.recordSeriesOutline.width = recordSeriesButtonBackground.width
  m.recordSeriesOutline.height = recordSeriesButtonBackground.height
end sub

sub channelUpdated()
  if m.top.channel = invalid
    m.top.findNode("noInfoChannelName").text = ""
    m.channelName.text = ""
  else
    m.top.findNode("noInfoChannelName").text = m.top.channel.Title
    m.channelName.text = m.top.channel.Title
    if m.top.programDetails = invalid
      m.image.uri = m.top.channel.posterURL
    end if
    m.favorite.visible = m.top.channel.favorite
  end if
end sub

sub programUpdated()

  m.top.watchSelectedChannel = false
  m.top.recordSelectedChannel = false
  m.top.recordSeriesSelectedChannel = false
  m.overview.maxLines = m.maxDetailLines
  prog = m.top.programDetails

  ' If no program selected, hide details view
  if prog = invalid
    channelUpdated()
    m.detailsView.visible = "false"
    m.noInfoView.visible = "true"
    return
  end if

  m.programName.text = prog.Title
  m.overview.text = prog.description

  m.episodeDetailsGroup.removeChildrenIndex(m.episodeDetailsGroup.getChildCount(), 0)

  if prog.isLive
    m.episodeDetailsGroup.appendChild(m.isLiveGroup)
  else if prog.isRepeat
    m.episodeDetailsGroup.appendChild(m.isRepeatGroup)
  end if

  ' Episode Number
  if prog.seasonNumber > 0 and prog.episodeNumber > 0
    m.episodeNumber.text = "S" + StrI(prog.seasonNumber).trim() + ":E" + StrI(prog.episodeNumber).trim()
    if prog.episodeTitle <> "" then m.episodeNumber.text = m.episodeNumber.text + " -" ' Add a Dash if showing Episode Number and Title
    m.episodeDetailsGroup.appendChild(m.episodeNumber)
  end if

  if prog.episodeTitle <> invalid and prog.episodeTitle <> ""
    m.episodeTitle.text = prog.episodeTitle
    m.episodeTitle.visible = true
    m.episodeDetailsGroup.appendChild(m.episodeTitle)
  end if

  m.duration.text = getDurationStringFromSeconds(prog.PlayDuration)

  ' Calculate Broadcast Details
  now = createObject("roDateTime")
  startDate = createObject("roDateTime")
  endDate = createObject("roDateTime")
  startDate.FromISO8601String(prog.StartDate)
  endDate.FromISO8601String(prog.EndDate)

  day = getRelativeDayName(startDate)

  ' Get Start Date in local timezone for display to user
  localStartDate = createObject("roDateTime")
  localStartDate.FromISO8601String(prog.StartDate)
  localStartDate.ToLocalTime()

  if startDate.AsSeconds() < now.AsSeconds() and endDate.AsSeconds() > now.AsSeconds()
    if day = "today"
      m.broadcastDetails.text = tr("Started at") + " " + formatTime(localStartDate)
    else
      m.broadcastDetails.text = tr("Started") + " " + tr(day) + ", " + formatTime(localStartDate)
    end if
  else if startDate.AsSeconds() > now.AsSeconds()
    if day = "today"
      m.broadcastDetails.text = tr("Starts at") + " " + formatTime(localStartDate)
    else
      m.broadcastDetails.text = tr("Starts") + " " + tr(day) + ", " + formatTime(localStartDate)
    end if
  else
    if day = "today"
      m.broadcastDetails.text = tr("Ended at") + " " + formatTime(localStartDate)
    else
      m.broadcastDetails.text = tr("Ended") + " " + tr(day) + ", " + formatTime(localStartDate)
    end if
  end if

  m.image.uri = prog.PosterURL

  ' If currently being recorded, change button to "Stop Recording"
  if prog.json.TimerId <> invalid
    if prog.json.SeriesTimerId <> invalid
      updateLabels(tr("Cancel Recording"), tr("Cancel Series Recording"))
    else
      updateLabels(tr("Cancel Recording"), tr("Record Series"))
    end if
  else
    updateLabels()
  end if

  ' If not a series, hide Record Series button
  if prog.json.isSeries <> true ' could be invalid or false
    m.recordSeriesButton.visible = false
  else
    m.recordSeriesButton.visible = true
  end if

  m.detailsView.visible = "true"
  m.noInfoView.visible = "false"

  m.top.height = m.detailsView.boundingRect().height
  m.overview.maxLines = m.maxPreviewLines
end sub

'
' Get relative date name for a date (yesterday, today, tomorrow, or otherwise weekday name )
function getRelativeDayName(date) as string
  now = createObject("roDateTime")
  ' needed for update-translations script to prevent strings from being removed
  ' tr("today")
  ' tr("yesterday")
  ' tr("tomorrow")
  ' tr("Monday")
  ' tr("Tuesday")
  ' tr("Wednesday")
  ' tr("Thursday")
  ' tr("Friday")
  ' tr("Saturday")
  ' tr("Sunday")

  ' Check for Today
  if now.AsDateString("short-date-dashes") = date.AsDateString("short-date-dashes")
    return "today"
  end if

  ' Check for Yesterday
  todayMidnight = now.AsSeconds() - (now.AsSeconds() mod 86400)
  dateMidnight = date.AsSeconds() - (date.AsSeconds() mod 86400)

  if todayMidnight - dateMidnight = 86400
    return "yesterday"
  end if

  if dateMidnight - todayMidnight = 86400
    return "tomorrow"
  end if

  return date.GetWeekday()

end function

'
' Get program duration string (e.g. 1h 20m)
function getDurationStringFromSeconds(seconds) as string

  hours = 0
  minutes = seconds / 60.0

  if minutes > 60
    hours = (minutes - (minutes mod 60)) / 60
    minutes = minutes mod 60
  end if

  if hours > 0
    return "%1h %2m".Replace("%1", StrI(hours).trim()).Replace("%2", StrI(minutes).trim())
  else
    return "%1m".Replace("%1", StrI(minutes).trim())
  end if

end function

'
' Show view channel button when item has Focus
sub focusChanged()
  if m.top.hasFocus = true
    m.overview.maxLines = m.maxDetailLines
    m.viewChannelFocusAnimationOpacity.keyValue = [0, 1]
    m.recordFocusAnimationOpacity.keyValue = [0, 1]
    m.recordSeriesFocusAnimationOpacity.keyValue = [0, 1]
    m.viewChannelButton.setFocus(true)
    m.viewChannelOutline.visible = true
    m.recordOutline.visible = false
    m.recordSeriesOutline.visible = false
    m.viewChannelButtonBackground.blendColor = "#006fab"
    m.recordButtonBackground.blendColor = "#000000"
    m.recordSeriesButtonBackground.blendColor = "#000000"
  else
    m.top.watchSelectedChannel = false
    m.top.recordSelectedChannel = false
    m.top.recordSeriesSelectedChannel = false
    m.viewChannelFocusAnimationOpacity.keyValue = [1, 0]
    m.recordFocusAnimationOpacity.keyValue = [1, 0]
    m.recordSeriesFocusAnimationOpacity.keyValue = [1, 0]
  end if

  m.focusAnimation.control = "start"

end sub

sub onAnimationComplete()
  if m.focusAnimation.state = "stopped" and m.top.hasFocus = false
    m.overview.maxLines = m.maxPreviewLines
  end if
end sub

function onKeyEvent(key as string, press as boolean) as boolean
  if not press then return false

  if key = "OK" and m.viewChannelButton.hasFocus()
    m.top.watchSelectedChannel = true
    return true
  else if key = "OK" and m.recordButton.hasFocus()
    m.top.recordSelectedChannel = true
    return true
  else if key = "OK" and m.recordSeriesButton.hasFocus()
    m.top.recordSeriesSelectedChannel = true
    return true
  end if

  if m.userCanRecord = true
    if key = "right" and m.viewChannelButton.hasFocus()
      m.recordButton.setFocus(true)
      m.viewChannelOutline.visible = false
      m.recordOutline.visible = true
      m.viewChannelButtonBackground.blendColor = "#000000"
      m.recordButtonBackground.blendColor = "#006fab"
      m.recordSeriesButtonBackground.blendColor = "#000000"
      return true
    else if key = "right" and m.recordButton.hasFocus()
      m.recordSeriesButton.setFocus(true)
      m.recordOutline.visible = false
      m.recordSeriesOutline.visible = true
      m.viewChannelButtonBackground.blendColor = "#000000"
      m.recordButtonBackground.blendColor = "#000000"
      m.recordSeriesButtonBackground.blendColor = "#006fab"
      return true
    else if key = "left" and m.recordSeriesButton.hasFocus()
      m.recordButton.setFocus(true)
      m.recordOutline.visible = true
      m.recordSeriesOutline.visible = false
      m.viewChannelButtonBackground.blendColor = "#000000"
      m.recordButtonBackground.blendColor = "#006fab"
      m.recordSeriesButtonBackground.blendColor = "#000000"
      return true
    else if key = "left" and m.recordButton.hasFocus()
      m.viewChannelButton.setFocus(true)
      m.viewChannelOutline.visible = true
      m.recordOutline.visible = false
      m.viewChannelButtonBackground.blendColor = "#006fab"
      m.recordButtonBackground.blendColor = "#000000"
      m.recordSeriesButtonBackground.blendColor = "#000000"
      return true
    end if
  end if

  if key = "up" or key = "down"
    return true
  end if

  return false
end function