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 += '';
// 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 += '';
+ }
+
+ $('.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;