From 6ddaf76be7efd6d97a7d05513c2aaa7e917274d3 Mon Sep 17 00:00:00 2001 From: uhensler <urs.hensler@frentix.com> Date: Mon, 3 Jun 2019 15:33:29 +0200 Subject: [PATCH] OO-4043: Peekview of live stream course node --- .../course/nodes/LiveStreamCourseNode.java | 8 + .../ui/LiveStreamPeekviewController.java | 179 ++++++++++++++++++ .../livestream/ui/_content/peekview.html | 38 ++++ .../ui/_i18n/LocalStrings_de.properties | 5 + .../ui/_i18n/LocalStrings_en.properties | 5 + 5 files changed, 235 insertions(+) create mode 100644 src/main/java/org/olat/course/nodes/livestream/ui/LiveStreamPeekviewController.java create mode 100644 src/main/java/org/olat/course/nodes/livestream/ui/_content/peekview.html diff --git a/src/main/java/org/olat/course/nodes/LiveStreamCourseNode.java b/src/main/java/org/olat/course/nodes/LiveStreamCourseNode.java index 436e7673f2c..bb478e1d798 100644 --- a/src/main/java/org/olat/course/nodes/LiveStreamCourseNode.java +++ b/src/main/java/org/olat/course/nodes/LiveStreamCourseNode.java @@ -40,6 +40,7 @@ import org.olat.course.nodes.livestream.LiveStreamModule; import org.olat.course.nodes.livestream.LiveStreamSecurityCallback; import org.olat.course.nodes.livestream.LiveStreamSecurityCallbackFactory; import org.olat.course.nodes.livestream.ui.LiveStreamEditController; +import org.olat.course.nodes.livestream.ui.LiveStreamPeekviewController; import org.olat.course.nodes.livestream.ui.LiveStreamRunController; import org.olat.course.run.navigation.NodeRunConstructionResult; import org.olat.course.run.userview.NodeEvaluation; @@ -100,6 +101,13 @@ public class LiveStreamCourseNode extends AbstractAccessableCourseNode { Controller ctrl = TitledWrapperHelper.getWrapper(ureq, wControl, runCtrl, this, "o_livestream_icon"); return new NodeRunConstructionResult(ctrl); } + + @Override + public Controller createPeekViewRunController(UserRequest ureq, WindowControl wControl, + UserCourseEnvironment userCourseEnv, NodeEvaluation ne) { + CourseCalendars calendars = CourseCalendars.createCourseCalendarsWrapper(ureq, wControl, userCourseEnv, ne); + return new LiveStreamPeekviewController(ureq, wControl, getIdent(), this.getModuleConfiguration(), calendars); + } @SuppressWarnings("deprecation") @Override diff --git a/src/main/java/org/olat/course/nodes/livestream/ui/LiveStreamPeekviewController.java b/src/main/java/org/olat/course/nodes/livestream/ui/LiveStreamPeekviewController.java new file mode 100644 index 00000000000..a0c1a90ac5d --- /dev/null +++ b/src/main/java/org/olat/course/nodes/livestream/ui/LiveStreamPeekviewController.java @@ -0,0 +1,179 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.nodes.livestream.ui; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import org.apache.commons.lang.time.DateUtils; +import org.olat.commons.calendar.CalendarUtils; +import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.htmlsite.OlatCmdEvent; +import org.olat.core.gui.components.link.Link; +import org.olat.core.gui.components.link.LinkFactory; +import org.olat.core.gui.components.velocity.VelocityContainer; +import org.olat.core.gui.control.Controller; +import org.olat.core.gui.control.Event; +import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.util.StringHelper; +import org.olat.course.nodes.LiveStreamCourseNode; +import org.olat.course.nodes.cal.CourseCalendars; +import org.olat.course.nodes.livestream.LiveStreamEvent; +import org.olat.course.nodes.livestream.LiveStreamService; +import org.olat.modules.ModuleConfiguration; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * + * Initial date: 3 Jun 2019<br> + * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com + * + */ +public class LiveStreamPeekviewController extends BasicController implements Controller { + + private final VelocityContainer mainVC; + private Link nodeLink; + + private final String nodeId; + + @Autowired + private LiveStreamService liveStreamService; + + public LiveStreamPeekviewController(UserRequest ureq, WindowControl wControl, String nodeId, + ModuleConfiguration moduleConfiguration, CourseCalendars calendars) { + super(ureq, wControl); + this.nodeId = nodeId; + + int bufferBeforeMin = moduleConfiguration.getIntegerSafe(LiveStreamCourseNode.CONFIG_BUFFER_BEFORE_MIN, 0); + int bufferAfterMin = moduleConfiguration.getIntegerSafe(LiveStreamCourseNode.CONFIG_BUFFER_AFTER_MIN, 0); + + mainVC = createVelocityContainer("peekview"); + List<? extends LiveStreamEvent> runningEvents = liveStreamService.getRunningEvents(calendars, bufferBeforeMin, bufferAfterMin); + List<EventWrapper> events; + if (!runningEvents.isEmpty()) { + events = wrapEvents(runningEvents, true); + nodeLink = LinkFactory.createLink("peekview.open.live", mainVC, this); + nodeLink.setIconRightCSS("o_icon o_icon_start"); + nodeLink.setElementCssClass("pull-right"); + } else { + List<? extends LiveStreamEvent> upcomingEvents = liveStreamService.getUpcomingEvents(calendars, bufferBeforeMin); + if (!upcomingEvents.isEmpty()) { + events = new ArrayList<>(1); + events.add(wrapEvent(upcomingEvents.get(0), false)); + nodeLink = LinkFactory.createLink("peekview.open.upcoming", mainVC, this); + nodeLink.setIconRightCSS("o_icon o_icon_start"); + nodeLink.setElementCssClass("pull-right"); + } else { + events = new ArrayList<>(0); + } + } + mainVC.contextPut("events", events); + + putInitialPanel(mainVC); + } + + private List<EventWrapper> wrapEvents(List<? extends LiveStreamEvent> events, boolean live) { + List<EventWrapper> wrappedEvents = new ArrayList<>(events.size()); + for (LiveStreamEvent event : events) { + wrappedEvents.add(wrapEvent(event, live)); + } + return wrappedEvents; + } + + private EventWrapper wrapEvent(LiveStreamEvent event, boolean live) { + String titleI18n = live? "peekview.title.live": "peekview.title.upcoming"; + String title = translate(titleI18n, new String[] {event.getSubject()}); + + Locale locale = getLocale(); + Calendar cal = CalendarUtils.createCalendarInstance(locale); + Date begin = event.getBegin(); + Date end = event.getEnd(); + cal.setTime(begin); + StringBuilder dateSb = new StringBuilder(); + dateSb.append(StringHelper.formatLocaleDateFull(begin.getTime(), locale)); + String date = dateSb.toString(); + + String time = null; + if (!event.isAllDayEvent()) { + StringBuilder timeSb = new StringBuilder(); + timeSb.append(StringHelper.formatLocaleTime(begin.getTime(), locale)); + timeSb.append(" - "); + if (!DateUtils.isSameDay(begin, end)) { + timeSb.append(StringHelper.formatLocaleDateFull(end.getTime(), locale)).append(", "); + } + timeSb.append(StringHelper.formatLocaleTime(end.getTime(), locale)); + time = timeSb.toString(); + } + + String location = event.getLocation(); + + return new EventWrapper(title, date, time, location); + } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if (source == nodeLink) { + fireEvent(ureq, new OlatCmdEvent(OlatCmdEvent.GOTONODE_CMD, nodeId)); + } + } + + @Override + protected void doDispose() { + // + } + + public final static class EventWrapper { + + private final String title; + private final String date; + private final String time; + private final String location; + + private EventWrapper(String title, String date, String time, String location) { + this.title = title; + this.date = date; + this.time = time; + this.location = location; + } + + public String getTitle() { + return title; + } + + public String getDate() { + return date; + } + + public String getTime() { + return time; + } + + public String getLocation() { + return location; + } + + } + +} diff --git a/src/main/java/org/olat/course/nodes/livestream/ui/_content/peekview.html b/src/main/java/org/olat/course/nodes/livestream/ui/_content/peekview.html new file mode 100644 index 00000000000..47ca8de4a90 --- /dev/null +++ b/src/main/java/org/olat/course/nodes/livestream/ui/_content/peekview.html @@ -0,0 +1,38 @@ +<div class="o_livestream_peekview clearfix"> + #if($events.isEmpty()) + <div class="o_instruction"> + $r.translate("peekview.no.streams") + </div> + </div> + #else + #foreach($event in $events) + <div class="o_livestream_peekview_event"> + #if($event.getTitle()) + <h5>$event.getTitle()</h5> + #end + <div class="o_cal_date text-muted"> + <i class="o_icon o_icon-fw o_icon_calendar"> </i> + $event.getDate() + </div> + #if($event.getTime() && $event.getTime() != "") + <div class="o_cal_time text-muted"> + <i class="o_icon o_icon-fw o_icon_time"> </i> + $event.getTime() + </div> + #end + #if($event.getLocation() && $event.getLocation() != "") + <div class="o_cal_location text-muted"> + <i class="o_icon o_icon-fw o_icon_home" title="$r.translateInAttribute("cal.form.location")"> </i> + $r.escapeHtml($event.getLocation()) + </div> + #end + </div> + #end + #if($r.available("peekview.open.live")) + $r.render("peekview.open.live") + #end + #if($r.available("peekview.open.upcoming")) + $r.render("peekview.open.upcoming") + #end + #end +</div> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_de.properties index 5401196541f..412ca080337 100644 --- a/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_de.properties @@ -7,6 +7,11 @@ link.text=Video Livestream list.title=Anstehende Livestreams pane.tab.accessibility=Zugang pane.tab.config=Konfiguration +peekview.no.streams=Es sind keine Livestreams geplant. +peekview.open.live=Livestream anzeigen +peekview.open.upcoming=Alle anzeigen +peekview.title.live=Jetzt live: {0} +peekview.title.upcoming=Demn\u00E4chst: {0} run.edit.events=Termine bearbeiten run.streams=Live Streams table.empty=Es sind keine Livestreams anstehend. diff --git a/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_en.properties index 8a75569a9dd..c40834169c0 100644 --- a/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/livestream/ui/_i18n/LocalStrings_en.properties @@ -7,6 +7,11 @@ link.text=Video live stream list.title=Upcoming live streams pane.tab.accessibility=Access pane.tab.config=Configuration +peekview.no.streams=No live streams are planned. +peekview.open.live=Show live stream +peekview.open.upcoming=Show all +peekview.title.live=Live: {0} +peekview.title.upcoming=Upcoming: {0} run.edit.events=Edit events run.streams=Livestreams table.empty=No upcoming live streams are available. -- GitLab