Merge remote-tracking branch 'server/master'

This commit is contained in:
Axel Uhl committed 2016-06-23 21:49:07 +02:00
commit 531e91cc1e
87 files changed
+674 -774

No files matched your search

@@ -127,7 +127,7 @@ public class AutoPlayController implements RaceTimesInfoProviderListener, Leader
sailingService, mediaService, userService, asyncActionsExecutor,
result.getCompetitorAndTheirBoats(), raceboardTimer, currentLiveRace, autoPlayerConfiguration.getLeaderboardName(),
/** leaderboardGroupName */ null, /** eventId */ null, errorReporter,
StringMessages.INSTANCE, userAgent, raceTimesInfoProvider);
StringMessages.INSTANCE, userAgent, raceTimesInfoProvider, true);
playerView.setContent(raceboardPerspective);
@@ -7,12 +7,21 @@ import java.util.List;
import com.google.gwt.i18n.client.LocaleInfo;
import com.sap.sse.common.Util;
/**
* Utilities for working with GWT client locales.
*/
public final class GWTLocaleUtil {
private static final String NO_LOCALE_TEXT = "---";
private GWTLocaleUtil() {
}
/**
* Returns all available client locales. As GWT works with a placeholder locale "default", this ensures that only
* real locales are returned.
*
* @return all available client locales
*/
public static Iterable<String> getAvailableLocales() {
List<String> result = new ArrayList<>();
result.addAll(Arrays.asList(LocaleInfo.getAvailableLocaleNames()));
@@ -20,6 +29,12 @@ public final class GWTLocaleUtil {
return result;
}
/**
* Returns all available client locales plus a null entry. This is useful where you need to populate UI elements for
* all locales plus a fallback entry.
*
* @return all available client locales plus a null entry
*/
public static Iterable<String> getAvailableLocalesAndDefault() {
List<String> result = new ArrayList<>();
result.add(null);
@@ -27,10 +42,20 @@ public final class GWTLocaleUtil {
return result;
}
/**
* @return the count of available client locales (including a default entry)
*/
public static int getLanguageCountWithDefault() {
return Util.size(getAvailableLocalesAndDefault());
}
/**
* Renders a locale with it's name in the language itself plus the technical locale name.
* For the fallback entry (null) a placeholder is returned instead
*
* @param localeNameOrNull the locale's name or null for the fallback entry
* @return a decorated representation of the locale to be shown on the UI
*/
public static String getDecoratedLanguageDisplayNameWithDefaultLocaleSupport(String localeNameOrNull) {
if (localeNameOrNull == null || localeNameOrNull.isEmpty()) {
return NO_LOCALE_TEXT;
@@ -5,6 +5,16 @@ import java.util.logging.Logger;
import com.google.gwt.regexp.shared.RegExp;
import com.google.gwt.user.client.Window.Navigator;
/**
* Helps to detect different form factors/device categories by analyzing the browser's user agent string. Based on the
* browser itself or the name of the operating system it's easy to detect mobile OSes as iOS or Android. Distinguishing
* smartphones and tablets is a little bit more complex because you need to analyze common device ID patterns for known
* tablets of various companies as Samsung or Sony.
*
* By now, it's not possible to ask the browser about the device or even the physical size of the device or browser
* window. It's also not possible to render an element with CSS size "1cm" or "1in" and read its pixel size in order to
* calculate the real size of the screen. This is caused by the fact that at least mobile browsers always fake 96 dpi.
*/
public class DeviceDetector {
private static Logger LOG = Logger.getLogger(DeviceDetector.class.getName());
@@ -13,6 +23,7 @@ public class DeviceDetector {
private static final RegExp tabletBlacklistRegExp = RegExp.compile(
"iPad|" // Apple ;-)
+ "Nexus 7|Nexus 10|Nexus 9|" // Google Tablets
+ "Ryu|" // Google Pixel C
+ "PlayBook|" // Blackberry
+ "KFAPWI|" // Kindle Fire HD
+ "FZ-B|" // Panasonic ToughPad
@@ -1,32 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.imagegallery;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.ImageElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class Image extends Composite {
private static ImageUiBinder uiBinder = GWT.create(ImageUiBinder.class);
interface ImageUiBinder extends UiBinder<Widget, Image> {
}
private final ImageDescriptor imageDescriptor;
@UiField DivElement title;
@UiField ImageElement image;
public Image(ImageDescriptor imageDescriptor) {
this.imageDescriptor = imageDescriptor;
ImageGalleryResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
title.setInnerText(this.imageDescriptor.getTitle());
image.setSrc(this.imageDescriptor.getImageURL());
}
}
@@ -1,12 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.common.theme.component.imagegallery.ImageGalleryResources" />
<g:HTMLPanel styleName="{local_res.css.sampleCssClass}">
<div>
<img ui:field="image" />
</div>
<div ui:field='title'></div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,102 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.imagegallery;
import java.util.Date;
public class ImageDescriptor {
private String title;
private String subtitle;
private Date createdAtDate;
private String author;
private int widthInPx;
private int heightInPx;
private String imageURL;
private String thumbnailURL;
private int thumbnailWidthInPx;
private int thumbnailHeightInPx;
public ImageDescriptor(String imageURL) {
this.imageURL = imageURL;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getCreatedAtDate() {
return createdAtDate;
}
public void setCreatedAtDate(Date createdAtDate) {
this.createdAtDate = createdAtDate;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getWidthInPx() {
return widthInPx;
}
public void setWidthInPx(int widthInPx) {
this.widthInPx = widthInPx;
}
public int getHeightInPx() {
return heightInPx;
}
public void setHeightInPx(int heightInPx) {
this.heightInPx = heightInPx;
}
public String getThumbnailURL() {
return thumbnailURL;
}
public void setThumbnailURL(String thumbnailURL) {
this.thumbnailURL = thumbnailURL;
}
public String getImageURL() {
return imageURL;
}
public void setImageURL(String imageURL) {
this.imageURL = imageURL;
}
public int getThumbnailWidthInPx() {
return thumbnailWidthInPx;
}
public void setThumbnailWidthInPx(int thumbnailWidthInPx) {
this.thumbnailWidthInPx = thumbnailWidthInPx;
}
public int getThumbnailHeightInPx() {
return thumbnailHeightInPx;
}
public void setThumbnailHeightInPx(int thumbnailHeightInPx) {
this.thumbnailHeightInPx = thumbnailHeightInPx;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
}
@@ -1,42 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.imagegallery;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.Widget;
public class ImageGallery extends Composite {
private static ImageGalleryUiBinder uiBinder = GWT.create(ImageGalleryUiBinder.class);
interface ImageGalleryUiBinder extends UiBinder<Widget, ImageGallery> {
}
private ImageGalleryData imageGalleryData;
@UiField DivElement titleUi;
@UiField HTMLPanel imagesPanel;
public ImageGallery() {
ImageGalleryResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
}
public ImageGallery(ImageGalleryData data) {
this();
setData(data);
}
public void setData(ImageGalleryData data) {
this.imageGalleryData = data;
titleUi.setInnerText(this.imageGalleryData.getName() != null ? this.imageGalleryData.getName() : "");
for(ImageDescriptor imageDesc: imageGalleryData.getImages()) {
Image image = new Image(imageDesc);
imagesPanel.add(image);
}
}
}
@@ -1,10 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res" type="com.sap.sailing.gwt.common.theme.component.imagegallery.ImageGalleryResources" />
<g:HTMLPanel styleName="{local_res.css.sampleCssClass}">
<div ui:field="titleUi" />
<g:HTMLPanel ui:field='imagesPanel' />
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,38 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.imagegallery;
import java.util.ArrayList;
import java.util.List;
public class ImageGalleryData {
private String name;
private List<ImageDescriptor> images;
public ImageGalleryData() {
this("", new ArrayList<ImageDescriptor>());
}
public ImageGalleryData(String name) {
this(name, new ArrayList<ImageDescriptor>());
}
public ImageGalleryData(String name, List<ImageDescriptor> images) {
this.name = name;
this.images = images;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<ImageDescriptor> getImages() {
return images;
}
public void setImages(List<ImageDescriptor> images) {
this.images = images;
}
}
@@ -1,16 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.imagegallery;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface ImageGalleryResources extends ClientBundle {
public static final ImageGalleryResources INSTANCE = GWT.create(ImageGalleryResources.class);
@Source("ImageGallery.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String sampleCssClass();
}
}
@@ -1,55 +0,0 @@
/**
* Website footer styling
*/
.sitefooter {
font-size: 1rem;
background: #333;
border-top: 5px solid #fff;
color: #fff;
line-height: 5em;
width: 100%;
padding: 0 1.333333333333333em;
}
.sitefooter_copyright {
font-weight: 600;
margin-right: 2em;
}
@media (min-width: 45em) {
.sitefooter_copyright {
float: left;
}
}
.sitefooter_links {
text-align: left;
font-size: 1em;
font-weight: 600;
text-transform: uppercase;
}
.sitefooter_links_link {
display: block;
color: #fff;
text-decoration: none;
margin-right: 2em;
}
.sitefooter_links_link:last-child {
margin-right: 0;
}
@media (min-width: 45em) {
.sitefooter_links_link {
display: inline-block;
}
}
.sitefooter_language {
text-align: left;
}
@media (min-width: 45em) {
.sitefooter_language {
text-align: right;
}
}
.sitefooter_language_link {
color: #f0ab00;
display: inline-block;
cursor: pointer;
margin-left: 0.666666666666667em;
}
@@ -1,68 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.sapfooter;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.Location;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class SAPFooter extends Composite {
private static SAPFooterPanelUiBinder uiBinder = GWT.create(SAPFooterPanelUiBinder.class);
interface SAPFooterPanelUiBinder extends UiBinder<Widget, SAPFooter> {
}
@UiField Anchor changeLanguageLink;
@UiField DivElement languageSelectionDiv;
private final Map<String, String> localeAndLanguages;
public SAPFooter() {
localeAndLanguages = new HashMap<String, String>();
localeAndLanguages.put("default", "English");
localeAndLanguages.put("de", "Deutsch");
SAPFooterResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
updateUI();
}
@UiHandler("changeLanguageLink")
public void changeLanguage(ClickEvent e) {
String selectedLanguage = changeLanguageLink.getText();
String selectedLocale = null;
for (Entry<String, String> entry: localeAndLanguages.entrySet()) {
if (entry.getValue().equals(selectedLanguage)) {
selectedLocale = entry.getKey();
}
}
if(selectedLocale != null) {
UrlBuilder builder = Location.createUrlBuilder().setParameter("locale", selectedLocale);
Window.Location.replace(builder.buildString());
}
}
private void updateUI() {
LocaleInfo currentLocale = LocaleInfo.getCurrentLocale();
HashMap<String, String> languagesToSelectFrom = new HashMap<String, String>(localeAndLanguages);
languagesToSelectFrom.remove(currentLocale.getLocaleName());
if(languagesToSelectFrom.size() == 1) {
changeLanguageLink.setText(languagesToSelectFrom.values().iterator().next());
}
}
}
@@ -1,47 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n"
type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res"
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res"
type="com.sap.sailing.gwt.common.theme.component.sapfooter.SAPFooterResources" />
<g:HTMLPanel>
<!-- Website footer -->
<footer class="{local_res.css.sitefooter}">
<div class="{res.mediaCss.grid}">
<div
class="{res.mediaCss.small12} {res.mediaCss.medium8} {res.mediaCss.columns}">
<div class="{local_res.css.sitefooter_copyright}">
<ui:text from='{i18n.footerCopyright}' />
</div>
<div class="{local_res.css.sitefooter_links}">
<a href="http://www.sap.com/about/legal/impressum.html" target="_blank"
class="{local_res.css.sitefooter_links_link}">
<ui:text from='{i18n.footerLegal}' />
</a>
<a href="http://www.sap.com/about/legal/privacy.html" target="_blank"
class="{local_res.css.sitefooter_links_link}">
<ui:text from='{i18n.footerPrivacy}' />
</a>
<a
href="mailto:sailing_analytics%40sap.com?subject=[SAP Sailing] Feedback"
target="_blank" class="{local_res.css.sitefooter_links_link}">
<ui:text from='{i18n.footerFeedback}' />
</a>
</div>
</div>
<div
class="{res.mediaCss.small12} {res.mediaCss.medium4} {res.mediaCss.columns} {local_res.css.sitefooter_language}">
<div ui:field="languageSelectionDiv">
<ui:text from='{i18n.footerLanguage}' />
:
<g:Anchor ui:field="changeLanguageLink"
styleName="{local_res.css.sitefooter_language_link}" />
</div>
</div>
</div>
</footer>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,21 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.sapfooter;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface SAPFooterResources extends ClientBundle {
public static final SAPFooterResources INSTANCE = GWT.create(SAPFooterResources.class);
@Source("SAPFooter.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String sitefooter();
String sitefooter_copyright();
String sitefooter_links();
String sitefooter_links_link();
String sitefooter_language();
String sitefooter_language_link();
}
}
@@ -1,102 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.videogallery;
import java.util.Date;
public class VideoDescriptor {
private String title;
private String subtitle;
private Date createdAtDate;
private String author;
private int widthInPx;
private int heightInPx;
private String videoURL;
private String thumbnailURL;
private int thumbnailWidthInPx;
private int thumbnailHeightInPx;
public VideoDescriptor(String videoURL) {
this.videoURL = videoURL;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getCreatedAtDate() {
return createdAtDate;
}
public void setCreatedAtDate(Date createdAtDate) {
this.createdAtDate = createdAtDate;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getWidthInPx() {
return widthInPx;
}
public void setWidthInPx(int widthInPx) {
this.widthInPx = widthInPx;
}
public int getHeightInPx() {
return heightInPx;
}
public void setHeightInPx(int heightInPx) {
this.heightInPx = heightInPx;
}
public String getThumbnailURL() {
return thumbnailURL;
}
public void setThumbnailURL(String thumbnailURL) {
this.thumbnailURL = thumbnailURL;
}
public String getVideoURL() {
return videoURL;
}
public void setVideoURL(String videoURL) {
this.videoURL = videoURL;
}
public int getThumbnailWidthInPx() {
return thumbnailWidthInPx;
}
public void setThumbnailWidthInPx(int thumbnailWidthInPx) {
this.thumbnailWidthInPx = thumbnailWidthInPx;
}
public int getThumbnailHeightInPx() {
return thumbnailHeightInPx;
}
public void setThumbnailHeightInPx(int thumbnailHeightInPx) {
this.thumbnailHeightInPx = thumbnailHeightInPx;
}
public String getSubtitle() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle = subtitle;
}
}
@@ -1,36 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.videogallery;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
public class VideoGallery extends Composite {
private static VideoGalleryUiBinder uiBinder = GWT.create(VideoGalleryUiBinder.class);
interface VideoGalleryUiBinder extends UiBinder<Widget, VideoGallery> {
}
private VideoGalleryData videoGalleryData;
@UiField DivElement galleryTitle;
public VideoGallery() {
VideoGalleryResources.INSTANCE.css().ensureInjected();
initWidget(uiBinder.createAndBindUi(this));
}
public VideoGallery(VideoGalleryData data) {
this();
setData(data);
}
public void setData(VideoGalleryData data) {
this.videoGalleryData = data;
galleryTitle.setInnerText(this.videoGalleryData.getName() != null ? this.videoGalleryData.getName() : "");
}
}
@@ -1,14 +0,0 @@
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder"
xmlns:g="urn:import:com.google.gwt.user.client.ui">
<ui:with field="i18n"
type="com.sap.sailing.gwt.common.client.i18n.TextMessages" />
<ui:with field="res"
type="com.sap.sailing.gwt.common.client.SharedResources" />
<ui:with field="local_res"
type="com.sap.sailing.gwt.common.theme.component.videogallery.VideoGalleryResources" />
<g:HTMLPanel styleName="{local_res.css.sampleCssClass}">
Video gallery...
<div ui:field='galleryTitle'></div>
</g:HTMLPanel>
</ui:UiBinder>
@@ -1,38 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.videogallery;
import java.util.ArrayList;
import java.util.List;
public class VideoGalleryData {
private String name;
private List<VideoDescriptor> videos;
public VideoGalleryData() {
this("", new ArrayList<VideoDescriptor>());
}
public VideoGalleryData(String name) {
this(name, new ArrayList<VideoDescriptor>());
}
public VideoGalleryData(String name, List<VideoDescriptor> videos) {
this.name = name;
this.videos = videos;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<VideoDescriptor> getVideos() {
return videos;
}
public void setVideos(List<VideoDescriptor> videos) {
this.videos = videos;
}
}
@@ -1,16 +0,0 @@
package com.sap.sailing.gwt.common.theme.component.videogallery;
import com.google.gwt.core.client.GWT;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
public interface VideoGalleryResources extends ClientBundle {
public static final VideoGalleryResources INSTANCE = GWT.create(VideoGalleryResources.class);
@Source("VideoGallery.gss")
LocalCss css();
public interface LocalCss extends CssResource {
String sampleCssClass();
}
}
@@ -5,9 +5,14 @@ import com.sap.sse.gwt.dispatch.shared.commands.Action;
import com.sap.sse.gwt.dispatch.shared.commands.Result;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* Extended {@link Action} interface, which requires a {@link SailingDispatchContext} for server-side execution.
*
* @param <R>
* {@link Result} type provided by the actions {@link #execute(SailingDispatchContext)} method
*/
public interface SailingAction<R extends Result> extends Action<R, SailingDispatchContext> {
@GwtIncompatible
R execute(SailingDispatchContext ctx) throws DispatchException;
}
@@ -8,7 +8,10 @@ import com.sap.sailing.news.EventNewsService;
import com.sap.sailing.server.RacingEventService;
import com.sap.sse.gwt.dispatch.client.system.DispatchContext;
/**
* {@link DispatchContext} implementation, which is passed to backend-side {@link SailingAction} executions to provide
* access to the required services related to the sailing domain.
*/
public interface SailingDispatchContext extends DispatchContext {
@GwtIncompatible
RacingEventService getRacingEventService();
@@ -13,6 +13,18 @@ import com.sap.sse.gwt.dispatch.shared.commands.ListResult;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the competition format races view for the
* {@link #GetCompetitionFormatRacesAction(UUID, String) given event- and regatta-id}, using a
* {@link RaceCompetitionFormatDataCalculator} to prepare the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live
* {@link EventActionUtil#getEventStateDependentTTL(SailingDispatchContext, UUID, Duration) depends on the event's
* state} using a duration of <i>1 minute</i> for currently running events.
* </p>
*/
public class GetCompetitionFormatRacesAction implements
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable {
@@ -22,6 +34,12 @@ public class GetCompetitionFormatRacesAction implements
protected GetCompetitionFormatRacesAction() {
}
/**
* Creates a {@link GetCompetitionFormatRacesAction} instance for the given event and regatta-id.
*
* @param eventId {@link UUID} of the event to load races for
* @param regattaId {@link String id} of the regatta to load races for
*/
public GetCompetitionFormatRacesAction(UUID eventId, String regattaId) {
this.eventId = eventId;
this.regattaId = regattaId;
@@ -8,6 +8,12 @@ import com.sap.sailing.gwt.server.EventListDataCalculator;
import com.sap.sailing.gwt.server.HomeServiceUtil;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the events list overview, using a
* {@link EventListDataCalculator} to prepare the appropriate data structure.
* </p>
*/
public class GetEventListViewAction implements SailingAction<EventListViewDTO>, IsClientCacheable {
@Override
@GwtIncompatible
@@ -12,6 +12,18 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the finished races section for the
* {@link #GetFinishedRacesAction(UUID, String) given event- and regatta-id}, using a {@link RaceListDataCalculator} to
* prepare the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live
* {@link EventActionUtil#getEventStateDependentTTL(SailingDispatchContext, UUID, Duration) depends on the event's
* state} using a duration of <i>5 minutes</i> for currently running events.
* </p>
*/
public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<SortedSetResult<RaceListRaceDTO>>>,
IsClientCacheable {
@@ -22,6 +34,12 @@ public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<Sorte
private GetFinishedRacesAction() {
}
/**
* Creates a {@link GetCompetitionFormatRacesAction} instance for the given event and regatta-id.
*
* @param eventId {@link UUID} of the event to load races for
* @param regattaId {@link String id} of the regatta to load races for
*/
public GetFinishedRacesAction(UUID eventId, String regattaId) {
this.eventId = eventId;
this.regattaId = regattaId;
@@ -7,12 +7,28 @@ import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.LiveRaceCalculator;
import com.sap.sailing.gwt.home.server.EventActionUtil.CalculationWithEvent;
import com.sap.sailing.gwt.home.server.LiveRaceCalculator;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the live races section for the
* {@link #GetLiveRacesForEventAction(UUID) given event-id}, using a {@link LiveRaceCalculator} to prepare the
* appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is calculated using the {@link LiveRaceCalculator}'s internal
* {@link com.sap.sailing.gwt.home.server.RaceRefreshCalculator}, which is called for every race in the event.
* </p>
* <p>
* NOTE: Because there can only be live races in currently running events, this action returns an empty
* {@link ResultWithTTL result} with a {@link EventActionUtil#calculateTtlForNonLiveEvent(Event, EventState)
* state-dependent} time to live, if the {@link Event} for the given id is not currently running.
* </p>
*/
public class GetLiveRacesForEventAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable {
private UUID eventId;
@@ -21,6 +37,12 @@ public class GetLiveRacesForEventAction implements SailingAction<ResultWithTTL<S
private GetLiveRacesForEventAction() {
}
/**
* Creates a {@link GetLiveRacesForEventAction} instance for the given event-id.
*
* @param eventId
* {@link UUID} of the event to load live races for
*/
public GetLiveRacesForEventAction(UUID eventId) {
this.eventId = eventId;
}
@@ -7,12 +7,28 @@ import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.LiveRaceCalculator;
import com.sap.sailing.gwt.home.server.EventActionUtil.CalculationWithEvent;
import com.sap.sailing.gwt.home.server.LiveRaceCalculator;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the live races section for the
* {@link #GetLiveRacesForRegattaAction(UUID, String) given event-id and regatta name}, using a
* {@link LiveRaceCalculator} to prepare the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is calculated using the {@link LiveRaceCalculator}'s internal
* {@link com.sap.sailing.gwt.home.server.RaceRefreshCalculator}, which is called for every race in the regatta.
* </p>
* <p>
* NOTE: Because there can only be live races in currently running events, this action returns an empty
* {@link ResultWithTTL result} with a {@link EventActionUtil#calculateTtlForNonLiveEvent(Event, EventState)
* state-dependent} time to live, if the {@link Event} for the given id is not currently running.
* </p>
*/
public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable {
private UUID eventId;
@@ -21,7 +37,13 @@ public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL
@SuppressWarnings("unused")
private GetLiveRacesForRegattaAction() {
}
/**
* Creates a {@link GetLiveRacesForRegattaAction} instance for the given event-id and regatta name.
*
* @param eventId {@link UUID} of the event to load live races for
* @param regattaName {@link String name} of the regatta to load live races for
*/
public GetLiveRacesForRegattaAction(UUID eventId, String regattaName) {
this.eventId = eventId;
this.regattaName = regattaName;
@@ -9,13 +9,24 @@ import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sailing.gwt.home.server.EventActionUtil.LeaderboardCallback;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sse.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown on the event overview or regattas page for the
* {@link #GetRegattaListViewAction(UUID) given event-id}, preparing the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live
* {@link EventActionUtil#getEventStateDependentTTL(SailingDispatchContext, UUID, Duration) depends on the event's
* state} using a duration of <i>3 minutes</i> for currently running events.
* </p>
*/
public class GetRegattaListViewAction implements SailingAction<ResultWithTTL<SortedSetResult<RegattaWithProgressDTO>>>,
IsClientCacheable {
private UUID eventId;
@@ -24,6 +35,12 @@ public class GetRegattaListViewAction implements SailingAction<ResultWithTTL<Sor
private GetRegattaListViewAction() {
}
/**
* Creates a {@link GetRegattaListViewAction} instance for the given event-id.
*
* @param eventId
* {@link UUID} of the event to load regattas for
*/
public GetRegattaListViewAction(UUID eventId) {
this.eventId = eventId;
}
@@ -12,6 +12,16 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the statistics sections for the
* {@link #GetRegattaStatisticsAction(UUID) given event- and regatta-id}, using a {@link StatisticsCalculator} to prepare
* the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>5 minutes</i>.
* </p>
*/
public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID eventId;
@@ -20,6 +30,12 @@ public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<E
protected GetRegattaStatisticsAction() {
}
/**
* Creates a {@link GetRegattaStatisticsAction} instance for the given event and regatta-id.
*
* @param eventId {@link UUID} of the event to load races for
* @param regattaId {@link String id} of the regatta to load races for
*/
public GetRegattaStatisticsAction(UUID eventId, String regattaId) {
this.eventId = eventId;
this.regattaId = regattaId;
@@ -7,10 +7,23 @@ import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.RaceCompetitionFormatDataCalculator;
import com.sap.sse.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown on the regatta overview page for the
* {@link #GetRegattaWithProgressAction(UUID, String) given event- and regatta-id}, using a
* {@link RaceCompetitionFormatDataCalculator} to prepare the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live
* {@link EventActionUtil#getEventStateDependentTTL(SailingDispatchContext, UUID, Duration) depends on the event's
* state} using a duration of <i>5 minutes</i> for currently running events.
* </p>
*/
public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable {
private UUID eventId;
@@ -20,6 +33,12 @@ public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL
private GetRegattaWithProgressAction() {
}
/**
* Creates a {@link GetRegattaWithProgressAction} instance for the given event and regatta-id.
*
* @param eventId {@link UUID} of the event to load races for
* @param regattaId {@link String id} of the regatta to load races for
*/
public GetRegattaWithProgressAction(UUID eventId, String regattaId) {
this.eventId = eventId;
this.regattaId = regattaId;
@@ -13,15 +13,25 @@ import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sailing.gwt.home.server.RaceContext;
import com.sap.sailing.gwt.home.server.EventActionUtil.LeaderboardCallback;
import com.sap.sailing.gwt.home.server.EventActionUtil.RaceCallback;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sailing.gwt.home.server.RaceContext;
import com.sap.sailing.gwt.server.HomeServiceUtil;
import com.sap.sse.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown on the mobile event overview page for the
* {@link #GetRegattasAndLiveRacesForEventAction(UUID) given event-id}, preparing the appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>2 minutes</i> for upcoming and currently running events,
* otherwise it {@link EventActionUtil#calculateTtlForNonLiveEvent(Event, EventState) depends on the event's state}.
* </p>
*/
public class GetRegattasAndLiveRacesForEventAction implements SailingAction<ResultWithTTL<RegattasAndLiveRacesDTO>>,
IsClientCacheable {
private UUID eventId;
@@ -30,6 +40,12 @@ public class GetRegattasAndLiveRacesForEventAction implements SailingAction<Resu
private GetRegattasAndLiveRacesForEventAction() {
}
/**
* Creates a {@link GetRegattasAndLiveRacesForEventAction} instance for the given event-id.
*
* @param eventId
* {@link UUID} of the event to load regattas and live races for
*/
public GetRegattasAndLiveRacesForEventAction(UUID eventId) {
this.eventId = eventId;
}
@@ -6,12 +6,23 @@ import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.event.statistics.EventStatisticsDTO;
import com.sap.sailing.gwt.home.communication.event.statistics.GetEventStatisticsAction;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.StatisticsCalculator;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the statistics sections for the
* {@link #GetSeriesStatisticsAction(UUID) given series-id}, using a {@link StatisticsCalculator} to prepare the
* appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>5 minutes</i>.
* </p>
*/
public class GetSeriesStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID seriesId;
@@ -19,6 +30,12 @@ public class GetSeriesStatisticsAction implements SailingAction<ResultWithTTL<Ev
protected GetSeriesStatisticsAction() {
}
/**
* Creates a {@link GetEventStatisticsAction} instance for the given series-id.
*
* @param seriesId
* {@link UUID} of the series to load data for
*/
public GetSeriesStatisticsAction(UUID seriesId) {
this.seriesId = seriesId;
}
@@ -3,12 +3,24 @@ package com.sap.sailing.gwt.home.communication.event.minileaderboard;
import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in compact leaderboard (e.g. on the event overview
* page) for the {@link #GetMiniLeaderbordAction(UUID, String) given event-id and leaderboard name}, where the amount of
* loaded entries can optionally be {@link #GetMiniLeaderbordAction(UUID, String, int) limited}.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>1 minute</i> for currently running events, <i>2 minutes</i>
* otherwise.
* </p>
*/
public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
private UUID eventId;
private String leaderboardName;
@@ -18,10 +30,30 @@ public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetM
private GetMiniLeaderbordAction() {
}
/**
* Creates a {@link GetMiniLeaderbordAction} instance for the given event-id and leaderboard name, where the amount
* of loaded entries is unlimited.
*
* @param eventId
* {@link UUID} of the {@link Event} to load data for
* @param leaderboardName
* {@link String leaderboard name} to load data for
*/
public GetMiniLeaderbordAction(UUID eventId, String leaderboardName) {
this(eventId, leaderboardName, 0);
}
/**
* Creates a {@link GetMiniLeaderbordAction} instance for the given event-id and leaderboard name, where the loaded
* entries are limited to the provided amount.
*
* @param eventId
* {@link UUID} of the {@link Event} to load data for
* @param leaderboardName
* {@link String leaderboard name} to load data for
* @param limit
* maximum number of entries to be loaded
*/
public GetMiniLeaderbordAction(UUID eventId, String leaderboardName, int limit) {
this.eventId = eventId;
this.leaderboardName = leaderboardName;
@@ -9,6 +9,17 @@ import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in compact leaderboard (e.g. on the series overview
* page) for the {@link #GetMiniOverallLeaderbordAction(UUID) given series-id}, where the amount of loaded entries can
* optionally be {@link #GetMiniOverallLeaderbordAction(UUID, int) limited}.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>1 minute</i> for currently running events, <i>2 minutes</i>
* otherwise.
* </p>
*/
public class GetMiniOverallLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
private UUID seriesId;
private int limit = 0;
@@ -17,10 +28,26 @@ public class GetMiniOverallLeaderbordAction implements SailingAction<ResultWithT
private GetMiniOverallLeaderbordAction() {
}
public GetMiniOverallLeaderbordAction(UUID eventId) {
this(eventId, 0);
/**
* Creates a {@link GetMiniLeaderbordAction} instance for the given series-id, where the amount of loaded entries is
* unlimited.
*
* @param seriesId
* {@link UUID} of the series to load data for
*/
public GetMiniOverallLeaderbordAction(UUID seriesId) {
this(seriesId, 0);
}
/**
* Creates a {@link GetMiniLeaderbordAction} instance for the given series-id, where the loaded
* entries are limited to the provided amount.
*
* @param seriesId
* {@link UUID} of the series to load data for
* @param limit
* maximum number of entries to be loaded
*/
public GetMiniOverallLeaderbordAction(UUID seriesId, int limit) {
this.seriesId = seriesId;
this.limit = limit;
@@ -8,6 +8,7 @@ import com.google.gwt.core.shared.GwtIncompatible;
import com.sap.sailing.domain.base.Event;
import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.event.EventState;
import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sailing.gwt.home.server.EventActionUtil.CalculationWithEvent;
import com.sap.sailing.news.EventNewsItem;
@@ -18,6 +19,21 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ListResult;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the news ticker section for the
* {@link #GetEventOverviewNewsAction(UUID) given event-id}, where the amount of loaded news entries can optionally be
* {@link #GetEventOverviewNewsAction(UUID, int) limited}.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>2 minutes</i> for currently running events.
* </p>
* <p>
* NOTE: Because the news ticker section is only shown in currently running events, this action returns an empty
* {@link ResultWithTTL result} with a {@link EventActionUtil#calculateTtlForNonLiveEvent(Event, EventState)
* state-dependent} time to live, if the {@link Event} for the given id is not currently running.
* </p>
*/
public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<ListResult<NewsEntryDTO>>>, IsClientCacheable {
private UUID eventId;
/**
@@ -29,10 +45,26 @@ public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<L
private GetEventOverviewNewsAction() {
}
/**
* Creates a {@link GetEventOverviewNewsAction} instance for the given event-id, where the amount of loaded news
* entries is unlimited.
*
* @param eventId
* {@link UUID} of the {@link Event} to load news for
*/
public GetEventOverviewNewsAction(UUID eventId) {
this.eventId = eventId;
}
/**
* Creates a {@link GetEventOverviewNewsAction} instance for the given event-id, where the loaded news entries are
* limited to the provided amount.
*
* @param eventId
* {@link UUID} of the {@link Event} to load news for
* @param limit
* maximum number of news entries to be loaded
*/
public GetEventOverviewNewsAction(UUID eventId, int limit) {
this.eventId = eventId;
this.limit = limit;
@@ -11,6 +11,16 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the statistics sections for the
* {@link #GetEventStatisticsAction(UUID) given event-id}, using a {@link StatisticsCalculator} to prepare the
* appropriate data structure.
* </p>
* <p>
* The {@link ResultWithTTL result's} time to live is <i>5 minutes</i>.
* </p>
*/
public class GetEventStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID eventId;
@@ -18,6 +28,12 @@ public class GetEventStatisticsAction implements SailingAction<ResultWithTTL<Eve
protected GetEventStatisticsAction() {
}
/**
* Creates a {@link GetEventStatisticsAction} instance for the given event-id.
*
* @param eventId
* {@link UUID} of the event to load data for
*/
public GetEventStatisticsAction(UUID eventId) {
this.eventId = eventId;
}
@@ -19,6 +19,12 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
import com.sap.sse.shared.media.ImageDescriptor;
/**
* <p>
* {@link SailingAction} implementation to load data to be shown in the series list overview for the
* {@link #GetEventSeriesViewAction(UUID) given series-id}, preparing the appropriate data structure.
* </p>
*/
public class GetEventSeriesViewAction implements SailingAction<EventSeriesViewDTO>, IsClientCacheable {
private UUID id;
@@ -27,6 +33,12 @@ public class GetEventSeriesViewAction implements SailingAction<EventSeriesViewDT
private GetEventSeriesViewAction() {
}
/**
* Creates a {@link GetEventSeriesViewAction} instance for the given series-id.
*
* @param id
* {@link UUID} of the series to load data for
*/
public GetEventSeriesViewAction(UUID id) {
super();
this.id = id;
@@ -15,6 +15,12 @@ import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
import com.sap.sse.shared.media.ImageDescriptor;
import com.sap.sse.shared.media.VideoDescriptor;
/**
* <p>
* {@link SailingAction} implementation to load images and videos to be shown on the media page for the
* {@link #GetMediaForEventAction(UUID) given event-id}, preparing the appropriate data structure.
* </p>
*/
public class GetMediaForEventAction implements SailingAction<MediaDTO>, IsClientCacheable {
private UUID eventId;
@@ -23,6 +29,12 @@ public class GetMediaForEventAction implements SailingAction<MediaDTO>, IsClient
private GetMediaForEventAction() {
}
/**
* Creates a {@link GetMediaForEventAction} instance for the given event-id.
*
* @param eventId
* {@link UUID} of the event to load media for
*/
public GetMediaForEventAction(UUID eventId) {
this.eventId = eventId;
}
@@ -15,6 +15,12 @@ import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ListResult;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
/**
* <p>
* {@link SailingAction} implementation to load recent events to be shown in the event list overview, where
* the amount of loaded entries can be {@link #GetRecentEventsAction(int) limited}.
* </p>
*/
public class GetRecentEventsAction implements SailingAction<ListResult<EventQuickfinderDTO>>, IsClientCacheable {
private int limit;
@@ -22,6 +28,12 @@ public class GetRecentEventsAction implements SailingAction<ListResult<EventQuic
protected GetRecentEventsAction() {
}
/**
* Creates a {@link GetRecentEventsAction} instance where the loaded entries are limited to the provided amount.
*
* @param limit
* maximum number of entries to be loaded
*/
public GetRecentEventsAction(int limit) {
this.limit = limit;
}
@@ -11,6 +11,7 @@ import com.sap.sailing.gwt.home.desktop.app.DesktopActivityManager;
import com.sap.sailing.gwt.home.desktop.app.DesktopActivityMapper;
import com.sap.sailing.gwt.home.desktop.app.DesktopClientFactory;
import com.sap.sailing.gwt.home.desktop.app.TabletAndDesktopApplicationClientFactory;
import com.sap.sailing.gwt.home.shared.SwitchingEntryPoint;
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.ui.client.RemoteServiceMappingConstants;
import com.sap.sailing.gwt.ui.client.ServerConfigurationService;
@@ -21,6 +22,10 @@ import com.sap.sse.gwt.client.mvp.AbstractMvpEntryPoint;
import com.sap.sse.gwt.resources.CommonControlsCSS;
import com.sap.sse.gwt.resources.Highcharts;
/**
* Desktop/tablet EntryPoint for the Home module. Be aware that this EntryPoint isn't directly started but instead the
* {@link SwitchingEntryPoint} decides about which version of the application will be shown.
*/
public class DesktopEntryPoint extends AbstractMvpEntryPoint<StringMessages, DesktopClientFactory> {
@@ -5,6 +5,10 @@ import com.google.gwt.activity.shared.ActivityMapper;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sailing.gwt.home.shared.app.SailingActivityManager;
/**
* Ensures that {@link DesktopResettableNavigationPathDisplay} will be correcly informed about the Activity type when
* the current activity changes.
*/
public class DesktopActivityManager extends SailingActivityManager<DesktopResettableNavigationPathDisplay> {
public DesktopActivityManager(ActivityMapper mapper, EventBus eventBus) {
@@ -1,7 +1,13 @@
package com.sap.sailing.gwt.home.desktop.app;
import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay;
import com.sap.sailing.gwt.home.shared.app.ResettableNavigationPathDisplay;
/**
* In sailing there are two kinds of activities: Ones with header and ones without. Because the header has a gray
* background, the {@link NavigationPathDisplay} needs to be set to the exact same background. Activities without header
* have white background, so we need to switch this based on the Activity type.
*/
public interface DesktopResettableNavigationPathDisplay extends ResettableNavigationPathDisplay {
void setWithHeader(boolean withHeader);
}
@@ -22,6 +22,9 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.client.media.GalleryImageHolder;
import com.sap.sailing.gwt.ui.client.media.VideoThumbnail;
/**
* Desktop page to show videos and images as a gallery.
*/
public class MediaPage extends Composite {
private static MediaPageUiBinder uiBinder = GWT.create(MediaPageUiBinder.class);
@@ -65,6 +68,8 @@ public class MediaPage extends Composite {
photoSectionUi.getStyle().clearDisplay();
String photoCss = null;
// To make the image gallery look good, we use different styling if there are only few (<7) images
// available. If there are more images, always 4 images are shown in a row.
switch (photosCount) {
case 1:
photoCss = res.mediaCss().medium12();
@@ -139,6 +144,12 @@ public class MediaPage extends Composite {
}
}
/**
* Shows a selected video in the big viewer.
*
* @param video the video to show in the big viewer
* @param autoplay true, if the video should play automatically, false otherwise
*/
private void putVideoOnDisplay(final SailingVideoDTO video, boolean autoplay) {
videoDisplayUi = new VideoWithLowerThird(true, autoplay);
videoDisplayUi.setVideo(video);
@@ -9,6 +9,10 @@ import com.sap.sailing.gwt.home.communication.media.SailingImageDTO;
import com.sap.sailing.gwt.home.shared.partials.fullscreen.FullscreenContainer;
import com.sap.sse.gwt.client.controls.carousel.ImageCarousel.FullscreenViewer;
/**
* Fullscreen viewer for the image gallery that shows the current image in a big view and lists all images on the bottom
* as small slider.
*/
public class SailingFullscreenViewer extends FullscreenContainer<SailingGalleryPlayer> implements
FullscreenViewer<SailingImageDTO> {
@@ -40,6 +40,12 @@ import com.sap.sailing.gwt.ui.raceboard.RaceBoardPerspectiveSettings;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
/**
* Base Activity for all desktop event pages. This includes the event page itself for multi-regatta events as well as
* regatta/single-regatta-event pages.
*
* @param <PLACE> The concrete {@link AbstractEventPlace} subclass, this instance is bound to.
*/
public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> extends AbstractActivity implements
EventView.Presenter {
@@ -57,6 +63,12 @@ public abstract class AbstractEventActivity<PLACE extends AbstractEventPlace> ex
protected final EventViewDTO eventDTO;
/**
* @param place the place of the tab to be activated
* @param eventDTO the basic event data
* @param clientFactory the {@link EventClientFactory} to use
* @param homePlacesNavigator the {@link DesktopPlacesNavigator} to use to navigate to other places in the application
*/
public AbstractEventActivity(PLACE place, EventViewDTO eventDTO, EventClientFactory clientFactory, DesktopPlacesNavigator homePlacesNavigator) {
this.currentPlace = place;
this.eventDTO = eventDTO;
@@ -12,6 +12,11 @@ import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay;
import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay.NavigationItem;
import com.sap.sailing.gwt.ui.client.StringMessages;
/**
* Base Activity for all desktop multi-regatta-event pages.
*
* @param <PLACE> The concrete {@link AbstractMultiregattaEventPlace} subclass, this instance is bound to.
*/
public class EventMultiregattaActivity extends AbstractEventActivity<AbstractMultiregattaEventPlace> implements EventMultiregattaView.Presenter {
private EventMultiregattaView currentView = new TabletAndDesktopMultiRegattaEventView();
@@ -2,12 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.event.multiregatta.mediatab;
import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.multiregatta.AbstractMultiregattaEventPlace;
import com.sap.sailing.gwt.home.shared.app.MobileSupport;
import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
public class MultiregattaMediaPlace extends AbstractMultiregattaEventPlace implements MobileSupport {
public class MultiregattaMediaPlace extends AbstractMultiregattaEventPlace implements HasMobileVersion {
public MultiregattaMediaPlace(String id) {
super(id);
}
@@ -23,9 +23,4 @@ public class MultiregattaMediaPlace extends AbstractMultiregattaEventPlace imple
return new MultiregattaMediaPlace(context);
}
}
@Override
public boolean hasMobileVersion() {
return true;
}
}
@@ -8,11 +8,11 @@ import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.sap.sailing.gwt.home.communication.event.EventReferenceDTO;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO.EventType;
import com.sap.sailing.gwt.home.communication.eventview.HasRegattaMetadata;
import com.sap.sailing.gwt.home.communication.eventview.HasRegattaMetadata.RegattaState;
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.home.communication.eventview.RegattaReferenceDTO;
import com.sap.sailing.gwt.home.communication.eventview.EventViewDTO.EventType;
import com.sap.sailing.gwt.home.communication.eventview.HasRegattaMetadata.RegattaState;
import com.sap.sailing.gwt.home.desktop.app.DesktopPlacesNavigator;
import com.sap.sailing.gwt.home.desktop.places.event.AbstractEventActivity;
import com.sap.sailing.gwt.home.desktop.places.event.EventClientFactory;
@@ -20,8 +20,8 @@ import com.sap.sailing.gwt.home.desktop.places.event.EventView;
import com.sap.sailing.gwt.home.desktop.places.event.EventView.PlaceCallback;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.overviewtab.RegattaOverviewPlace;
import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.app.NavigationPathDisplay.NavigationItem;
import com.sap.sailing.gwt.home.shared.app.PlaceNavigation;
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
@@ -30,6 +30,13 @@ import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.player.Timer.PlayStates;
import com.sap.sse.gwt.client.useragent.UserAgentDetails;
/**
* Base Activity for all desktop single-regatta-event/series-event pages as well as the pages for one regatta of a
* multi-regatta-event.
*
* @param <PLACE>
* The concrete {@link AbstractEventRegattaPlace} subclass, this instance is bound to.
*/
public class EventRegattaActivity extends AbstractEventActivity<AbstractEventRegattaPlace> implements EventRegattaView.Presenter {
private EventRegattaView currentView = new TabletAndDesktopRegattaEventView();
private final UserAgentDetails userAgent = new UserAgentDetails(Window.Navigator.getUserAgent());
@@ -2,12 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta.mediatab;
import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace;
import com.sap.sailing.gwt.home.shared.app.MobileSupport;
import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
public class RegattaMediaPlace extends AbstractEventRegattaPlace implements MobileSupport {
public class RegattaMediaPlace extends AbstractEventRegattaPlace implements HasMobileVersion {
public RegattaMediaPlace(String id, String regattaId) {
super(id, regattaId);
}
@@ -29,9 +29,4 @@ public class RegattaMediaPlace extends AbstractEventRegattaPlace implements Mobi
return new RegattaMediaPlace(context);
}
}
@Override
public boolean hasMobileVersion() {
return true;
}
}
@@ -2,12 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta.racestab;
import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace;
import com.sap.sailing.gwt.home.shared.app.MobileSupport;
import com.sap.sailing.gwt.home.shared.app.HasMobileVersion;
import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
public class RegattaRacesPlace extends AbstractEventRegattaPlace implements MobileSupport {
public class RegattaRacesPlace extends AbstractEventRegattaPlace implements HasMobileVersion {
public RegattaRacesPlace(String id, String leaderboardName) {
super(id, leaderboardName);
}
@@ -28,9 +28,4 @@ public class RegattaRacesPlace extends AbstractEventRegattaPlace implements Mobi
return new RegattaRacesPlace(context);
}
}
@Override
public boolean hasMobileVersion() {
return true;
}
}
@@ -9,6 +9,7 @@ import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.sap.sailing.gwt.common.client.SharedResources;
import com.sap.sailing.gwt.home.mobile.app.MobileActivityMapper;
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
import com.sap.sailing.gwt.home.shared.SwitchingEntryPoint;
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
import com.sap.sailing.gwt.home.shared.app.ResettableNavigationPathDisplay;
import com.sap.sailing.gwt.home.shared.app.SailingActivityManager;
@@ -20,6 +21,10 @@ import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.gwt.client.mvp.AbstractMvpEntryPoint;
import com.sap.sse.gwt.resources.CommonControlsCSS;
/**
* Smartphone EntryPoint for the Home module. Be aware that this EntryPoint isn't directly started but instead the
* {@link SwitchingEntryPoint} decides about which version of the application will be shown.
*/
public class MobileEntryPoint extends AbstractMvpEntryPoint<StringMessages, MobileApplicationClientFactory> {
@@ -30,6 +30,9 @@ import com.sap.sailing.gwt.home.mobile.app.MobilePlacesNavigator;
import com.sap.sailing.gwt.home.shared.SwitchingEntryPoint;
import com.sap.sse.common.Util.Pair;
/**
* Mobile page footer with several links and the ability to switch the language.
*/
public class Footer extends Composite {
private static FooterPanelUiBinder uiBinder = GWT.create(FooterPanelUiBinder.class);
@@ -26,6 +26,9 @@ import com.sap.sse.gwt.client.LinkUtil;
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
import com.sap.sse.security.ui.authentication.AuthenticationSignOutRequestEvent;
/**
* Mobile page header with SAP logo title and a dropdown menu (burger button) on the right.
*/
public class Header extends Composite {
// @UiField TextBox searchText;
@@ -11,6 +11,9 @@ import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Widget;
/**
* Represents an entry in the header's popup menu.
*/
public class HeaderNavigationItem extends Widget implements HasClickHandlers {
@UiField
@@ -82,6 +82,19 @@ public final class EventActionUtil {
return new LeaderboardContext(context, event, leaderboardGroups, leaderboard);
}
/**
* Gets or calculates the time to live for the event with the given ID, depending on its
* {@link HomeServiceUtil#calculateEventState(com.sap.sailing.domain.base.EventBase) calculated state}.
*
* @param context
* {@link SailingDispatchContext} to retrieve {@link Event}
* @param eventId
* {@link UUID} of the {@link Event} to get/calculate the time to live for
* @param liveTTL
* the {@link Duration time to live} to use if the event is currently running
* @return the given liveTTL if the event is currently running, otherwise the
* {@link #calculateTtlForNonLiveEvent(Event, EventState) calculated TTL}
*/
public static Duration getEventStateDependentTTL(SailingDispatchContext context, UUID eventId, Duration liveTTL) {
Event event = context.getRacingEventService().getEvent(eventId);
return getEventStateDependentTTL(event, liveTTL);
@@ -104,6 +117,25 @@ public final class EventActionUtil {
return callback.calculateWithEvent(event);
}
/**
* Calculates the time to live based on the given {@link Event}'s {@link Event#getStartDate() start time} and the
* given {@link HomeServiceUtil#calculateEventState(com.sap.sailing.domain.base.EventBase) calculated state}:
* <p><table>
* <tr><th>Event state </th><th>Start time </th><th>TTL </th></tr>
* <tr><td>UPMCOMING/PLANNED</td><td>36 hours and more before</td><td>=> 1 hour</td></tr>
* <tr><td> </td><td>less than 36 hours before</td><td>=> 30 minutes</td></tr>
* <tr><td> </td><td>less than 3 hours before</td><td>=> 15 minutes</td></tr>
* <tr><td> </td><td>less than 15 minutes before</td><td>=> time till start</td></tr>
* <tr><td>FINISHED </td><td>any </td><td>=> 12 hours</td></tr>
* <tr><td>RUNNING </td><td>any </td><td>=> [0]</td></tr>
* </table></p>
*
* @param event
* {@link Event} to calculate the time to live for
* @param eventState
* the {@link EventState} to calculate the time to live for
* @return The calculated {@link Duration time to live}
*/
public static Duration calculateTtlForNonLiveEvent(Event event, EventState eventState) {
TimePoint now = MillisecondsTimePoint.now();
if(eventState == EventState.UPCOMING || eventState == EventState.PLANNED) {
@@ -21,8 +21,7 @@ import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesContext;
import com.sap.sailing.gwt.home.shared.places.fakeseries.SeriesDefaultPlace;
/**
* Helper class to support converting old places to new ones.
*
* Helper class to support converting old places to new ones and relace inconsistent places with working ones.
*/
public class ApplicationPlaceUpdater {
@@ -2,6 +2,10 @@ package com.sap.sailing.gwt.home.shared.app;
import com.sap.sailing.gwt.home.communication.SailingDispatchSystem;
/**
* Definition of ClientFactories that provide access to the dispatch based remote framework through
* {@link SailingDispatchSystem}.
*/
public interface ClientFactoryWithDispatch {
SailingDispatchSystem getDispatch();
}
@@ -1,5 +1,9 @@
package com.sap.sailing.gwt.home.shared.app;
/**
* Allows places to define a custom page title. This title is shown as page title on desktop and in the header on
* mobile.
*/
public interface HasLocationTitle {
String getLocationTitle();
}
@@ -1,5 +1,9 @@
package com.sap.sailing.gwt.home.shared.app;
/**
* Marker for Places that have a mobile version. This is used to decide which page version has to be shown for a
* specific place.
*/
public interface HasMobileVersion {
}
@@ -1,5 +1,10 @@
package com.sap.sailing.gwt.home.shared.app;
/**
* Marker for Places that have a mobile version depending on some place state. This is commonly uses in combination with
* {@link com.sap.sailing.gwt.home.shared.ExperimentalFeatures} for new mobile places that should be able to be
* deactivated during active development.
*/
public interface MobileSupport {
boolean hasMobileVersion();
@@ -1,5 +1,18 @@
package com.sap.sailing.gwt.home.shared.app;
/**
* Abstraction of a hierarchy regarding navigation. This concept is introduced to allow activities to define its
* navigation path/hierarchy using a UI element that is not part of the activity itself. This allows the central
* definition of the navigation UI without losing the ability to control the concrete navigation path for an activity in
* a fine grained way.
*
* {@link NavigationPathDisplay} uses a async mechanism to let activities set their concrete navigation path because
* some parts of the navigation path can rely on dynamic information (e.g. event/series names) that isn't available on
* construction of the activity.
*
* The abtraction also allows different implementations/visualizations. So it's possible to render breadcrumbs on
* desktop, while on mobile devices a popup menu is used.
*/
public interface NavigationPathDisplay {
void showNavigationPath(NavigationItem... navigationPath);
@@ -1,5 +1,8 @@
package com.sap.sailing.gwt.home.shared.app;
/**
* {@link NavigationPathDisplay} that can be reset to clear the currently shown navigation path.
*/
public interface ResettableNavigationPathDisplay extends NavigationPathDisplay {
void reset();
@@ -5,6 +5,13 @@ import com.google.gwt.activity.shared.ActivityMapper;
import com.google.web.bindery.event.shared.EventBus;
import com.sap.sse.gwt.client.mvp.CustomActivityManager;
/**
* Specific {@link CustomActivityManager} that controls a {@link ResettableNavigationPathDisplay} by resetting the
* navigation path before activation of an activity. With that, there is no wrong path in the navigation path if an
* acitivity defines a navigation path by itself.
*
* @param <NPD> the concrete {@link ResettableNavigationPathDisplay} used by this ActivityManager.
*/
public class SailingActivityManager<NPD extends ResettableNavigationPathDisplay> extends CustomActivityManager {
private NPD navigationPathDisplay;
@@ -26,6 +26,12 @@ import com.google.gwt.user.client.ui.SimpleLayoutPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Base class for fullscreen viewer UIs. This viewer has an extensible header area with a close button and a content
* area that takes the rest of the available space.
*
* @param <T> The type of the content widget.
*/
public class FullscreenContainer<T extends Widget> {
private static FullscreenContainerUiBinder uiBinder = GWT.create(FullscreenContainerUiBinder.class);
@@ -56,9 +62,15 @@ public class FullscreenContainer<T extends Widget> {
popup.addStyleName(style.popup());
}
/**
* To be overwritten by subclasses to hook into the fullscreen viewer's lifecycle.
*/
protected void onShow() {
}
/**
* To be overwritten by subclasses to hook into the fullscreen viewer's lifecycle.
*/
protected void onClose() {
}
@@ -72,6 +84,9 @@ public class FullscreenContainer<T extends Widget> {
headerContentUi.getElement().getStyle().setMarginLeft(5, Unit.EM);
}
/**
* Should be called by subclasses if the content needs a border as optical guidance for the user.
*/
protected void showBorder() {
contentUi.addStyleName(style.contentBorder());
}
@@ -85,6 +100,11 @@ public class FullscreenContainer<T extends Widget> {
return popup.addCloseHandler(handler);
}
/**
* To be called by subclasses to add more actions (in addition to the close button) to the upper right corner of the fullscreen veiwer.
*
* @param widget the action widget to add to the toolbar in the upper right corner.
*/
public void addToolbarAction(Widget widget) {
widget.addStyleName(style.toolbarAction());
toolbarUi.add(widget);
@@ -10,6 +10,9 @@ import com.sap.sailing.gwt.ui.client.media.PlayEvent;
import com.sap.sailing.gwt.ui.client.media.VideoJSPlayer;
import com.sap.sse.gwt.client.media.VideoDTO;
/**
* Video player with custom play button.
*/
public class VideoPlayer extends Composite {
private final VideoPlayerResources.LocalCss style = VideoPlayerResources.INSTANCE.css();
private VideoJSPlayer videoJSPlayer;
@@ -4,6 +4,9 @@ import com.sap.sailing.gwt.home.communication.event.LabelType;
import com.sap.sailing.gwt.home.shared.partials.lowerthird.LowerThird;
import com.sap.sse.gwt.client.media.VideoDTO;
/**
* Video player with a lower third containing title, subtitle and an optional {@link LabelType}.
*/
public class VideoWithLowerThird extends VideoPlayer {
private final LowerThird lowerThird = new LowerThird();
@@ -1606,4 +1606,6 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String loadingRegattasAndRaces();
String selectFromRacesWithOverlappingTimeRange();
String finishTime(String timeAsString);
String showCompetitorCharts();
String showWindChart();
}
@@ -444,7 +444,7 @@ scoringSchemeHighPointFirstGetsTen=High Point, winner gets 10 points
scoringSchemeHighPointFirstGetsTenOrEight=High Point, winner gets 10 points (or 8)
scoringSchemeHighPointFirstGetsTenOrEightDescription=Score in points. Winner scores 10 points, 2nd - 9 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored.
scoringSchemeHighPointFirstGetsTwelveOrEight=High Point, winner gets 12 points (or 8)
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor having won most races, if tie remains then tie is broken by the rank in the last race scored.
scoringSchemeHighPointFirstGetsTwelveOrEightDescription=Score in points. Winner scores 12 points, 2nd - 11 points, .... A tie is broken in favour of the competitor with the highest score, if tie remains then tie is broken by the rank in the last race scored.
scoringSystem=Scoring system
createFlexibleLeaderboard=Create flexible leaderboard
createRegattaLeaderboard=Create regatta leaderboard
@@ -1578,4 +1578,6 @@ noTracksFound=No tracks found
noRacesAvailable=No races available
loadingRegattasAndRaces=Loading Regattas and Races
selectFromRacesWithOverlappingTimeRange=Select from the races whose time range overlaps with media track those to which the track shall be linked
finishTime=Finish at: {0}
finishTime=Finish at: {0}
showCompetitorCharts=Show competitor chart
showWindChart=Show wind chart
@@ -1563,4 +1563,6 @@ noTracksFound=Keine Tracks gefunden
noRacesAvailable=Keine Rennen verfügbar
loadingRegattasAndRaces=Regatten und Rennen werden geladen
selectFromRacesWithOverlappingTimeRange=Das oder die Rennen aus der Liste derer zum Verknüpfen auswählen, die zeitlich mit dem Medien-Track überlappen
finishTime=Ende um: {0}
finishTime=Ende um: {0}
showCompetitorCharts=Teilnehmer-Diagramme zeigen
showWindChart=Windiagramm zeigen
@@ -20,7 +20,7 @@ public class MediaPlayerLifecycle implements ComponentLifecycle<MediaPlayerSetti
@Override
public MediaPlayerSettings createDefaultSettings() {
return new MediaPlayerSettings();
return MediaPlayerSettings.readSettingsFromURL();
}
@Override
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.client.media;
import com.sap.sailing.gwt.common.client.formfactor.DeviceDetector;
import com.sap.sse.common.settings.AbstractSettings;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
@@ -8,11 +9,8 @@ public class MediaPlayerSettings extends AbstractSettings {
public static final String PARAM_AUTOPLAY_MEDIA = "autoSelectMedia";
/**
* The default settings
*/
public MediaPlayerSettings() {
this.autoPlayMedia = true;
this.autoPlayMedia = !DeviceDetector.isMobile();
}
public MediaPlayerSettings(boolean autoPlayMedia) {
@@ -24,7 +22,7 @@ public class MediaPlayerSettings extends AbstractSettings {
}
public static MediaPlayerSettings readSettingsFromURL() {
final Boolean autoPlayMedia = GwtHttpRequestUtils.getBooleanParameter(PARAM_AUTOPLAY_MEDIA, true /* default */);
final Boolean autoPlayMedia = GwtHttpRequestUtils.getBooleanParameter(PARAM_AUTOPLAY_MEDIA, !DeviceDetector.isMobile());
return new MediaPlayerSettings(autoPlayMedia);
}
@@ -14,6 +14,9 @@ import com.sap.sse.common.media.MediaSubType;
import com.sap.sse.common.media.MediaType;
import com.sap.sse.common.media.MimeType;
/**
* video.js (http://videojs.com/) wrapper as GWT widget.
*/
public class VideoJSPlayer extends Widget {
private static VideoJSPlayerUiBinder uiBinder = GWT.create(VideoJSPlayerUiBinder.class);
@@ -2,5 +2,9 @@ package com.sap.sailing.gwt.ui.client.refresh;
import com.google.gwt.user.client.ui.IsWidget;
/**
* View that shows a loading indicator.
*
*/
public interface BusyView extends IsWidget {
}
@@ -2,6 +2,9 @@ package com.sap.sailing.gwt.ui.client.refresh;
import com.sap.sse.gwt.client.mvp.ErrorView;
/**
* ClientFactory definition to create error and busy (loading indicator) views.
*/
public interface ErrorAndBusyClientFactory {
BusyView createBusyView();
@@ -36,6 +36,16 @@ public class DateAndTimeFormatterUtil {
return defaultDateFormatter.render(startDate) + " - " + defaultDateFormatter.render(endDate);
}
/**
* Formats a duration in a compact format so that hours and minutes are only shown if the duration is >1h to avoid
* unnecessary 00:yy or 00:xx:yy values.
*
* Be aware that this method doesn't work for durations >= 24h.
*
* @param timeInMilliseconds
* the duration in milliseconds to format
* @return the formatted duration
*/
public static String formatElapsedTime(long timeInMilliseconds) {
String result = "";
int seconds = (int) (timeInMilliseconds / 1000) % 60 ;
@@ -12,6 +12,7 @@ import com.google.gwt.user.client.rpc.ServiceDefTarget;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.sap.sailing.gwt.common.client.formfactor.DeviceDetector;
import com.sap.sailing.gwt.ui.client.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
import com.sap.sailing.gwt.ui.client.MediaService;
@@ -25,6 +26,7 @@ import com.sap.sse.gwt.client.EntryPointHelper;
import com.sap.sse.gwt.client.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveLifecycleWithAllSettings;
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
@@ -74,6 +76,11 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
// read perspective settings parameters from URL
final RaceBoardPerspectiveSettings perspectiveSettings = RaceBoardPerspectiveSettings.readSettingsFromURL();
// Determine if the charts, such as the competitor chart or the wind chart, the edit marks
// panels, such as mark passing and mark position editors and manage media buttons should be shown.
// Automatic selection of attached video (if any) also depends on this flag.
// The decision is made once during initial page load based on the device type (mobile or not).
final boolean showChartMarkEditMediaButtonsAndVideo = !DeviceDetector.isMobile();
sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
@Override
@@ -100,7 +107,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
return;
}
createPerspectivePage(raceboardData, perspectiveSettings);
createPerspectivePage(raceboardData, perspectiveSettings, showChartMarkEditMediaButtonsAndVideo);
}
@Override
@@ -119,7 +126,8 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
vp.add(new Label(message));
}
private void createPerspectivePage(RaceboardDataDTO raceboardData, RaceBoardPerspectiveSettings perspectiveSettings) {
private void createPerspectivePage(RaceboardDataDTO raceboardData, RaceBoardPerspectiveSettings perspectiveSettings,
boolean showChartMarkEditMediaButtonsAndVideo) {
selectedRace = raceboardData.getRace();
Window.setTitle(selectedRace.getName());
Timer timer = new Timer(PlayModes.Replay, 1000l);
@@ -128,13 +136,18 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
Collections.singletonList(selectedRace.getRaceIdentifier()), 5000l /* requestInterval*/);
RaceBoardPerspectiveLifecycle raceboardPerspectiveLifecycle = new RaceBoardPerspectiveLifecycle(null, StringMessages.INSTANCE);
PerspectiveCompositeSettings<RaceBoardPerspectiveSettings> defaultSettings = raceboardPerspectiveLifecycle.createDefaultSettings();
PerspectiveCompositeSettings<RaceBoardPerspectiveSettings> perspectiveCompositeSettings =
new PerspectiveCompositeSettings<>(perspectiveSettings, defaultSettings.getSettingsPerComponentId());
PerspectiveLifecycleWithAllSettings<RaceBoardPerspectiveLifecycle, RaceBoardPerspectiveSettings> raceboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(raceboardPerspectiveLifecycle,
raceboardPerspectiveLifecycle.createDefaultSettings());
perspectiveCompositeSettings);
RaceBoardPanel raceBoardPerspective = new RaceBoardPanel(
raceboardPerspectiveLifecyclesAndSettings, sailingService, mediaService, getUserService(),
asyncActionsExecutor, raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(), leaderboardName,
leaderboardGroupName, eventId, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider);
RaceBoardPanel raceBoardPerspective = new RaceBoardPanel(raceboardPerspectiveLifecyclesAndSettings,
sailingService, mediaService, getUserService(), asyncActionsExecutor,
raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(), leaderboardName,
leaderboardGroupName, eventId, RaceBoardEntryPoint.this, getStringMessages(), userAgent,
raceTimesInfoProvider, showChartMarkEditMediaButtonsAndVideo);
RootLayoutPanel.get().add(raceBoardPerspective.getEntryWidget());
}
@@ -159,13 +159,18 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
* the charts are created. This decision is made once on startup in the {@link RaceBoardEntryPoint} class.
* @param showChartMarkEditMediaButtonsAndVideo
* if <code>true</code> charts, such as the competitor chart or the wind chart, (as well as edit mark
* panels and manage media buttons) are shown and a padding is provided for the RaceTimePanel that
* aligns its right border with that of the chart. Otherwise those components will be hidden.
*/
public RaceBoardPanel(PerspectiveLifecycleWithAllSettings<RaceBoardPerspectiveLifecycle, RaceBoardPerspectiveSettings> perspectiveLifecycleWithAllSettings,
SailingServiceAsync sailingService, MediaServiceAsync mediaService,
UserService userService, AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
SailingServiceAsync sailingService, MediaServiceAsync mediaService, UserService userService,
AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
Timer timer, RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName,
String leaderboardGroupName, UUID eventId, ErrorReporter errorReporter, final StringMessages stringMessages,
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider) {
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider,
boolean showChartMarkEditMediaButtonsAndVideo) {
super(perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle(), perspectiveLifecycleWithAllSettings.getPerspectiveSettings());
this.perspectiveLifecycleWithAllSettings = perspectiveLifecycleWithAllSettings;
this.sailingService = sailingService;
@@ -250,7 +255,8 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
leaderboardPanel.setTitle(stringMessages.leaderboard());
leaderboardPanel.getElement().getStyle().setMarginLeft(6, Unit.PX);
leaderboardPanel.getElement().getStyle().setMarginTop(10, Unit.PX);
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, isScreenLargeEnoughToInitiallyDisplayLeaderboard, raceMap, userService); // initializes the raceMap field
createOneScreenView(leaderboardName, leaderboardGroupName, eventId, mainPanel, isScreenLargeEnoughToInitiallyDisplayLeaderboard,
raceMap, userService, showChartMarkEditMediaButtonsAndVideo); // initializes the raceMap field
leaderboardPanel.addLeaderboardUpdateListener(this);
// in case the URL configuration contains the name of a competitors filter set we try to activate it
// FIXME the competitorsFilterSets has now moved to CompetitorSearchTextBox (which should probably be renamed); pass on the parameters to the LeaderboardPanel and see what it does with it
@@ -263,9 +269,10 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
}
}
}
racetimePanel = new RaceTimePanel(raceTimePanelLifecycle, userService, timer, timeRangeWithZoomModel, stringMessages, raceTimesInfoProvider,
getPerspectiveSettings().isCanReplayDuringLiveRaces(), getPerspectiveSettings().isChartSupportEnabled(),
selectedRaceIdentifier, getPerspectiveSettings().getInitialDurationAfterRaceStartInReplay());
racetimePanel = new RaceTimePanel(raceTimePanelLifecycle, userService, timer, timeRangeWithZoomModel,
stringMessages, raceTimesInfoProvider, getPerspectiveSettings().isCanReplayDuringLiveRaces(),
showChartMarkEditMediaButtonsAndVideo, selectedRaceIdentifier,
getPerspectiveSettings().getInitialDurationAfterRaceStartInReplay());
racetimePanel.updateSettings(raceTimePanelSettings);
timeRangeWithZoomModel.addTimeZoomChangeListener(racetimePanel);
raceTimesInfoProvider.addRaceTimesInfoProviderListener(racetimePanel);
@@ -289,14 +296,16 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
* @param event
* an optional event; may be <code>null</code> or else can be used to show some context information in
* the {@link GlobalNavigationPanel}.
* @param showChartMarkEditMediaButtonsAndVideo
* @param isScreenLargeEnoughToOfferChartSupport
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a
* padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
* the charts are created.
*/
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event, FlowPanel mainPanel,
boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard, RaceMap raceMap, UserService userService) {
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event,
FlowPanel mainPanel, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard, RaceMap raceMap,
UserService userService, boolean showChartMarkEditMediaButtonsAndVideo) {
MediaPlayerLifecycle mediaPlayerLifecycle = perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle().getMediaPlayerLifecycle();
MediaPlayerSettings mediaPlayerSettings = perspectiveLifecycleWithAllSettings.findComponentSettingsByLifecycle(mediaPlayerLifecycle);
@@ -309,7 +318,7 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
// create the default leaderboard and select the right race
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
List<Component<?>> componentsForSideBySideViewer = new ArrayList<Component<?>>();
if (getPerspectiveSettings().isChartSupportEnabled()) {
if (showChartMarkEditMediaButtonsAndVideo) {
competitorChart = new MultiCompetitorRaceChart(multiCompetitorRaceChartLifecycle, sailingService, asyncActionsExecutor,
competitorSelectionProvider, selectedRaceIdentifier, timer, timeRangeWithZoomModel, stringMessages,
errorReporter, true, true, leaderboardGroupName, leaderboardName);
@@ -324,18 +333,23 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
windChart.setVisible(false);
windChart.getEntryWidget().setTitle(stringMessages.windChart());
componentsForSideBySideViewer.add(windChart);
editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier, stringMessages,
competitorSelectionProvider, errorReporter, timer);
}
editMarkPassingPanel = new EditMarkPassingsPanel(sailingService, selectedRaceIdentifier, stringMessages,
competitorSelectionProvider, errorReporter, timer);
if (showChartMarkEditMediaButtonsAndVideo) {
editMarkPassingPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
componentsForSideBySideViewer.add(editMarkPassingPanel);
editMarkPositionPanel = new EditMarkPositionPanel(raceMap, leaderboardPanel, selectedRaceIdentifier, leaderboardName, stringMessages, sailingService, timer, timeRangeWithZoomModel,
asyncActionsExecutor, errorReporter);
}
editMarkPositionPanel = new EditMarkPositionPanel(raceMap, leaderboardPanel, selectedRaceIdentifier, leaderboardName, stringMessages, sailingService, timer, timeRangeWithZoomModel,
asyncActionsExecutor, errorReporter);
if (showChartMarkEditMediaButtonsAndVideo) {
editMarkPositionPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
componentsForSideBySideViewer.add(editMarkPositionPanel);
}
mediaPlayerManagerComponent = new MediaPlayerManagerComponent(mediaPlayerLifecycle,
selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages,
errorReporter, userAgent, this, mediaPlayerSettings);
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent,
@@ -345,11 +359,7 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
mainPanel.add(leaderboardAndMapViewer.getViewerWidget());
boolean showLeaderboard = getPerspectiveSettings().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard;
setLeaderboardVisible(showLeaderboard);
if (getPerspectiveSettings().isChartSupportEnabled()) {
setWindChartVisible(getPerspectiveSettings().isShowWindChart());
setCompetitorChartVisible(getPerspectiveSettings().isShowCompetitorsChart());
}
if (getPerspectiveSettings().isShowChartMarkEditMediaButtonsAndVideo()) {
if (showChartMarkEditMediaButtonsAndVideo) {
setWindChartVisible(getPerspectiveSettings().isShowWindChart());
setCompetitorChartVisible(getPerspectiveSettings().isShowCompetitorsChart());
}
@@ -1,7 +1,5 @@
package com.sap.sailing.gwt.ui.raceboard;
import com.google.gwt.dom.client.Document;
import com.sap.sailing.gwt.common.client.formfactor.DeviceDetector;
import com.sap.sse.common.Duration;
import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.settings.AbstractSettings;
@@ -16,20 +14,11 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
private final boolean showLeaderboard;
private final boolean showWindChart;
private final boolean showCompetitorsChart;
// Determine if the charts, such as the competitor chart or the wind chart, the edit marks
// panels, such as mark passing and mark position editors and manage media buttons should be shown.
// Automatic selection of attached video (if any) also depends on this flag.
// The decision is made once during initial page load based on the device type (mobile or not).
private final boolean showChartMarkEditMediaButtonsAndVideo;
private final String activeCompetitorsFilterSetName;
private final boolean canReplayDuringLiveRaces;
private final boolean simulationEnabled;
private final Duration initialDurationAfterRaceStartInReplay;
/** indicates whether it's enabled to display charts or not */
private final boolean chartSupportEnabled;
public static final String PARAM_VIEW_MODE = "viewMode";
public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard";
public static final String PARAM_VIEW_SHOW_NAVIGATION_PANEL = "viewShowNavigationPanel";
@@ -45,23 +34,19 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
public RaceBoardPerspectiveSettings() {
this(/* activeCompetitorsFilterSetName */null, /* showLeaderboard */true,
/* showWindChart */false, /* showCompetitorsChart */false,
/* simulationEnabled */true, /* canReplayDuringLiveRaces */false, /* chartSupportEnabled */ true,
/* showChartMarkEditMediaButtonsAndVideo */ !DeviceDetector.isMobile(),
/* simulationEnabled */true, /* canReplayDuringLiveRaces */false,
/* initialDurationAfterRaceStartInReplay */ null);
}
public RaceBoardPerspectiveSettings(String activeCompetitorsFilterSetName, boolean showLeaderboard,
boolean showWindChart, boolean showCompetitorsChart, boolean simulationEnabled, boolean canReplayDuringLiveRaces,
boolean chartSupportEnabled, boolean showChartMarkEditMediaButtonsAndVideo,
Duration initialDurationAfterRaceStartInReplay) {
boolean showWindChart, boolean showCompetitorsChart, boolean simulationEnabled,
boolean canReplayDuringLiveRaces, Duration initialDurationAfterRaceStartInReplay) {
this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName;
this.showLeaderboard = showLeaderboard;
this.showWindChart = showWindChart;
this.showCompetitorsChart = showCompetitorsChart;
this.simulationEnabled = simulationEnabled;
this.canReplayDuringLiveRaces = canReplayDuringLiveRaces;
this.chartSupportEnabled = chartSupportEnabled;
this.showChartMarkEditMediaButtonsAndVideo = showChartMarkEditMediaButtonsAndVideo;
this.initialDurationAfterRaceStartInReplay = initialDurationAfterRaceStartInReplay;
}
@@ -89,10 +74,6 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
return canReplayDuringLiveRaces;
}
public boolean isChartSupportEnabled() {
return chartSupportEnabled;
}
public static RaceBoardPerspectiveSettings readSettingsFromURL() {
final boolean showLeaderboard = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_SHOW_LEADERBOARD, true /* default */);
final boolean showWindChart = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_SHOW_WINDCHART, false /* default */);
@@ -101,22 +82,11 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(PARAM_VIEW_COMPETITOR_FILTER, null /* default */);
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(PARAM_CAN_REPLAY_DURING_LIVE_RACES, false /* default */);
// Determine if the screen is large enough to display charts such as the competitor chart or the wind chart.
// This decision is made once based on the initial screen height. Resizing the window afterwards will have
// no impact on the chart support, i.e. they are available/unavailable based on the initial decision.
boolean isScreenLargeEnoughToOfferChartSupport = Document.get().getClientHeight() >= 600;
final boolean chartSupportEnabled = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_CHART_SUPPORT_ENABLED, isScreenLargeEnoughToOfferChartSupport);
final Duration initialDurationAfterRaceStartInReplay = parseDuration(GwtHttpRequestUtils.getStringParameter(
PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS, null /* default */));
return new RaceBoardPerspectiveSettings(activeCompetitorsFilterSetName, showLeaderboard, showWindChart,
showCompetitorsChart, simulationEnabled, canReplayWhileLiveIsPossible, chartSupportEnabled,
!DeviceDetector.isMobile(), initialDurationAfterRaceStartInReplay);
}
public boolean isShowChartMarkEditMediaButtonsAndVideo() {
return showChartMarkEditMediaButtonsAndVideo;
showCompetitorsChart, simulationEnabled, canReplayWhileLiveIsPossible, initialDurationAfterRaceStartInReplay);
}
public Duration getInitialDurationAfterRaceStartInReplay() {
@@ -26,15 +26,15 @@ public class RaceBoardPerspectiveSettingsDialogComponent implements SettingsDial
public Widget getAdditionalWidget(DataEntryDialog<?> dialog) {
VerticalPanel vp = new VerticalPanel();
showLeaderboardCheckBox = dialog.createCheckbox(stringMessages.show() + " " + stringMessages.leaderboard());
showLeaderboardCheckBox = dialog.createCheckbox(stringMessages.showLeaderboard());
showLeaderboardCheckBox.setValue(initialSettings.isShowLeaderboard());
vp.add(showLeaderboardCheckBox);
showWindChartCheckBox = dialog.createCheckbox(stringMessages.show() + " " + stringMessages.windChart());
showWindChartCheckBox = dialog.createCheckbox(stringMessages.showWindChart());
showWindChartCheckBox.setValue(initialSettings.isShowWindChart());
vp.add(showWindChartCheckBox);
showCompetitorsChartCheckBox = dialog.createCheckbox(stringMessages.show() + " " + stringMessages.competitorCharts());
showCompetitorsChartCheckBox = dialog.createCheckbox(stringMessages.showCompetitorCharts());
showCompetitorsChartCheckBox.setValue(initialSettings.isShowCompetitorsChart());
vp.add(showCompetitorsChartCheckBox);
@@ -45,8 +45,7 @@ public class RaceBoardPerspectiveSettingsDialogComponent implements SettingsDial
public RaceBoardPerspectiveSettings getResult() {
RaceBoardPerspectiveSettings result = new RaceBoardPerspectiveSettings(initialSettings.getActiveCompetitorsFilterSetName(),
showLeaderboardCheckBox.getValue(), showWindChartCheckBox.getValue(), showCompetitorsChartCheckBox.getValue(),
initialSettings.isSimulationEnabled(), initialSettings.isCanReplayDuringLiveRaces(), initialSettings.isChartSupportEnabled(),
initialSettings.isShowChartMarkEditMediaButtonsAndVideo(),
initialSettings.isSimulationEnabled(), initialSettings.isCanReplayDuringLiveRaces(),
initialSettings.getInitialDurationAfterRaceStartInReplay());
return result;
}
@@ -687,8 +687,12 @@ public class RegattasResource extends AbstractSailingServerResource {
Regatta regatta = findRegattaByName(regattaName);
if (regatta == null) {
response = Response.status(Status.NOT_FOUND)
.entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
.build();
.entity("Could not find a regatta with name '" + StringEscapeUtils.escapeHtml(regattaName) + "'.").type(MediaType.TEXT_PLAIN)
.build();
} else if (!((fromtime != null && totime != null) || (fromtimeasmillis != null && totimeasmillis != null))) {
response = Response.status(Status.NOT_FOUND)
.entity("Either the 'fromtime' and 'totime' or the 'fromtimeasmillis' and 'totimeasmillis' parameter must be set.").type(MediaType.TEXT_PLAIN)
.build();
} else {
RaceDefinition race = findRaceByName(regatta, raceName);
if (race == null) {
@@ -26,8 +26,8 @@
<tr>
<td>Mandatory parameters:</td>
<td>
<div>regattaname</div>
<div>racename</div>
<div>fromtime (ISO format, such as 2014-02-14T10:12:03Z) or fromtimeasmillis (time in milliseconds)</div>
<div>totime (ISO format, such as 2014-02-14T10:12:03Z) or totimeasmillis (time in milliseconds)</div>
</td>
</tr>
<tr>
@@ -35,10 +35,6 @@
<td>
<div>windsource [COMBINED = Default, WEB, EXPEDITION, TRACK_BASED_ESTIMATION, COURSE_BASED, RACECOMMITTEE]</div>
<div>windsourceid (Id of a wind source. For example Igtimi wind sources will have the type=EXPEDITION but each of them has unique ids. If you want to filter by these then you can use this parameter)</div>
<div>fromtime (ISO format, such as 2014-02-14T10:12:03Z)</div>
<div>fromtimeasmillis</div>
<div>totime (ISO format, such as 2014-02-14T10:12:03Z)</div>
<div>totimeasmillis</div>
</td>
</tr>
<tr>
@@ -13,6 +13,7 @@ import com.google.gwt.dom.client.ScriptElement;
* D049941
*/
public class JavaScriptInjector {
// TODO: why not simply use com.google.gwt.core.client.ScriptInjector? Is there specific functionality that isn't provided by the GWT class?
private static HeadElement head;
/**
@@ -1,9 +1,14 @@
package com.sap.sse.gwt.client.mvp;
import com.google.gwt.activity.shared.ActivityManager;
import com.google.gwt.activity.shared.ActivityMapper;
import com.google.gwt.place.shared.Place;
import com.google.web.bindery.event.shared.EventBus;
/**
* Custom {@link ActivityManager} implementation that fires a {@link PlaceChangedEvent} on the given {@link EventBus}
* whenever the current place changed.
*/
public class CustomActivityManager extends DelegatingActivityManager {
private EventBus eventBus;
@@ -10,6 +10,10 @@ import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.web.bindery.event.shared.EventBus;
import com.google.web.bindery.event.shared.SimpleEventBus;
/**
* Custom {@link ActivityManager} implementation that allows hooking into the lifecycle.
*
*/
public class DelegatingActivityManager extends ActivityManager {
private final ActivityManager realActivityManager;
@@ -35,9 +39,19 @@ public class DelegatingActivityManager extends ActivityManager {
realActivityManager.setDisplay(display);
}
/**
* To be overwritten by sublcasses to hook into the lifecycle.
*
* @param activity the activity to be started
*/
protected void beforeActivityStart(Activity activity) {
}
/**
* To be overwritten by sublcasses to hook into the lifecycle.
*
* @param activity the place that has been started
*/
protected void afterPlaceActivation(Place place) {
}
@@ -2,6 +2,9 @@ package com.sap.sse.gwt.client.mvp;
import com.google.gwt.user.client.ui.IsWidget;
/**
* View that shows an application error.
*/
public interface ErrorView extends IsWidget {
}
@@ -12,6 +12,12 @@ import com.sap.sse.gwt.dispatch.shared.commands.Result;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
import com.sap.sse.gwt.dispatch.shared.exceptions.ServerDispatchException;
/**
* Abstract server-side part of the dispatch functionality. Needs to be subclassed in modules that want to use dispatch
* along with a custom DispatchContext.
*
* @param <CTX> the concrete {@link DispatchContext} used by dispatch.
*/
public abstract class AbstractDispatchServlet<CTX extends DispatchContext> extends ProxiedRemoteServiceServlet
implements DispatchRPC<CTX> {
private static final long serialVersionUID = -4279307111608131857L;