Merge branch 'master' into bug3734

This commit is contained in:
Axel Uhl committed 2016-06-23 23:52:54 +02:00
commit 37d1531e37
42 files changed
+596 -120

No files matched your search

@@ -26,8 +26,10 @@ public class RaceLogAttachOnTrackedRaceTest {
private RaceLog raceLog; private RaceLog raceLog;
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
final RaceLog result = this.raceLog;
this.raceLog = null; this.raceLog = null;
return result;
} }
@Override @Override
@@ -121,6 +121,26 @@ public abstract class TrackBasedTest {
*/ */
public static DynamicTrackedRaceImpl createTestTrackedRace(String regattaName, String raceName, String boatClassName, public static DynamicTrackedRaceImpl createTestTrackedRace(String regattaName, String raceName, String boatClassName,
Iterable<Competitor> competitors, TimePoint timePointForFixes, boolean useMarkPassingCalculator) { Iterable<Competitor> competitors, TimePoint timePointForFixes, boolean useMarkPassingCalculator) {
return createTestTrackedRace(regattaName, raceName, boatClassName, competitors, timePointForFixes, useMarkPassingCalculator,
mock(RaceLogResolver.class));
}
/**
* Creates a simple two-lap upwind-downwind course for a race/event with given name and boat class name with the
* competitors specified. The marks are laid out such that the upwind/downwind leg detection should be alright. The
* start line equals the finish line and the leeward gate. Wind is coming from the north. A single wind fix with
* bearing 180deg (from=0deg) is added to the {@link WindSourceType#WEB} wind track using
* <code>timePointForFixes</code> as time point. The leeward gate is located at N54.4680424, E10.234451 and
* N54.4680424, E10.24. The windward mark is located at N54.48, E10.24.
* @param timePointForFixes
* a wind fix will be inserted into the {@link WindSourceType#WEB} wind track which is aligned with the
* course layout; the value of this parameter will be used as the time stamp for this wind fix. Using a
* time that is reasonably within the race time (mark passing times or whatever is collected for the
* tracked race returned by this method) is important because otherwise confidences of wind readouts may
* be ridiculously low.
* @param useMarkPassingCalculator whether or not to use the internal mark passing calculator
*/
public static DynamicTrackedRaceImpl createTestTrackedRace(String regattaName, String raceName, String boatClassName,
Iterable<Competitor> competitors, TimePoint timePointForFixes, boolean useMarkPassingCalculator, RaceLogResolver raceLogResolver) {
BoatClassImpl boatClass = new BoatClassImpl(boatClassName, /* typicallyStartsUpwind */ true); BoatClassImpl boatClass = new BoatClassImpl(boatClassName, /* typicallyStartsUpwind */ true);
Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE, Regatta regatta = new RegattaImpl(EmptyRaceLogStore.INSTANCE, EmptyRegattaLogStore.INSTANCE,
RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null, RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass, /*startDate*/ null, /*endDate*/ null, /* trackedRegattaRegistry */ null,
@@ -143,7 +163,7 @@ public abstract class TrackBasedTest {
EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0, EmptyGPSFixStore.INSTANCE, /* delayToLiveInMillis */ 0,
/* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000, /* millisecondsOverWhichToAverageWind */ 30000, /* millisecondsOverWhichToAverageSpeed */ 30000,
/* delay for wind estimation cache invalidation */ 0, useMarkPassingCalculator, /* delay for wind estimation cache invalidation */ 0, useMarkPassingCalculator,
OneDesignRankingMetric::new, mock(RaceLogResolver.class)); OneDesignRankingMetric::new, raceLogResolver);
// in this simplified artificial course, the top mark is exactly north of the right leeward gate // in this simplified artificial course, the top mark is exactly north of the right leeward gate
DegreePosition topPosition = new DegreePosition(54.48, 10.24); DegreePosition topPosition = new DegreePosition(54.48, 10.24);
TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed TimePoint afterTheRace = new MillisecondsTimePoint(timePointForFixes.asMillis() + 36000000); // 10h after the fix timed
@@ -0,0 +1,78 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Collections;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogDependentStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogImpl;
import com.sap.sailing.domain.abstractlog.race.impl.RaceLogStartTimeEventImpl;
import com.sap.sailing.domain.abstractlog.race.impl.SimpleRaceLogIdentifierImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.tracking.StartTimeChangedListener;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class TrackedRaceStartTimeUpdateForDependentStartTimeTest extends TrackBasedTest {
@Test
public void testStartTimeUpdateForRaceWithDependentStartTime() {
final Competitor hasso = createCompetitor("Hasso");
final RaceLog r1RaceLog = new RaceLogImpl("r1RaceLog");
final RaceLog r2RaceLog = new RaceLogImpl("r2RaceLog");
final RaceLogResolver raceLogResolver = new RaceLogResolver() {
@Override
public RaceLog resolve(SimpleRaceLogIdentifier identifier) {
if (identifier.getRaceColumnName().equals("R1")) {
return r1RaceLog;
} else if (identifier.getRaceColumnName().equals("R2")) {
return r2RaceLog;
}
return null;
}
};
final TrackedRace r1 = createTestTrackedRace("Regatta", "R1", "J/70", Collections.singleton(hasso),
MillisecondsTimePoint.now(), /* useMarkPassingCalculator */ false, raceLogResolver);
final TrackedRace r2 = createTestTrackedRace("Regatta", "R2", "J/70", Collections.singleton(hasso),
MillisecondsTimePoint.now(), /* useMarkPassingCalculator */ false, raceLogResolver);
r1.attachRaceLog(r1RaceLog);
r2.attachRaceLog(r2RaceLog);
final TimePoint[] r1StartTime = new TimePoint[1];
final TimePoint[] r2StartTime = new TimePoint[1];
r1.addStartTimeChangedListener(new StartTimeChangedListener() {
@Override
public void startTimeChanged(TimePoint newTimePoint) throws MalformedURLException, IOException {
r1StartTime[0] = newTimePoint;
}
});
r2.addStartTimeChangedListener(new StartTimeChangedListener() {
@Override
public void startTimeChanged(TimePoint newTimePoint) throws MalformedURLException, IOException {
r2StartTime[0] = newTimePoint;
}
});
final AbstractLogEventAuthor author = new LogEventAuthorImpl("Axel", 0);
final Duration startTimeDiff = Duration.ONE_MINUTE;
r2RaceLog.add(new RaceLogDependentStartTimeEventImpl(MillisecondsTimePoint.now(), author, /* pass */ 0,
new SimpleRaceLogIdentifierImpl(r1.getTrackedRegatta().getRegatta().getName(), "R1", "Default"), startTimeDiff));
assertNull(r2StartTime[0]);
final TimePoint r1StartTimeToSet = MillisecondsTimePoint.now();
r1RaceLog.add(new RaceLogStartTimeEventImpl(r1StartTimeToSet, author, /* pass */ 0, r1StartTimeToSet));
assertNotNull(r1StartTime[0]);
assertEquals(r1StartTimeToSet, r1StartTime[0]);
assertNotNull(r2StartTime[0]);
assertEquals(r1StartTimeToSet.plus(startTimeDiff), r2StartTime[0]);
}
}
@@ -814,7 +814,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
return null;
} }
@Override @Override
@@ -457,7 +457,8 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
return null;
} }
@Override @Override
@@ -700,8 +700,10 @@ public interface TrackedRace extends Serializable, IsManagedByCache<SharedDomain
/** /**
* Detaches the race log associated with this {@link TrackedRace}. * Detaches the race log associated with this {@link TrackedRace}.
*
* @return the race log detached or {@code null} if no race log can be found by the {@code identifier}
*/ */
void detachRaceLog(Serializable identifier); RaceLog detachRaceLog(Serializable identifier);
/** /**
* Detaches the link {@link RaceExecutionOrderProvider} * Detaches the link {@link RaceExecutionOrderProvider}
@@ -23,6 +23,9 @@ import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent; import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ConfirmedFinishPositioningListFinder; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ConfirmedFinishPositioningListFinder;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver; import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogResolver;
import com.sap.sailing.domain.abstractlog.race.state.RaceStateChangedListener;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.BaseRaceStateChangedListener;
import com.sap.sailing.domain.base.BoatClass; import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.CourseBase; import com.sap.sailing.domain.base.CourseBase;
@@ -87,6 +90,15 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
*/ */
private Map<Competitor, CompetitorResult> competitorResultsFromRaceLog; private Map<Competitor, CompetitorResult> competitorResultsFromRaceLog;
/**
* When one or more race logs are attached, changes in those race logs, or in case of dependent start
* times even changes in other race logs, may impact this race's start time. This listener receives those start
* time changes, also those from races that this race's start time depends upon, and triggers an update of
* this race's start time caches. The field is transient, therefore needs no serialization support but needs
* to be restored during at the time of de-serialization.
*/
private transient RaceStateChangedListener raceStateBasedStartTimeChangedListener;
public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines, public DynamicTrackedRaceImpl(TrackedRegatta trackedRegatta, RaceDefinition race, Iterable<Sideline> sidelines,
WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis, WindStore windStore, GPSFixStore gpsFixStore, long delayToLiveInMillis,
long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed, long millisecondsOverWhichToAverageWind, long millisecondsOverWhichToAverageSpeed,
@@ -95,6 +107,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis, super(trackedRegatta, race, sidelines, windStore, gpsFixStore, delayToLiveInMillis,
millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed, millisecondsOverWhichToAverageWind, millisecondsOverWhichToAverageSpeed,
delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver); delayForCacheInvalidationOfWindEstimation, useInternalMarkPassingAlgorithm, rankingMetricConstructor, raceLogResolver);
raceStateBasedStartTimeChangedListener = createRaceStateStartTimeChangeListener();
this.competitorResultsFromRaceLog = new HashMap<>(); this.competitorResultsFromRaceLog = new HashMap<>();
this.logListener = new DynamicTrackedRaceLogListener(this); this.logListener = new DynamicTrackedRaceLogListener(this);
if (markPassingCalculator != null) { if (markPassingCalculator != null) {
@@ -126,6 +139,7 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
*/ */
private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException {
ois.defaultReadObject(); ois.defaultReadObject();
raceStateBasedStartTimeChangedListener = createRaceStateStartTimeChangeListener();
listeners = new HashSet<RaceChangeListener>(); listeners = new HashSet<RaceChangeListener>();
logListener = new DynamicTrackedRaceLogListener(this); logListener = new DynamicTrackedRaceLogListener(this);
courseDesignChangedListeners = new HashSet<>(); courseDesignChangedListeners = new HashSet<>();
@@ -141,6 +155,19 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
return this; return this;
} }
private RaceStateChangedListener createRaceStateStartTimeChangeListener() {
return new BaseRaceStateChangedListener() {
@Override
public void onStartTimeChanged(ReadonlyRaceState state) {
final TimePoint oldStartTime = getStartOfRace();
updateStartOfRaceCacheFields();
if (!Util.equalsWithNull(oldStartTime, getStartOfRace())) {
onStartTimeChangedByRaceCommittee(getStartOfRace());
}
}
};
}
/** /**
* {@link #raceIsKnownToStartUpwind} (see also {@link #raceIsKnownToStartUpwind()}) is initialized based on the <code>race</code>'s * {@link #raceIsKnownToStartUpwind} (see also {@link #raceIsKnownToStartUpwind()}) is initialized based on the <code>race</code>'s
* {@link RaceDefinition#getBoatClass()} boat class's {@link BoatClass#typicallyStartsUpwind()} result. It can be changed * {@link RaceDefinition#getBoatClass()} boat class's {@link BoatClass#typicallyStartsUpwind()} result. It can be changed
@@ -957,15 +984,24 @@ DynamicTrackedRace, GPSTrackListener<Competitor, GPSFixMoving> {
public void attachRaceLog(RaceLog raceLog) { public void attachRaceLog(RaceLog raceLog) {
logListener.addTo(raceLog); logListener.addTo(raceLog);
super.attachRaceLog(raceLog); super.attachRaceLog(raceLog);
getRaceState(raceLog).addChangedListener(raceStateBasedStartTimeChangedListener);
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
RaceLog attachedRaceLog = attachedRaceLogs.get(identifier); final RaceLog attachedRaceLog = attachedRaceLogs.get(identifier);
if (attachedRaceLog != null) { if (attachedRaceLog != null) {
logListener.removeFrom(attachedRaceLog); logListener.removeFrom(attachedRaceLog);
} }
super.detachRaceLog(identifier); final RaceLog raceLogDetached = super.detachRaceLog(identifier);
assert raceLogDetached == attachedRaceLog;
synchronized (raceStates) {
final ReadonlyRaceState raceState = raceStates.remove(attachedRaceLog);
if (raceState != null) {
raceState.removeChangedListener(raceStateBasedStartTimeChangedListener);
}
}
return attachedRaceLog;
} }
@Override @Override
@@ -403,7 +403,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
* must be established again after de-serialization by invoking {@link #setRaceLogResolver}. * must be established again after de-serialization by invoking {@link #setRaceLogResolver}.
*/ */
private transient RaceLogResolver raceLogResolver; private transient RaceLogResolver raceLogResolver;
/** /**
* Constructs the tracked race with one-design ranking. * Constructs the tracked race with one-design ranking.
*/ */
@@ -565,7 +565,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
logger.log(Level.SEVERE, "Waiting for loading from stores to finish was interrupted", e); logger.log(Level.SEVERE, "Waiting for loading from stores to finish was interrupted", e);
} }
} }
@Override @Override
public RankingMetric getRankingMetric() { public RankingMetric getRankingMetric() {
return rankingMetric; return rankingMetric;
@@ -905,7 +905,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
* and not {@link Object}. * and not {@link Object}.
*/ */
private final String updateStartOfRaceCacheFieldsMonitor = ""; private final String updateStartOfRaceCacheFieldsMonitor = "";
private void updateStartOfRaceCacheFields() { protected void updateStartOfRaceCacheFields() {
synchronized (updateStartOfRaceCacheFieldsMonitor) { synchronized (updateStartOfRaceCacheFieldsMonitor) {
TimePoint newStartTime = null; TimePoint newStartTime = null;
TimePoint newStartTimeWithoutInferenceFromStartMarkPassings = null; TimePoint newStartTimeWithoutInferenceFromStartMarkPassings = null;
@@ -3513,7 +3513,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
return !attachedRaceExecutionOrderProviders.isEmpty(); return !attachedRaceExecutionOrderProviders.isEmpty();
} }
private ReadonlyRaceState getRaceState(RaceLog raceLog) { protected ReadonlyRaceState getRaceState(RaceLog raceLog) {
ReadonlyRaceState result; ReadonlyRaceState result;
synchronized (raceStates) { synchronized (raceStates) {
result = raceStates.get(raceLog); result = raceStates.get(raceLog);
@@ -3539,10 +3539,11 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
this.attachedRaceLogs.remove(identifier); final RaceLog raceLog = this.attachedRaceLogs.remove(identifier);
updateStartOfRaceCacheFields(); updateStartOfRaceCacheFields();
updateStartAndEndOfTracking(/* waitForGPSFixesToLoad */ false); updateStartAndEndOfTracking(/* waitForGPSFixesToLoad */ false);
return raceLog;
} }
@Override @Override
@@ -572,7 +572,8 @@ public class MockedTrackedRace implements DynamicTrackedRace {
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
return null;
} }
@Override @Override
@@ -127,7 +127,7 @@ public class AutoPlayController implements RaceTimesInfoProviderListener, Leader
sailingService, mediaService, userService, asyncActionsExecutor, sailingService, mediaService, userService, asyncActionsExecutor,
result.getCompetitorAndTheirBoats(), raceboardTimer, currentLiveRace, autoPlayerConfiguration.getLeaderboardName(), result.getCompetitorAndTheirBoats(), raceboardTimer, currentLiveRace, autoPlayerConfiguration.getLeaderboardName(),
/** leaderboardGroupName */ null, /** eventId */ null, errorReporter, /** leaderboardGroupName */ null, /** eventId */ null, errorReporter,
StringMessages.INSTANCE, userAgent, raceTimesInfoProvider); StringMessages.INSTANCE, userAgent, raceTimesInfoProvider, true);
playerView.setContent(raceboardPerspective); playerView.setContent(raceboardPerspective);
@@ -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.commands.Result;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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> { public interface SailingAction<R extends Result> extends Action<R, SailingDispatchContext> {
@GwtIncompatible @GwtIncompatible
R execute(SailingDispatchContext ctx) throws DispatchException; 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.sailing.server.RacingEventService;
import com.sap.sse.gwt.dispatch.client.system.DispatchContext; 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 { public interface SailingDispatchContext extends DispatchContext {
@GwtIncompatible @GwtIncompatible
RacingEventService getRacingEventService(); 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.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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 public class GetCompetitionFormatRacesAction implements
SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable { SailingAction<ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>>>, IsClientCacheable {
@@ -22,6 +34,12 @@ public class GetCompetitionFormatRacesAction implements
protected GetCompetitionFormatRacesAction() { 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) { public GetCompetitionFormatRacesAction(UUID eventId, String regattaId) {
this.eventId = eventId; this.eventId = eventId;
this.regattaId = regattaId; this.regattaId = regattaId;
@@ -8,6 +8,12 @@ import com.sap.sailing.gwt.server.EventListDataCalculator;
import com.sap.sailing.gwt.server.HomeServiceUtil; import com.sap.sailing.gwt.server.HomeServiceUtil;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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 { public class GetEventListViewAction implements SailingAction<EventListViewDTO>, IsClientCacheable {
@Override @Override
@GwtIncompatible @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.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; 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>>>, public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<SortedSetResult<RaceListRaceDTO>>>,
IsClientCacheable { IsClientCacheable {
@@ -22,6 +34,12 @@ public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<Sorte
private GetFinishedRacesAction() { 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) { public GetFinishedRacesAction(UUID eventId, String regattaId) {
this.eventId = eventId; this.eventId = eventId;
this.regattaId = regattaId; 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.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext; import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil; 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.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.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL; import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; 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>>>, public class GetLiveRacesForEventAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable { IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -21,6 +37,12 @@ public class GetLiveRacesForEventAction implements SailingAction<ResultWithTTL<S
private GetLiveRacesForEventAction() { 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) { public GetLiveRacesForEventAction(UUID eventId) {
this.eventId = 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.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext; import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil; 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.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.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL; import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; 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>>>, public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL<SortedSetResult<LiveRaceDTO>>>,
IsClientCacheable { IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -21,7 +37,13 @@ public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL
@SuppressWarnings("unused") @SuppressWarnings("unused")
private GetLiveRacesForRegattaAction() { 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) { public GetLiveRacesForRegattaAction(UUID eventId, String regattaName) {
this.eventId = eventId; this.eventId = eventId;
this.regattaName = regattaName; 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.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO; import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil; 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.EventActionUtil.LeaderboardCallback;
import com.sap.sailing.gwt.home.server.LeaderboardContext;
import com.sap.sse.common.Duration; import com.sap.sse.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.commands.SortedSetResult; 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>>>, public class GetRegattaListViewAction implements SailingAction<ResultWithTTL<SortedSetResult<RegattaWithProgressDTO>>>,
IsClientCacheable { IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -24,6 +35,12 @@ public class GetRegattaListViewAction implements SailingAction<ResultWithTTL<Sor
private GetRegattaListViewAction() { 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) { public GetRegattaListViewAction(UUID eventId) {
this.eventId = 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.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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 { public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -20,6 +30,12 @@ public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<E
protected GetRegattaStatisticsAction() { 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) { public GetRegattaStatisticsAction(UUID eventId, String regattaId) {
this.eventId = eventId; this.eventId = eventId;
this.regattaId = regattaId; 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.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO; import com.sap.sailing.gwt.home.communication.regatta.RegattaWithProgressDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil; 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.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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.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 { public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL<RegattaWithProgressDTO>>, IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -20,6 +33,12 @@ public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL
private GetRegattaWithProgressAction() { 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) { public GetRegattaWithProgressAction(UUID eventId, String regattaId) {
this.eventId = eventId; this.eventId = eventId;
this.regattaId = regattaId; 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.SailingDispatchContext;
import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO; import com.sap.sailing.gwt.home.communication.eventview.RegattaMetadataDTO;
import com.sap.sailing.gwt.home.server.EventActionUtil; 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.LeaderboardCallback;
import com.sap.sailing.gwt.home.server.EventActionUtil.RaceCallback; 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.sailing.gwt.server.HomeServiceUtil;
import com.sap.sse.common.Duration; import com.sap.sse.common.Duration;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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.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>>, public class GetRegattasAndLiveRacesForEventAction implements SailingAction<ResultWithTTL<RegattasAndLiveRacesDTO>>,
IsClientCacheable { IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -30,6 +40,12 @@ public class GetRegattasAndLiveRacesForEventAction implements SailingAction<Resu
private GetRegattasAndLiveRacesForEventAction() { 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) { public GetRegattasAndLiveRacesForEventAction(UUID eventId) {
this.eventId = 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.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext; 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.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.EventActionUtil;
import com.sap.sailing.gwt.home.server.StatisticsCalculator; import com.sap.sailing.gwt.home.server.StatisticsCalculator;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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 { public class GetSeriesStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID seriesId; private UUID seriesId;
@@ -19,6 +30,12 @@ public class GetSeriesStatisticsAction implements SailingAction<ResultWithTTL<Ev
protected GetSeriesStatisticsAction() { 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) { public GetSeriesStatisticsAction(UUID seriesId) {
this.seriesId = seriesId; this.seriesId = seriesId;
} }
@@ -3,12 +3,24 @@ package com.sap.sailing.gwt.home.communication.event.minileaderboard;
import java.util.UUID; import java.util.UUID;
import com.google.gwt.core.shared.GwtIncompatible; 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.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext; import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
import com.sap.sailing.gwt.home.server.EventActionUtil; import com.sap.sailing.gwt.home.server.EventActionUtil;
import com.sap.sse.gwt.dispatch.shared.caching.IsClientCacheable; 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.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 { public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
private UUID eventId; private UUID eventId;
private String leaderboardName; private String leaderboardName;
@@ -18,10 +30,30 @@ public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetM
private GetMiniLeaderbordAction() { 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) { public GetMiniLeaderbordAction(UUID eventId, String leaderboardName) {
this(eventId, leaderboardName, 0); 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) { public GetMiniLeaderbordAction(UUID eventId, String leaderboardName, int limit) {
this.eventId = eventId; this.eventId = eventId;
this.leaderboardName = leaderboardName; 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.caching.IsClientCacheable;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL; 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 { public class GetMiniOverallLeaderbordAction implements SailingAction<ResultWithTTL<GetMiniLeaderboardDTO>>, IsClientCacheable {
private UUID seriesId; private UUID seriesId;
private int limit = 0; private int limit = 0;
@@ -17,10 +28,26 @@ public class GetMiniOverallLeaderbordAction implements SailingAction<ResultWithT
private GetMiniOverallLeaderbordAction() { 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) { public GetMiniOverallLeaderbordAction(UUID seriesId, int limit) {
this.seriesId = seriesId; this.seriesId = seriesId;
this.limit = limit; 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.domain.base.Event;
import com.sap.sailing.gwt.home.communication.SailingAction; import com.sap.sailing.gwt.home.communication.SailingAction;
import com.sap.sailing.gwt.home.communication.SailingDispatchContext; 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;
import com.sap.sailing.gwt.home.server.EventActionUtil.CalculationWithEvent; import com.sap.sailing.gwt.home.server.EventActionUtil.CalculationWithEvent;
import com.sap.sailing.news.EventNewsItem; 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.ListResult;
import com.sap.sse.gwt.dispatch.shared.commands.ResultWithTTL; 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 { public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<ListResult<NewsEntryDTO>>>, IsClientCacheable {
private UUID eventId; private UUID eventId;
/** /**
@@ -29,10 +45,26 @@ public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<L
private GetEventOverviewNewsAction() { 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) { public GetEventOverviewNewsAction(UUID eventId) {
this.eventId = 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) { public GetEventOverviewNewsAction(UUID eventId, int limit) {
this.eventId = eventId; this.eventId = eventId;
this.limit = limit; 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.commands.ResultWithTTL;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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 { public class GetEventStatisticsAction implements SailingAction<ResultWithTTL<EventStatisticsDTO>>, IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -18,6 +28,12 @@ public class GetEventStatisticsAction implements SailingAction<ResultWithTTL<Eve
protected GetEventStatisticsAction() { 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) { public GetEventStatisticsAction(UUID eventId) {
this.eventId = 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.gwt.dispatch.shared.exceptions.DispatchException;
import com.sap.sse.shared.media.ImageDescriptor; 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 { public class GetEventSeriesViewAction implements SailingAction<EventSeriesViewDTO>, IsClientCacheable {
private UUID id; private UUID id;
@@ -27,6 +33,12 @@ public class GetEventSeriesViewAction implements SailingAction<EventSeriesViewDT
private GetEventSeriesViewAction() { 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) { public GetEventSeriesViewAction(UUID id) {
super(); super();
this.id = id; 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.ImageDescriptor;
import com.sap.sse.shared.media.VideoDescriptor; 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 { public class GetMediaForEventAction implements SailingAction<MediaDTO>, IsClientCacheable {
private UUID eventId; private UUID eventId;
@@ -23,6 +29,12 @@ public class GetMediaForEventAction implements SailingAction<MediaDTO>, IsClient
private GetMediaForEventAction() { 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) { public GetMediaForEventAction(UUID eventId) {
this.eventId = 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.commands.ListResult;
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException; 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 { public class GetRecentEventsAction implements SailingAction<ListResult<EventQuickfinderDTO>>, IsClientCacheable {
private int limit; private int limit;
@@ -22,6 +28,12 @@ public class GetRecentEventsAction implements SailingAction<ListResult<EventQuic
protected GetRecentEventsAction() { 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) { public GetRecentEventsAction(int limit) {
this.limit = limit; this.limit = limit;
} }
@@ -101,7 +101,11 @@ public class MultiRegattaListStepsBody extends UIObject implements RequiresResiz
String[] tokens = seriesName.split(" "); String[] tokens = seriesName.split(" ");
StringBuilder initials = new StringBuilder(); StringBuilder initials = new StringBuilder();
for (int i = 0; i < tokens.length; i++) { for (int i = 0; i < tokens.length; i++) {
initials.append(tokens[i].charAt(0)); if (tokens[i].isEmpty()) { // this may happen, e.g., in case of a FlexibleLeaderboard that does not have a series
initials.append('R');
} else {
initials.append(tokens[i].charAt(0));
}
} }
return initials.toString(); return initials.toString();
} }
@@ -2,12 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.event.multiregatta.mediatab;
import com.google.gwt.place.shared.Prefix; import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.multiregatta.AbstractMultiregattaEventPlace; 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.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace; import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext; 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) { public MultiregattaMediaPlace(String id) {
super(id); super(id);
} }
@@ -23,9 +23,4 @@ public class MultiregattaMediaPlace extends AbstractMultiregattaEventPlace imple
return new MultiregattaMediaPlace(context); return new MultiregattaMediaPlace(context);
} }
} }
@Override
public boolean hasMobileVersion() {
return true;
}
} }
@@ -2,12 +2,12 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta.mediatab;
import com.google.gwt.place.shared.Prefix; import com.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace; 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.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace; import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext; 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) { public RegattaMediaPlace(String id, String regattaId) {
super(id, regattaId); super(id, regattaId);
} }
@@ -29,9 +29,4 @@ public class RegattaMediaPlace extends AbstractEventRegattaPlace implements Mobi
return new RegattaMediaPlace(context); 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.google.gwt.place.shared.Prefix;
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace; 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.PlaceTokenPrefixes;
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace; import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
import com.sap.sailing.gwt.home.shared.places.event.EventContext; 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) { public RegattaRacesPlace(String id, String leaderboardName) {
super(id, leaderboardName); super(id, leaderboardName);
} }
@@ -28,9 +28,4 @@ public class RegattaRacesPlace extends AbstractEventRegattaPlace implements Mobi
return new RegattaRacesPlace(context); return new RegattaRacesPlace(context);
} }
} }
@Override
public boolean hasMobileVersion() {
return true;
}
} }
@@ -82,6 +82,19 @@ public final class EventActionUtil {
return new LeaderboardContext(context, event, leaderboardGroups, leaderboard); 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) { public static Duration getEventStateDependentTTL(SailingDispatchContext context, UUID eventId, Duration liveTTL) {
Event event = context.getRacingEventService().getEvent(eventId); Event event = context.getRacingEventService().getEvent(eventId);
return getEventStateDependentTTL(event, liveTTL); return getEventStateDependentTTL(event, liveTTL);
@@ -104,6 +117,25 @@ public final class EventActionUtil {
return callback.calculateWithEvent(event); 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) { public static Duration calculateTtlForNonLiveEvent(Event event, EventState eventState) {
TimePoint now = MillisecondsTimePoint.now(); TimePoint now = MillisecondsTimePoint.now();
if(eventState == EventState.UPCOMING || eventState == EventState.PLANNED) { if(eventState == EventState.UPCOMING || eventState == EventState.PLANNED) {
@@ -444,7 +444,7 @@ scoringSchemeHighPointFirstGetsTen=High Point, winner gets 10 points
scoringSchemeHighPointFirstGetsTenOrEight=High Point, winner gets 10 points (or 8) 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. 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) 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 scoringSystem=Scoring system
createFlexibleLeaderboard=Create flexible leaderboard createFlexibleLeaderboard=Create flexible leaderboard
createRegattaLeaderboard=Create regatta leaderboard createRegattaLeaderboard=Create regatta leaderboard
@@ -20,7 +20,7 @@ public class MediaPlayerLifecycle implements ComponentLifecycle<MediaPlayerSetti
@Override @Override
public MediaPlayerSettings createDefaultSettings() { public MediaPlayerSettings createDefaultSettings() {
return new MediaPlayerSettings(); return MediaPlayerSettings.readSettingsFromURL();
} }
@Override @Override
@@ -1,5 +1,6 @@
package com.sap.sailing.gwt.ui.client.media; 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.common.settings.AbstractSettings;
import com.sap.sse.gwt.shared.GwtHttpRequestUtils; import com.sap.sse.gwt.shared.GwtHttpRequestUtils;
@@ -8,11 +9,8 @@ public class MediaPlayerSettings extends AbstractSettings {
public static final String PARAM_AUTOPLAY_MEDIA = "autoSelectMedia"; public static final String PARAM_AUTOPLAY_MEDIA = "autoSelectMedia";
/**
* The default settings
*/
public MediaPlayerSettings() { public MediaPlayerSettings() {
this.autoPlayMedia = true; this.autoPlayMedia = !DeviceDetector.isMobile();
} }
public MediaPlayerSettings(boolean autoPlayMedia) { public MediaPlayerSettings(boolean autoPlayMedia) {
@@ -24,7 +22,7 @@ public class MediaPlayerSettings extends AbstractSettings {
} }
public static MediaPlayerSettings readSettingsFromURL() { 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); return new MediaPlayerSettings(autoPlayMedia);
} }
@@ -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.DockLayoutPanel;
import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootLayoutPanel; 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.AbstractSailingEntryPoint;
import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel; import com.sap.sailing.gwt.ui.client.LogoAndTitlePanel;
import com.sap.sailing.gwt.ui.client.MediaService; 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.async.AsyncActionsExecutor;
import com.sap.sse.gwt.client.player.Timer; import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes; 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; import com.sap.sse.gwt.client.shared.perspective.PerspectiveLifecycleWithAllSettings;
public class RaceBoardEntryPoint extends AbstractSailingEntryPoint { public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
@@ -74,6 +76,11 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
// read perspective settings parameters from URL // read perspective settings parameters from URL
final RaceBoardPerspectiveSettings perspectiveSettings = RaceBoardPerspectiveSettings.readSettingsFromURL(); 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>() { sailingService.getRaceboardData(regattaName, raceName, leaderboardName, leaderboardGroupName, eventId, new AsyncCallback<RaceboardDataDTO>() {
@Override @Override
@@ -100,7 +107,7 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
return; return;
} }
createPerspectivePage(raceboardData, perspectiveSettings); createPerspectivePage(raceboardData, perspectiveSettings, showChartMarkEditMediaButtonsAndVideo);
} }
@Override @Override
@@ -119,7 +126,8 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
vp.add(new Label(message)); vp.add(new Label(message));
} }
private void createPerspectivePage(RaceboardDataDTO raceboardData, RaceBoardPerspectiveSettings perspectiveSettings) { private void createPerspectivePage(RaceboardDataDTO raceboardData, RaceBoardPerspectiveSettings perspectiveSettings,
boolean showChartMarkEditMediaButtonsAndVideo) {
selectedRace = raceboardData.getRace(); selectedRace = raceboardData.getRace();
Window.setTitle(selectedRace.getName()); Window.setTitle(selectedRace.getName());
Timer timer = new Timer(PlayModes.Replay, 1000l); Timer timer = new Timer(PlayModes.Replay, 1000l);
@@ -128,13 +136,18 @@ public class RaceBoardEntryPoint extends AbstractSailingEntryPoint {
Collections.singletonList(selectedRace.getRaceIdentifier()), 5000l /* requestInterval*/); Collections.singletonList(selectedRace.getRaceIdentifier()), 5000l /* requestInterval*/);
RaceBoardPerspectiveLifecycle raceboardPerspectiveLifecycle = new RaceBoardPerspectiveLifecycle(null, StringMessages.INSTANCE); 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, PerspectiveLifecycleWithAllSettings<RaceBoardPerspectiveLifecycle, RaceBoardPerspectiveSettings> raceboardPerspectiveLifecyclesAndSettings = new PerspectiveLifecycleWithAllSettings<>(raceboardPerspectiveLifecycle,
raceboardPerspectiveLifecycle.createDefaultSettings()); perspectiveCompositeSettings);
RaceBoardPanel raceBoardPerspective = new RaceBoardPanel( RaceBoardPanel raceBoardPerspective = new RaceBoardPanel(raceboardPerspectiveLifecyclesAndSettings,
raceboardPerspectiveLifecyclesAndSettings, sailingService, mediaService, getUserService(), sailingService, mediaService, getUserService(), asyncActionsExecutor,
asyncActionsExecutor, raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(), leaderboardName, raceboardData.getCompetitorAndTheirBoats(), timer, selectedRace.getRaceIdentifier(), leaderboardName,
leaderboardGroupName, eventId, RaceBoardEntryPoint.this, getStringMessages(), userAgent, raceTimesInfoProvider); leaderboardGroupName, eventId, RaceBoardEntryPoint.this, getStringMessages(), userAgent,
raceTimesInfoProvider, showChartMarkEditMediaButtonsAndVideo);
RootLayoutPanel.get().add(raceBoardPerspective.getEntryWidget()); 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 * 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 * 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. * 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, public RaceBoardPanel(PerspectiveLifecycleWithAllSettings<RaceBoardPerspectiveLifecycle, RaceBoardPerspectiveSettings> perspectiveLifecycleWithAllSettings,
SailingServiceAsync sailingService, MediaServiceAsync mediaService, SailingServiceAsync sailingService, MediaServiceAsync mediaService, UserService userService,
UserService userService, AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats, AsyncActionsExecutor asyncActionsExecutor, Map<CompetitorDTO, BoatDTO> competitorsAndTheirBoats,
Timer timer, RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName, Timer timer, RegattaAndRaceIdentifier selectedRaceIdentifier, String leaderboardName,
String leaderboardGroupName, UUID eventId, ErrorReporter errorReporter, final StringMessages stringMessages, String leaderboardGroupName, UUID eventId, ErrorReporter errorReporter, final StringMessages stringMessages,
UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider) { UserAgentDetails userAgent, RaceTimesInfoProvider raceTimesInfoProvider,
boolean showChartMarkEditMediaButtonsAndVideo) {
super(perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle(), perspectiveLifecycleWithAllSettings.getPerspectiveSettings()); super(perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle(), perspectiveLifecycleWithAllSettings.getPerspectiveSettings());
this.perspectiveLifecycleWithAllSettings = perspectiveLifecycleWithAllSettings; this.perspectiveLifecycleWithAllSettings = perspectiveLifecycleWithAllSettings;
this.sailingService = sailingService; this.sailingService = sailingService;
@@ -250,7 +255,8 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
leaderboardPanel.setTitle(stringMessages.leaderboard()); leaderboardPanel.setTitle(stringMessages.leaderboard());
leaderboardPanel.getElement().getStyle().setMarginLeft(6, Unit.PX); leaderboardPanel.getElement().getStyle().setMarginLeft(6, Unit.PX);
leaderboardPanel.getElement().getStyle().setMarginTop(10, 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); leaderboardPanel.addLeaderboardUpdateListener(this);
// in case the URL configuration contains the name of a competitors filter set we try to activate it // 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 // 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, racetimePanel = new RaceTimePanel(raceTimePanelLifecycle, userService, timer, timeRangeWithZoomModel,
getPerspectiveSettings().isCanReplayDuringLiveRaces(), getPerspectiveSettings().isChartSupportEnabled(), stringMessages, raceTimesInfoProvider, getPerspectiveSettings().isCanReplayDuringLiveRaces(),
selectedRaceIdentifier, getPerspectiveSettings().getInitialDurationAfterRaceStartInReplay()); showChartMarkEditMediaButtonsAndVideo, selectedRaceIdentifier,
getPerspectiveSettings().getInitialDurationAfterRaceStartInReplay());
racetimePanel.updateSettings(raceTimePanelSettings); racetimePanel.updateSettings(raceTimePanelSettings);
timeRangeWithZoomModel.addTimeZoomChangeListener(racetimePanel); timeRangeWithZoomModel.addTimeZoomChangeListener(racetimePanel);
raceTimesInfoProvider.addRaceTimesInfoProviderListener(racetimePanel); raceTimesInfoProvider.addRaceTimesInfoProviderListener(racetimePanel);
@@ -289,14 +296,16 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
* @param event * @param event
* an optional event; may be <code>null</code> or else can be used to show some context information in * an optional event; may be <code>null</code> or else can be used to show some context information in
* the {@link GlobalNavigationPanel}. * the {@link GlobalNavigationPanel}.
* @param showChartMarkEditMediaButtonsAndVideo
* @param isScreenLargeEnoughToOfferChartSupport * @param isScreenLargeEnoughToOfferChartSupport
* if the screen is large enough to display charts such as the competitor chart or the wind chart, a * 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 * padding is provided for the RaceTimePanel that aligns its right border with that of the charts, and
* the charts are created. * the charts are created.
*/ */
private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event, FlowPanel mainPanel, private void createOneScreenView(String leaderboardName, String leaderboardGroupName, UUID event,
boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard, RaceMap raceMap, UserService userService) { FlowPanel mainPanel, boolean isScreenLargeEnoughToInitiallyDisplayLeaderboard, RaceMap raceMap,
UserService userService, boolean showChartMarkEditMediaButtonsAndVideo) {
MediaPlayerLifecycle mediaPlayerLifecycle = perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle().getMediaPlayerLifecycle(); MediaPlayerLifecycle mediaPlayerLifecycle = perspectiveLifecycleWithAllSettings.getPerspectiveLifecycle().getMediaPlayerLifecycle();
MediaPlayerSettings mediaPlayerSettings = perspectiveLifecycleWithAllSettings.findComponentSettingsByLifecycle(mediaPlayerLifecycle); MediaPlayerSettings mediaPlayerSettings = perspectiveLifecycleWithAllSettings.findComponentSettingsByLifecycle(mediaPlayerLifecycle);
@@ -309,7 +318,7 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
// create the default leaderboard and select the right race // create the default leaderboard and select the right race
raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap); raceTimesInfoProvider.addRaceTimesInfoProviderListener(raceMap);
List<Component<?>> componentsForSideBySideViewer = new ArrayList<Component<?>>(); List<Component<?>> componentsForSideBySideViewer = new ArrayList<Component<?>>();
if (getPerspectiveSettings().isChartSupportEnabled()) { if (showChartMarkEditMediaButtonsAndVideo) {
competitorChart = new MultiCompetitorRaceChart(multiCompetitorRaceChartLifecycle, sailingService, asyncActionsExecutor, competitorChart = new MultiCompetitorRaceChart(multiCompetitorRaceChartLifecycle, sailingService, asyncActionsExecutor,
competitorSelectionProvider, selectedRaceIdentifier, timer, timeRangeWithZoomModel, stringMessages, competitorSelectionProvider, selectedRaceIdentifier, timer, timeRangeWithZoomModel, stringMessages,
errorReporter, true, true, leaderboardGroupName, leaderboardName); errorReporter, true, true, leaderboardGroupName, leaderboardName);
@@ -324,18 +333,23 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
windChart.setVisible(false); windChart.setVisible(false);
windChart.getEntryWidget().setTitle(stringMessages.windChart()); windChart.getEntryWidget().setTitle(stringMessages.windChart());
componentsForSideBySideViewer.add(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.setLeaderboard(leaderboardPanel.getLeaderboard());
editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings()); editMarkPassingPanel.getEntryWidget().setTitle(stringMessages.editMarkPassings());
componentsForSideBySideViewer.add(editMarkPassingPanel); 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()); editMarkPositionPanel.setLeaderboard(leaderboardPanel.getLeaderboard());
componentsForSideBySideViewer.add(editMarkPositionPanel); componentsForSideBySideViewer.add(editMarkPositionPanel);
} }
mediaPlayerManagerComponent = new MediaPlayerManagerComponent(mediaPlayerLifecycle, mediaPlayerManagerComponent = new MediaPlayerManagerComponent(mediaPlayerLifecycle,
selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages, selectedRaceIdentifier, raceTimesInfoProvider, timer, mediaService, userService, stringMessages,
errorReporter, userAgent, this, mediaPlayerSettings); errorReporter, userAgent, this, mediaPlayerSettings);
leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent, leaderboardAndMapViewer = new SideBySideComponentViewer(leaderboardPanel, raceMap, mediaPlayerManagerComponent,
@@ -345,11 +359,7 @@ public class RaceBoardPanel extends AbstractPerspectiveComposite<RaceBoardPerspe
mainPanel.add(leaderboardAndMapViewer.getViewerWidget()); mainPanel.add(leaderboardAndMapViewer.getViewerWidget());
boolean showLeaderboard = getPerspectiveSettings().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard; boolean showLeaderboard = getPerspectiveSettings().isShowLeaderboard() && isScreenLargeEnoughToInitiallyDisplayLeaderboard;
setLeaderboardVisible(showLeaderboard); setLeaderboardVisible(showLeaderboard);
if (getPerspectiveSettings().isChartSupportEnabled()) { if (showChartMarkEditMediaButtonsAndVideo) {
setWindChartVisible(getPerspectiveSettings().isShowWindChart());
setCompetitorChartVisible(getPerspectiveSettings().isShowCompetitorsChart());
}
if (getPerspectiveSettings().isShowChartMarkEditMediaButtonsAndVideo()) {
setWindChartVisible(getPerspectiveSettings().isShowWindChart()); setWindChartVisible(getPerspectiveSettings().isShowWindChart());
setCompetitorChartVisible(getPerspectiveSettings().isShowCompetitorsChart()); setCompetitorChartVisible(getPerspectiveSettings().isShowCompetitorsChart());
} }
@@ -1,7 +1,5 @@
package com.sap.sailing.gwt.ui.raceboard; 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.Duration;
import com.sap.sse.common.impl.MillisecondsDurationImpl; import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.common.settings.AbstractSettings; import com.sap.sse.common.settings.AbstractSettings;
@@ -16,20 +14,11 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
private final boolean showLeaderboard; private final boolean showLeaderboard;
private final boolean showWindChart; private final boolean showWindChart;
private final boolean showCompetitorsChart; 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 String activeCompetitorsFilterSetName;
private final boolean canReplayDuringLiveRaces; private final boolean canReplayDuringLiveRaces;
private final boolean simulationEnabled; private final boolean simulationEnabled;
private final Duration initialDurationAfterRaceStartInReplay; 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_MODE = "viewMode";
public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard"; public static final String PARAM_VIEW_SHOW_LEADERBOARD = "viewShowLeaderboard";
public static final String PARAM_VIEW_SHOW_NAVIGATION_PANEL = "viewShowNavigationPanel"; public static final String PARAM_VIEW_SHOW_NAVIGATION_PANEL = "viewShowNavigationPanel";
@@ -45,23 +34,19 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
public RaceBoardPerspectiveSettings() { public RaceBoardPerspectiveSettings() {
this(/* activeCompetitorsFilterSetName */null, /* showLeaderboard */true, this(/* activeCompetitorsFilterSetName */null, /* showLeaderboard */true,
/* showWindChart */false, /* showCompetitorsChart */false, /* showWindChart */false, /* showCompetitorsChart */false,
/* simulationEnabled */true, /* canReplayDuringLiveRaces */false, /* chartSupportEnabled */ true, /* simulationEnabled */true, /* canReplayDuringLiveRaces */false,
/* showChartMarkEditMediaButtonsAndVideo */ !DeviceDetector.isMobile(),
/* initialDurationAfterRaceStartInReplay */ null); /* initialDurationAfterRaceStartInReplay */ null);
} }
public RaceBoardPerspectiveSettings(String activeCompetitorsFilterSetName, boolean showLeaderboard, public RaceBoardPerspectiveSettings(String activeCompetitorsFilterSetName, boolean showLeaderboard,
boolean showWindChart, boolean showCompetitorsChart, boolean simulationEnabled, boolean canReplayDuringLiveRaces, boolean showWindChart, boolean showCompetitorsChart, boolean simulationEnabled,
boolean chartSupportEnabled, boolean showChartMarkEditMediaButtonsAndVideo, boolean canReplayDuringLiveRaces, Duration initialDurationAfterRaceStartInReplay) {
Duration initialDurationAfterRaceStartInReplay) {
this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName; this.activeCompetitorsFilterSetName = activeCompetitorsFilterSetName;
this.showLeaderboard = showLeaderboard; this.showLeaderboard = showLeaderboard;
this.showWindChart = showWindChart; this.showWindChart = showWindChart;
this.showCompetitorsChart = showCompetitorsChart; this.showCompetitorsChart = showCompetitorsChart;
this.simulationEnabled = simulationEnabled; this.simulationEnabled = simulationEnabled;
this.canReplayDuringLiveRaces = canReplayDuringLiveRaces; this.canReplayDuringLiveRaces = canReplayDuringLiveRaces;
this.chartSupportEnabled = chartSupportEnabled;
this.showChartMarkEditMediaButtonsAndVideo = showChartMarkEditMediaButtonsAndVideo;
this.initialDurationAfterRaceStartInReplay = initialDurationAfterRaceStartInReplay; this.initialDurationAfterRaceStartInReplay = initialDurationAfterRaceStartInReplay;
} }
@@ -89,10 +74,6 @@ public class RaceBoardPerspectiveSettings extends AbstractSettings {
return canReplayDuringLiveRaces; return canReplayDuringLiveRaces;
} }
public boolean isChartSupportEnabled() {
return chartSupportEnabled;
}
public static RaceBoardPerspectiveSettings readSettingsFromURL() { public static RaceBoardPerspectiveSettings readSettingsFromURL() {
final boolean showLeaderboard = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_SHOW_LEADERBOARD, true /* default */); final boolean showLeaderboard = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_SHOW_LEADERBOARD, true /* default */);
final boolean showWindChart = GwtHttpRequestUtils.getBooleanParameter(PARAM_VIEW_SHOW_WINDCHART, false /* 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 */); String activeCompetitorsFilterSetName = GwtHttpRequestUtils.getStringParameter(PARAM_VIEW_COMPETITOR_FILTER, null /* default */);
final boolean canReplayWhileLiveIsPossible = GwtHttpRequestUtils.getBooleanParameter(PARAM_CAN_REPLAY_DURING_LIVE_RACES, false /* 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( final Duration initialDurationAfterRaceStartInReplay = parseDuration(GwtHttpRequestUtils.getStringParameter(
PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS, null /* default */)); PARAM_TIME_AFTER_RACE_START_AS_HOURS_COLON_MILLIS_COLON_SECONDS, null /* default */));
return new RaceBoardPerspectiveSettings(activeCompetitorsFilterSetName, showLeaderboard, showWindChart, return new RaceBoardPerspectiveSettings(activeCompetitorsFilterSetName, showLeaderboard, showWindChart,
showCompetitorsChart, simulationEnabled, canReplayWhileLiveIsPossible, chartSupportEnabled, showCompetitorsChart, simulationEnabled, canReplayWhileLiveIsPossible, initialDurationAfterRaceStartInReplay);
!DeviceDetector.isMobile(), initialDurationAfterRaceStartInReplay);
}
public boolean isShowChartMarkEditMediaButtonsAndVideo() {
return showChartMarkEditMediaButtonsAndVideo;
} }
public Duration getInitialDurationAfterRaceStartInReplay() { public Duration getInitialDurationAfterRaceStartInReplay() {
@@ -45,8 +45,7 @@ public class RaceBoardPerspectiveSettingsDialogComponent implements SettingsDial
public RaceBoardPerspectiveSettings getResult() { public RaceBoardPerspectiveSettings getResult() {
RaceBoardPerspectiveSettings result = new RaceBoardPerspectiveSettings(initialSettings.getActiveCompetitorsFilterSetName(), RaceBoardPerspectiveSettings result = new RaceBoardPerspectiveSettings(initialSettings.getActiveCompetitorsFilterSetName(),
showLeaderboardCheckBox.getValue(), showWindChartCheckBox.getValue(), showCompetitorsChartCheckBox.getValue(), showLeaderboardCheckBox.getValue(), showWindChartCheckBox.getValue(), showCompetitorsChartCheckBox.getValue(),
initialSettings.isSimulationEnabled(), initialSettings.isCanReplayDuringLiveRaces(), initialSettings.isChartSupportEnabled(), initialSettings.isSimulationEnabled(), initialSettings.isCanReplayDuringLiveRaces(),
initialSettings.isShowChartMarkEditMediaButtonsAndVideo(),
initialSettings.getInitialDurationAfterRaceStartInReplay()); initialSettings.getInitialDurationAfterRaceStartInReplay());
return result; return result;
} }
@@ -448,7 +448,8 @@ public class DummyTrackedRace extends TrackedRaceWithWindEssentials {
} }
@Override @Override
public void detachRaceLog(Serializable identifier) { public RaceLog detachRaceLog(Serializable identifier) {
return null;
} }
@Override @Override