diff --git a/dashboard-ui/css/librarybrowser.css b/dashboard-ui/css/librarybrowser.css index 6c33a4463d..dbbcddde7a 100644 --- a/dashboard-ui/css/librarybrowser.css +++ b/dashboard-ui/css/librarybrowser.css @@ -474,12 +474,11 @@ a.itemTag:hover { .libraryPage ::-webkit-scrollbar-track-piece { background-color: #3b3b3b; - -webkit-border-radius: 6px; } -.libraryPage ::-webkit-scrollbar-thumb:vertical { - -webkit-border-radius: 6px; - background: #666 no-repeat center; +.libraryPage ::-webkit-scrollbar-thumb:vertical, .libraryPage ::-webkit-scrollbar-thumb:horizontal { + -webkit-border-radius: 2px; + background: #888 no-repeat center; } .detailSection { diff --git a/dashboard-ui/css/livetv.css b/dashboard-ui/css/livetv.css index 4f6757b03f..fbcbd88d37 100644 --- a/dashboard-ui/css/livetv.css +++ b/dashboard-ui/css/livetv.css @@ -61,6 +61,10 @@ color: #64A239; } +.premiereTvProgram { + color: yellow; +} + .sportsProgramInfo { background-color: #0F2624; border-bottom: 2px solid #0A7C33; @@ -124,36 +128,134 @@ margin-bottom: 1em; } +.channelTimeslotHeader { + position: absolute; + left: 0; +} + .timeslotHeaders { + position: absolute; + right: 13px; + overflow-y: hidden; + overflow-x: hidden; white-space: nowrap; } +.channelPrograms { + white-space: nowrap; + height: 47px; +} + .timeslotHeader { - width: 100px; display: inline-block; - padding: .5em .5em; - background: #38c; +} + +.timeslotHeaderInner { + padding: .5em .35em; } .timeslotCell { - width: 100px; display: inline-block; - padding: .5em .5em; - - border: 1px solid #444; + border-bottom: 1px solid #444; + border-left: 1px solid #444; border-collapse: collapse; - display: table-cell; + position: relative; } -.channelTimeslotCell { - text-align: center; +.channelHeaderCell, .channelTimeslotHeader { overflow: hidden; text-overflow: ellipsis; + border-bottom: 1px solid #444; + border-left: 1px solid #444; + border-right: 1px solid #444; + width: 139px; } -.channelTimeslotHeader, .channelTimeslotCell { - width: 80px; - color: #ddd; +.channelTimeslotHeader, .timeslotHeader { + background: #1d1d1d; + border-bottom: 1px solid #333; + border-left: 1px solid #333; + border-top: 1px solid #333; +} + +.timeslotHeader, .channelTimeslotHeader { + height: 28px; +} + +.channelHeaderCellInner { + padding: .5em .5em; +} + +.channelList { + overflow-y: hidden; + overflow-x: hidden; + position: absolute; + left: 0; + bottom: 16px; +} + +.programGrid { + position: absolute; + bottom: 0; + right: 0; + overflow-y: scroll; + overflow-x: scroll; +} + +.timeslotCell, .timeslotHeader { + width: 180px; +} + +.timeslotCellInner { + position: absolute; + bottom: 0; + overflow: hidden; + width: 100%; + top: 0; +} + +.timeslotHeaders, .programGrid { + left: 141px; +} + +.channelTimeslotHeader, .timeslotHeaders { + top: 135px; +} + +.channelList, .programGrid { + top: 165px; +} + +.channelHeaderCell, .timeslotCell { + height: 46px; +} + +.guideProgramName { + padding: .35em .5em; +} + +.guideProgramTime { + padding: 0 .5em .35em; +} + +@media (max-width: 600px) { + + .channelHeaderCell, .channelTimeslotHeader { + width: 90px; + } + + .timeslotHeaders, .programGrid { + left: 91px; + } +} +/* Account for hidden navigation */ +@media (max-width: 750px) { + + .channelTimeslotHeader, .timeslotHeaders { + top: 100px; + } + + .channelList, .programGrid { + top: 130px; + } } -.guideChannel { -} \ No newline at end of file diff --git a/dashboard-ui/css/site.css b/dashboard-ui/css/site.css index 4926350871..680ad528f7 100644 --- a/dashboard-ui/css/site.css +++ b/dashboard-ui/css/site.css @@ -44,11 +44,6 @@ body { text-decoration: underline; } -* { - text-shadow: none; - -webkit-font-smoothing: antialiased; -} - h1 { font-weight: 300; font-size: 2.22em; diff --git a/dashboard-ui/livetvguide.html b/dashboard-ui/livetvguide.html index 36596f6f69..7af4d1ee39 100644 --- a/dashboard-ui/livetvguide.html +++ b/dashboard-ui/livetvguide.html @@ -12,15 +12,26 @@ Scheduled Series -
+
-

+
+ +
-
+
+
 
+
+
+
+
+
+
diff --git a/dashboard-ui/scripts/livetvchannel.js b/dashboard-ui/scripts/livetvchannel.js index 944c167bc8..17048d86de 100644 --- a/dashboard-ui/scripts/livetvchannel.js +++ b/dashboard-ui/scripts/livetvchannel.js @@ -62,7 +62,7 @@ html += 'LIVE  '; } else if (program.IsPremiere) { - html += 'PREMIERE  '; + html += 'PREMIERE  '; } else if (program.IsSeries && !program.IsRepeat) { html += 'NEW  '; diff --git a/dashboard-ui/scripts/livetvguide.js b/dashboard-ui/scripts/livetvguide.js index 696a2b9706..ca0da5d109 100644 --- a/dashboard-ui/scripts/livetvguide.js +++ b/dashboard-ui/scripts/livetvguide.js @@ -1,5 +1,8 @@ (function ($, document, apiClient) { + // 30 mins + var cellDurationMs = 30 * 60 * 1000; + function formatDigit(i) { return i < 10 ? "0" + i : i; } @@ -29,6 +32,8 @@ date.setTime(date.getTime() - (date.getSeconds() * 1000)); + date.setHours(date.getHours(), date.getMinutes(), 0, 0); + return date; } @@ -46,14 +51,14 @@ var date = currentDate; var nextDay = new Date(date.getTime()); - nextDay.setDate(nextDay.getDate() + 1); + nextDay.setDate(nextDay.getDate() + 2); nextDay.setHours(1, 0, 0, 0); var promise1 = channelsPromise; var promise2 = apiClient.getLiveTvPrograms({ UserId: Dashboard.getCurrentUserId(), - MaxEndDate: getDateFormat(nextDay) + MaxStartDate: getDateFormat(nextDay) }); @@ -66,69 +71,216 @@ }); } - function renderDate(page, date) { - - $('.guideDate', page).html(LibraryBrowser.getFutureDateText(date)); - - $('.timeslotHeaders', page).html(getTimeslotHeadersHtml(date)); - } - function getTimeslotHeadersHtml(date) { var html = ''; - html += '
 
'; - date = new Date(date.getTime()); var dateNumber = date.getDate(); while (date.getDate() == dateNumber) { html += '
'; + html += '
'; html += LiveTvHelpers.getDisplayTime(date); html += '
'; + html += '
'; // Add 30 mins - date.setTime(date.getTime() + (30 * 60 * 1000)); + date.setTime(date.getTime() + cellDurationMs); } return html; } - function getChannelHtml(page, date, channel, programs) { + function findProgramStartingInCell(programs, startIndex, cellStart, cellEnd, cellIndex) { + + for (var i = startIndex, length = programs.length; i < length; i++) { + + var program = programs[i]; + + if (!program.StartDateLocal) { + try { + + program.StartDateLocal = parseISO8601Date(program.StartDate, { toLocal: true }); + + } catch (err) { + + } + + } + + if (!program.EndDateLocal) { + try { + + program.EndDateLocal = parseISO8601Date(program.EndDate, { toLocal: true }); + + } catch (err) { + + } + + } + + var localTime = program.StartDateLocal.getTime(); + if ((localTime >= cellStart || cellIndex == 0) && localTime < cellEnd && program.EndDateLocal > cellStart) { + + return { + + index: i, + program: program + }; + + } + } + + return null; + } + + function getChannelProgramsHtml(page, date, channel, programs) { var html = ''; - html += '
'; + var dateNumber = date.getDate(); - html += '
'; - html += channel.Name + '
' + channel.Number; - html += '
'; + programs = programs.filter(function (curr) { + return curr.ChannelId == channel.Id; + }); + html += '
'; + + var programIndex = 0; + var cellIndex = 0; + + while (date.getDate() == dateNumber) { + + // Add 30 mins + var cellEndDate = new Date(date.getTime() + cellDurationMs); + + var program = findProgramStartingInCell(programs, programIndex, date, cellEndDate, cellIndex); + + if (program) { + programIndex = program.index + 1; + program = program.program; + } + + html += '
'; + + var cssClass = "timeslotCellInner"; + + if (program) { + if (program.IsKids) { + cssClass += " childProgramInfo"; + } + else if (program.IsSports) { + cssClass += " sportsProgramInfo"; + } + else if (program.IsNews) { + cssClass += " newsProgramInfo"; + } + else if (program.IsMovie) { + cssClass += " movieProgramInfo"; + } + } + + html += '
'; + + if (program) { + + html += '
'; + html += program.Name; + html += '
'; + + html += '
'; + + if (program.IsLive) { + html += 'LIVE  '; + } + else if (program.IsPremiere) { + html += 'PREMIERE  '; + } + else if (program.IsSeries && !program.IsRepeat) { + html += 'NEW  '; + } + + html += LiveTvHelpers.getDisplayTime(program.StartDateLocal); + html += ' - '; + html += LiveTvHelpers.getDisplayTime(program.EndDateLocal); + + html += '
'; + + } else { + html += ' '; + } + + html += '
'; + html += '
'; + + date = cellEndDate; + cellIndex++; + } html += '
'; return html; } - function renderChannels(page, date, channels, programs) { + function renderPrograms(page, date, channels, programs) { var html = []; for (var i = 0, length = channels.length; i < length; i++) { - html.push(getChannelHtml(page, date, channels[i], programs)); + html.push(getChannelProgramsHtml(page, date, channels[i], programs)); } - $('#guide', page).html(html.join('')); + $('.programGrid', page).html(html.join('')); + } + + function renderChannelHeaders(page, channels) { + + var html = ''; + + for (var i = 0, length = channels.length; i < length; i++) { + + var channel = channels[i]; + + html += '
'; + + html += '
'; + html += channel.Name + '
' + channel.Number; + html += '
'; + html += '
'; + + html += '
'; + } + + $('.channelList', page).html(html); } function renderGuide(page, date, channels, programs) { - renderDate(page, date); - renderChannels(page, date, channels, programs); + renderChannelHeaders(page, channels); + $('.timeslotHeaders', page).html(getTimeslotHeadersHtml(date)); + renderPrograms(page, date, channels, programs); } - $(document).on('pagebeforeshow', "#liveTvGuidePage", function () { + function onProgramGridScroll(page, elem) { + + var grid = $(elem); + + grid.prev().scrollTop(grid.scrollTop()); + $('.timeslotHeaders', page).scrollLeft(grid.scrollLeft()); + } + + $(document).on('pageinit', "#liveTvGuidePage", function () { + + var page = this; + + $('.programGrid', page).on('scroll', function () { + + onProgramGridScroll(page, this); + }); + + }).on('pagebeforeshow', "#liveTvGuidePage", function () { var page = this;