bug6105: showing take-down request button also for in-race YouTube video

This commit is contained in:
Axel Uhl
2025-05-07 18:40:52 +02:00
parent 4b0614a5bc
commit 3bb6d6c8b7
10 changed files with 66 additions and 140 deletions
@@ -30,22 +30,18 @@ public class FloatingMediaPlayerContainer extends AbstractMediaContainer impleme
private final WindowBox dialogBox;
private final MediaSynchControl mediaSynchControl;
private final PopupPositionProvider popupPositionProvider;
private Anchor edit;
private final Anchor edit;
public FloatingMediaPlayerContainer(MediaSynchPlayer mediaPlayer, PopupPositionProvider popupPositionProvider,
UserService userservice, MediaServiceWriteAsync mediaServiceWrite, ErrorReporter errorReporter,
UserService userService, MediaServiceWriteAsync mediaServiceWrite, ErrorReporter errorReporter,
PlayerCloseListener playerCloseListener, PopoutListener popoutListener) {
super(new FlowPanel(), mediaPlayer, popoutListener, playerCloseListener);
this.popupPositionProvider = popupPositionProvider;
rootPanel.addStyleName("video-root-panel");
rootPanel.add(mediaPlayer.asWidget());
this.edit = new Anchor();
this.edit.getElement().getStyle().setBackgroundImage("url('" + res.editIcon().getSafeUri().asString() + "')");
EditButtonProxy proxy = new EditButtonProxy() {
@Override
public void setTitle(String string) {
edit.setTitle(string);
@@ -66,15 +62,12 @@ public class FloatingMediaPlayerContainer extends AbstractMediaContainer impleme
edit.getElement().getStyle().setDisplay(b ? Display.BLOCK : Display.NONE);
}
};
mediaSynchControl = new MediaSynchControl(this.mediaPlayer, mediaServiceWrite, errorReporter, proxy, userservice);
mediaSynchControl = new MediaSynchControl(this.mediaPlayer, mediaServiceWrite, errorReporter, proxy, userService);
mediaSynchControl.widget().addStyleName("media-synch-control");
rootPanel.add(mediaSynchControl.widget());
mediaPlayer.setEditFlag(mediaSynchControl);
this.dialogBox = new WindowBox(mediaPlayer.getMediaTrack().title, mediaPlayer.getMediaTrack().toString(),
rootPanel, new WindowBox.PopoutHandler() {
@Override
public void popout() {
FloatingMediaPlayerContainer.this.popoutListener
@@ -87,30 +80,25 @@ public class FloatingMediaPlayerContainer extends AbstractMediaContainer impleme
dialogBox.addBeforeBarButtons(edit);
}
dialogBox.addCloseHandler(new CloseHandler<PopupPanel>() {
@Override
public void onClose(CloseEvent<PopupPanel> event) {
FloatingMediaPlayerContainer.this.mediaPlayer.pauseMedia();
FloatingMediaPlayerContainer.this.popupCloseListener.playerClosed();
}
});
show();
// hook into the click events but relay them also
// Event.sinkEvents(dialogBox.getElement(), Event.ONCLICK);
EventListener originalListener = Event.getEventListener(dialogBox.getElement());
Event.setEventListener(dialogBox.getElement(), new EventListener() {
@Override
public void onBrowserEvent(Event event) {
if(event.getTypeInt() == Event.ONMOUSEDOWN || event.getTypeInt() == Event.ONTOUCHSTART) {
if (event.getTypeInt() == Event.ONMOUSEDOWN || event.getTypeInt() == Event.ONTOUCHSTART) {
moveToTop();
}
originalListener.onBrowserEvent(event);
}
});
moveToTop();
}
@@ -133,7 +121,6 @@ public class FloatingMediaPlayerContainer extends AbstractMediaContainer impleme
void show() {
dialogBox.show();
dialogBox.setVisible(false);
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
@Override
public void execute() {
@@ -144,12 +131,10 @@ public class FloatingMediaPlayerContainer extends AbstractMediaContainer impleme
dialogBox.setVisible(true);
}
});
}
@Override
void hide() {
dialogBox.hide();
}
}
@@ -48,10 +48,6 @@ public interface MediaPlayerManager {
void closeFloatingPlayer(MediaTrackWithSecurityDTO videoTrack);
void playDockedVideo(MediaTrackWithSecurityDTO videoTrack);
void closeDockedVideo();
void addMediaTrack();
boolean deleteMediaTrack(MediaTrackWithSecurityDTO mediaTrack);
@@ -78,8 +74,6 @@ public interface MediaPlayerManager {
List<MediaTrack> getVideoTracks();
MediaTrack getDockedVideoTrack();
UserAgentDetails getUserAgent();
RegattaAndRaceIdentifier getCurrentRace();
@@ -91,6 +85,5 @@ public interface MediaPlayerManager {
ErrorReporter getErrorReporter();
Status getMediaTrackStatus(MediaTrack track);
}
@@ -77,7 +77,6 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
private final SimplePanel rootPanel = new SimplePanel();
private final UserService userService;
private MediaPlayer dockedVideoPlayer;
private final Map<MediaTrack, MediaPlayerContainer> activePlayerContainers = new HashMap<MediaTrack, MediaPlayerContainer>();
private Collection<MediaTrackWithSecurityDTO> assignedMediaTracks = new ArrayList<>();
private Collection<MediaTrackWithSecurityDTO> overlappingMediaTracks = new ArrayList<>();
@@ -339,36 +338,6 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
}
}
@Override
public void playDockedVideo(MediaTrackWithSecurityDTO videoTrack) {
if ((dockedVideoPlayer == null) || (dockedVideoPlayer.getMediaTrack() != videoTrack)) {
closeDockedVideo();
closeFloatingPlayer(videoTrack);
MediaPlayerContainer videoDockedContainer = createAndWrapVideoPlayer(videoTrack,
new VideoContainerFactory<VideoDockedContainer>() {
@Override
public VideoDockedContainer createVideoContainer(MediaSynchPlayer videoPlayer,
UserService userService, MediaServiceWriteAsync mediaServiceWrite, ErrorReporter errorReporter,
PlayerCloseListener playerCloseListener, PopoutListener popoutListener) {
VideoDockedContainer videoDockedContainer = new VideoDockedContainer(rootPanel,
videoPlayer, playerCloseListener, popoutListener);
return videoDockedContainer;
}
});
registerVideoContainer(videoTrack, videoDockedContainer);
notifyStateChange();
}
}
@Override
public void closeDockedVideo() {
if (dockedVideoPlayer != null) {
dockedVideoPlayer.shutDown();
dockedVideoPlayer = null;
notifyStateChange();
}
}
@Override
public void playAudio(MediaTrackWithSecurityDTO audioTrack) {
muteAudio();
@@ -391,23 +360,19 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
@Override
public void playFloatingVideo(final MediaTrackWithSecurityDTO videoTrack) {
if (dockedVideoPlayer != null && dockedVideoPlayer.getMediaTrack() == videoTrack) {
closeDockedVideo();
}
MediaPlayerContainer activeVideoContainer = activePlayerContainers.get(videoTrack);
if (activeVideoContainer == null) {
FloatingMediaPlayerContainer videoFloatingContainer = createAndWrapVideoPlayer(videoTrack,
new VideoContainerFactory<FloatingMediaPlayerContainer>() {
@Override
public FloatingMediaPlayerContainer createVideoContainer(MediaSynchPlayer videoPlayer,
UserService userservice, MediaServiceWriteAsync mediaServiceWrite, ErrorReporter errorReporter,
UserService userService, MediaServiceWriteAsync mediaServiceWrite, ErrorReporter errorReporter,
PlayerCloseListener playerCloseListener, PopoutListener popoutListener) {
FloatingMediaPlayerContainer videoFloatingContainer = new FloatingMediaPlayerContainer(videoPlayer, popupPositionProvider,
userservice, mediaServiceWrite, errorReporter, playerCloseListener, popoutListener);
userService, mediaServiceWrite, errorReporter, playerCloseListener, popoutListener);
return videoFloatingContainer;
}
});
registerVideoContainer(videoTrack, videoFloatingContainer);
notifyStateChange();
}
@@ -438,7 +403,7 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
public void popoutVideo(MediaTrackWithSecurityDTO videoTrack) {
MediaPlayerContainer videoContainer;
if (videoTrack.isYoutube()) {
videoContainer = new YoutubeWindowPlayer(videoTrack, playerCloseListener);
videoContainer = new YoutubeWindowPlayer(videoTrack, playerCloseListener); // TODO bug6105 make YouTube player show take-down request button
} else {
videoContainer = new VideoJSWindowPlayer(videoTrack, playerCloseListener, leaderboardGroupName, eventId);
}
@@ -448,11 +413,10 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
};
final MediaSynchPlayer videoPlayer;
if (videoTrack.isYoutube()) {
videoPlayer = new VideoYoutubePlayer(videoTrack, getRaceStartTime(), raceTimer);
videoPlayer = new VideoYoutubePlayer(videoTrack, getRaceStartTime(), raceTimer, userService, raceIdentifier);
} else {
videoPlayer = new VideoJSSyncPlayer(videoTrack, getRaceStartTime(), raceTimer, userService, leaderboardGroupName, eventId);
}
return videoContainerFactory.createVideoContainer(videoPlayer, userService, getMediaServiceWrite(), errorReporter,
playerCloseListener, popoutListener);
}
@@ -645,11 +609,6 @@ public class MediaPlayerManagerComponent extends AbstractComponent<MediaPlayerSe
}
@Override
public MediaTrack getDockedVideoTrack() {
return dockedVideoPlayer != null ? dockedVideoPlayer.getMediaTrack() : null;
}
@Override
public Set<MediaTrack> getPlayingVideoTracks() {
return activePlayerContainers.keySet();
@@ -1,23 +0,0 @@
package com.sap.sailing.gwt.ui.client.media;
import com.google.gwt.user.client.ui.Panel;
import com.sap.sailing.gwt.ui.client.media.popup.PopoutWindowPlayer.PlayerCloseListener;
import com.sap.sailing.gwt.ui.client.media.shared.MediaSynchPlayer;
public class VideoDockedContainer extends AbstractMediaContainer implements MediaPlayerContainer {
public VideoDockedContainer(Panel rootPanel, MediaSynchPlayer videoPlayer, PlayerCloseListener playerCloseListener, PopoutListener popoutListener) {
super(rootPanel, videoPlayer, popoutListener, playerCloseListener);
}
@Override
void show() {
rootPanel.setVisible(true);
}
@Override
void hide() {
rootPanel.setVisible(true);
}
}
@@ -5,16 +5,21 @@ import java.util.List;
import com.google.gwt.event.logical.shared.AttachEvent;
import com.google.gwt.event.logical.shared.AttachEvent.Handler;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.IsWidget;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
import com.sap.sailing.domain.common.media.MediaTrackWithSecurityDTO;
import com.sap.sailing.gwt.ui.client.media.shared.AbstractMediaPlayer;
import com.sap.sailing.gwt.ui.client.media.shared.MediaSynchPlayer;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.media.MediaMenuIcon;
import com.sap.sse.gwt.client.media.TakedownNoticeService;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.common.CommonSharedResources;
public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSynchPlayer, MediaSynchAdapter, IsWidget {
@@ -22,6 +27,11 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
void execute();
}
/**
* Contains the {@link #takedownButton} and the actual {@link #videoContainer} and is what {@link #asWidget()} returns
*/
private final Panel mediaWrapper;
private final Panel videoContainer;
private static int videoCounter;
@@ -33,6 +43,8 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
private EditFlag editFlag;
private YoutubeVideoControl videoControl;
private final MediaMenuIcon takedownButton;
/**
* Required to indicate whether this control has been requested to close. In this case it must not call any player
@@ -43,12 +55,20 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
private final List<DeferredAction> deferredActions = new ArrayList<DeferredAction>();
public VideoYoutubePlayer(final MediaTrackWithSecurityDTO videoTrack, TimePoint raceStartTime, Timer raceTimer) {
public VideoYoutubePlayer(final MediaTrackWithSecurityDTO videoTrack, TimePoint raceStartTime, Timer raceTimer,
TakedownNoticeService takedownNoticeService, RegattaAndRaceIdentifier raceIdentifier) {
super(videoTrack);
this.raceTimer = raceTimer;
this.raceStartTime = raceStartTime;
this.mediaWrapper = new FlowPanel();
mediaWrapper.addStyleName(CommonSharedResources.INSTANCE.mainCss().media_wrapper());
mediaWrapper.setHeight("100%");
mediaWrapper.setWidth("100%");
takedownButton = new MediaMenuIcon(takedownNoticeService, "takedownRequestForRaceVideo");
takedownButton.setData(raceIdentifier.toString(), videoTrack.url);
this.videoContainer = new SimplePanel();
mediaWrapper.add(videoContainer);
mediaWrapper.add(takedownButton);
this.videoContainer.setStyleName("Youtube-Video-Panel");
final String videoContainerId = "videoContainer-" + videoTrack.url + ++videoCounter;
this.videoContainer.getElement().setId(videoContainerId);
@@ -57,7 +77,6 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
.setInnerText(
"When the Youtube video doesn't show up, click the popout button at the upper right corner to open the video in a dedicated browser window.");
this.videoContainer.addAttachHandler(new Handler() {
@Override
public void onAttachOrDetach(AttachEvent event) {
// The videoContainer must be attached to the DOM before the Youtube player can be created.
@@ -72,7 +91,6 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
}
}
});
}
private void defer(DeferredAction deferredAction) {
@@ -246,7 +264,7 @@ public class VideoYoutubePlayer extends AbstractMediaPlayer implements MediaSync
@Override
public Widget asWidget() {
return videoContainer;
return mediaWrapper;
}
@Override
@@ -17,7 +17,6 @@ public class YoutubeVideoControl {
private double deferredPlaybackSpeed;
YoutubeVideoControl(String videoUrl, String videoContainerId) {
if (!isYoutubeApiInitialized()) {
loadInitialYoutubePlayer(videoUrl, videoContainerId);
} else {
@@ -38,28 +37,22 @@ public class YoutubeVideoControl {
// Code Playground: https://code.google.com/apis/ajax/playground/?exp=youtube#chromeless_player
// Extended with API-initialization control to support multiple players on the same page.
private native void loadInitialYoutubePlayer(String videoUrl, String videoContainerId) /*-{
var that = this;
// This function creates an <iframe> containing a YouTube player after the API code downloads.
var player;
$wnd.onYouTubeIframeAPIReady = function() {
that.@com.sap.sailing.gwt.ui.client.media.YoutubeVideoControl::setYoutubeApiInitialized()();
that.@com.sap.sailing.gwt.ui.client.media.YoutubeVideoControl::loadYoutubePlayer(Ljava/lang/String;Ljava/lang/String;)(videoUrl, videoContainerId);
}
// Use script tag trick to cope with browser's cross domain restrictions
var tag = $doc.createElement('script');
tag.src = "//www.youtube.com/iframe_api"; // This is a protocol-relative URL as described here: http://paulirish.com/2010/the-protocol-relative-url/
var firstScriptTag = $doc.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}-*/;
private native void loadYoutubePlayer(String videoUrl, String videoContainerId) /*-{
var that = this;
var player = new $wnd.YT.Player(videoContainerId, {
videoId : videoUrl,
//height: '480', //see https://developers.google.com/youtube/iframe_api_reference?hl=en#Playback_quality
@@ -77,7 +70,6 @@ public class YoutubeVideoControl {
modestbranding: 1
}
});
}-*/;
public void initPlayState(JavaScriptObject youtubePlayer) {
@@ -21,14 +21,11 @@ public abstract class PopoutWindowPlayer extends AbstractMediaPlayer implements
protected PopoutWindowPlayer(MediaTrackWithSecurityDTO mediaTrack, PlayerCloseListener popupCloseListener) {
super(mediaTrack);
this.popupCloseHandler = popupCloseListener;
String playerWindowUrl = getPlayerWindowUrl();
String codesvr = Window.Location.getParameter("gwt.codesvr");
if (codesvr != null) {
playerWindowUrl = playerWindowUrl + "&gwt.codesvr=" + codesvr;
}
playerWindow = openWindow(playerWindowUrl);
registerNativeStuff();
}
@@ -1,36 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.7.0//EN" "http://gwtproject.org/doctype/2.7.0/gwt-module.dtd">
<module>
<inherits name="com.google.gwt.user.User" />
<inherits name="com.google.gwt.user.User" />
<!-- Other module inherits -->
<inherits name="com.sap.sse.gwt.EmulatedJRE" />
<inherits name="com.sap.sse.gwt.SSESharedGWT" />
<inherits name="com.sap.sse.SSECommon" />
<inherits name="com.sap.sse.security.ui.LoginPanel" />
<inherits name="com.sap.sailing.domain.SailingDomain" />
<inherits name="com.sap.sse.gwt.AdminConsole" />
<inherits name="com.sap.sailing.landscape.Landscape" />
<!-- Highcharts API -->
<inherits name="com.sap.sse.gwt.Highcharts_Autoinject" />
<!-- Google Maps API -->
<inherits name='com.google.gwt.ajaxloader.AjaxLoader' />
<inherits name='com.google.gwt.maps.Maps' />
<!-- GWT JSON Support -->
<inherits name='com.google.gwt.json.JSON' />
<!-- Other module inherits -->
<inherits name="com.sap.sse.gwt.EmulatedJRE" />
<inherits name="com.sap.sse.gwt.SSESharedGWT" />
<inherits name="com.sap.sse.SSECommon" />
<inherits name="com.sap.sse.security.ui.LoginPanel" />
<inherits name="com.sap.sailing.domain.SailingDomain" />
<inherits name="com.sap.sse.gwt.AdminConsole" />
<inherits name="com.sap.sailing.gwt.ui.SourceRaceboard"/>
<inherits name="com.sap.sailing.ExpeditionConnectorCommon" />
<inherits name='com.sap.sailing.gwt.settings.Settings'/>
<inherits name="com.sap.sailing.landscape.Landscape" />
<!-- Highcharts API -->
<inherits name="com.sap.sse.gwt.Highcharts_Autoinject" />
<!-- Google Maps API -->
<inherits name='com.google.gwt.ajaxloader.AjaxLoader' />
<inherits name='com.google.gwt.maps.Maps' />
<!-- GWT JSON Support -->
<inherits name='com.google.gwt.json.JSON' />
<!-- module containing locale configuration -->
<inherits name='com.sap.sailing.gwt.common.SailingLocalesSinglePermutation' />
<!-- module containing locale configuration -->
<inherits name='com.sap.sailing.gwt.common.SailingLocalesSinglePermutation' />
<entry-point class="com.sap.sailing.gwt.ui.client.media.popup.YoutubePopupWindow" />
<entry-point class="com.sap.sailing.gwt.ui.client.media.popup.YoutubePopupWindow" />
<source path='client'/>
<source path='shared'/>
<source path='actions'/>
<source path='common'/>
<source path='simulator'/>
<source path='adminconsole'/>
<source path='usermanagement'/>
<source path='masterdataimport'/>
<source path='leaderboard'/>
<source path='client'/>
<source path='shared'/>
<source path='actions'/>
<source path='common'/>
<source path='simulator'/>
<source path='adminconsole'/>
<source path='usermanagement'/>
<source path='masterdataimport'/>
<source path='leaderboard'/>
</module>
@@ -7,4 +7,5 @@ takedownRequestForLogoImage=Logo image for {0}
takedownRequestForEventGalleryVideo=Event gallery video for {0}
takedownRequestForEventGalleryImage=Gallery image of event {0}
takedownRequestForEventTeaserImage=Teaser image of event {0}
takedownRequestForEventStageImage=Stage image of event {0}
takedownRequestForEventStageImage=Stage image of event {0}
takedownRequestForRaceVideo=Video in race {0}
@@ -7,4 +7,5 @@ takedownRequestForLogoImage=Logo-Bild für {0}
takedownRequestForEventGalleryVideo=Galerie-Video der Veranstaltung {0}
takedownRequestForEventGalleryImage=Galerie-Bild der Veranstaltung {0}
takedownRequestForEventTeaserImage=Kleines Aufmacher-Bild der Veranstaltung {0}
takedownRequestForEventStageImage=Haupt-Bild der Veranstaltung {0}
takedownRequestForEventStageImage=Haupt-Bild der Veranstaltung {0}
takedownRequestForRaceVideo=Video zu Wettfahrt {0}