mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-23 22:19:13 +00:00
Merge branch 'permission-vertical' into bug4709_pv
This commit is contained in:
+2
-2
@@ -79,8 +79,8 @@ public class SecuredDomainType extends HasPermissionsImpl {
|
||||
public static final HasPermissions RESULT_IMPORT_URL = new SecuredDomainType("RESULT_IMPORT_URL");
|
||||
|
||||
/**
|
||||
* Describes access permissions to {@code ExpeditionDeviceConfiguration} objects. Type-relative
|
||||
* object identifier is the {@code ExpeditionDeviceConfiguration.deviceUuid} property as string.
|
||||
* Describes access permissions to {@code ExpeditionDeviceConfiguration} objects. Type-relative object identifier is
|
||||
* the WildcardPermissionEncoder.encode(getServerInfo().getServerName(), deviceConfiguration.getName());
|
||||
*/
|
||||
public static final HasPermissions EXPEDITION_DEVICE_CONFIGURATION = new SecuredDomainType("EXPEDITION_DEVICE_CONFIGURATION");
|
||||
|
||||
|
||||
+2
-1
@@ -8,13 +8,14 @@ import com.sap.sse.common.NamedWithID;
|
||||
import com.sap.sse.common.Renamable;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.media.ImageSize;
|
||||
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
|
||||
import com.sap.sse.shared.media.WithMedia;
|
||||
|
||||
/**
|
||||
* Base interface for an Event consisting of all static information, which might be shared
|
||||
* by the server and an Android application.
|
||||
*/
|
||||
public interface EventBase extends NamedWithID, WithDescription, Renamable, WithMedia {
|
||||
public interface EventBase extends NamedWithID, WithDescription, Renamable, WithMedia, WithQualifiedObjectIdentifier {
|
||||
|
||||
void setDescription(String description);
|
||||
|
||||
|
||||
+13
@@ -13,6 +13,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.Venue;
|
||||
import com.sap.sailing.domain.common.security.SecuredDomainType;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
@@ -20,6 +21,8 @@ import com.sap.sse.common.media.ImageSize;
|
||||
import com.sap.sse.common.media.MediaTagConstants;
|
||||
import com.sap.sse.common.media.MimeType;
|
||||
import com.sap.sse.concurrent.CopyOnWriteHashMap;
|
||||
import com.sap.sse.security.shared.HasPermissions;
|
||||
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
|
||||
import com.sap.sse.shared.media.ImageDescriptor;
|
||||
import com.sap.sse.shared.media.MediaDescriptor;
|
||||
import com.sap.sse.shared.media.MediaUtils;
|
||||
@@ -368,4 +371,14 @@ public abstract class EventBaseImpl implements EventBase {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QualifiedObjectIdentifier getIdentifier() {
|
||||
return getType().getQualifiedObjectIdentifier(getId().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HasPermissions getType() {
|
||||
return SecuredDomainType.EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,7 @@ import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.security.SecuredDomainType;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sse.security.shared.HasPermissions;
|
||||
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
|
||||
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
|
||||
|
||||
/**
|
||||
* An event is a group of {@link Regatta regattas} carried out at a common venue within a common time frame. For
|
||||
@@ -18,7 +14,7 @@ import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
|
||||
* @author Axel Uhl (D043530)
|
||||
*
|
||||
*/
|
||||
public interface Event extends EventBase, WithQualifiedObjectIdentifier {
|
||||
public interface Event extends EventBase {
|
||||
|
||||
/**
|
||||
* For events, the ID is always a UUID.
|
||||
@@ -74,14 +70,4 @@ public interface Event extends EventBase, WithQualifiedObjectIdentifier {
|
||||
* logo / link on the event's UI representation.
|
||||
*/
|
||||
void setWindFinderReviewedSpotsCollection(Iterable<String> reviewedSpotsCollectionIds);
|
||||
|
||||
@Override
|
||||
default QualifiedObjectIdentifier getIdentifier() {
|
||||
return getType().getQualifiedObjectIdentifier(getId().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
default HasPermissions getType() {
|
||||
return SecuredDomainType.EVENT;
|
||||
}
|
||||
}
|
||||
|
||||
+10
-6
@@ -554,16 +554,20 @@ public class CandidateFinderImpl implements CandidateFinder {
|
||||
new ArrayList<Candidate>(), new ArrayList<Candidate>());
|
||||
TreeSet<GPSFix> affectedFixes = new TreeSet<GPSFix>(comp);
|
||||
GPSFixTrack<Competitor, GPSFixMoving> track = race.getTrack(c);
|
||||
for (GPSFix fix : fixes) {
|
||||
for (GPSFixMoving fix : fixes) {
|
||||
if (timeRangeForValidCandidates.getTimeRangeOrNull() != null && timeRangeForValidCandidates.getTimeRangeOrNull().includes(fix.getTimePoint())) {
|
||||
affectedFixes.add(fix);
|
||||
GPSFix fixBefore;
|
||||
GPSFix fixAfter;
|
||||
GPSFix fixBefore = null;
|
||||
GPSFix fixAfter = null;
|
||||
final boolean fixIsValid;
|
||||
track.lockForRead();
|
||||
try {
|
||||
TimePoint timePoint = fix.getTimePoint();
|
||||
fixBefore = track.getLastFixBefore(timePoint);
|
||||
fixAfter = track.getFirstFixAfter(timePoint);
|
||||
fixIsValid = track.isValid(fix);
|
||||
if (fixIsValid) {
|
||||
TimePoint t = fix.getTimePoint();
|
||||
fixBefore = track.getLastFixBefore(t);
|
||||
fixAfter = track.getFirstFixAfter(t);
|
||||
}
|
||||
} finally {
|
||||
track.unlockAfterRead();
|
||||
}
|
||||
|
||||
+21
-17
@@ -5,10 +5,12 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.google.gwt.place.shared.Place;
|
||||
import com.google.gwt.place.shared.PlaceTokenizer;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public abstract class AbstractMapTokenizer<P extends Place> implements PlaceTokenizer<P> {
|
||||
|
||||
@@ -18,48 +20,50 @@ public abstract class AbstractMapTokenizer<P extends Place> implements PlaceToke
|
||||
public P getPlace(String token) {
|
||||
return getPlaceFromParameters(toParameterMap(token));
|
||||
}
|
||||
|
||||
protected abstract P getPlaceFromParameters(Map<String, String> parameters);
|
||||
|
||||
protected abstract Map<String, String> getParameters(P place);
|
||||
|
||||
protected abstract P getPlaceFromParameters(Map<String, Set<String>> parameters);
|
||||
|
||||
protected abstract Map<String, Set<String>> getParameters(P place);
|
||||
|
||||
@Override
|
||||
public String getToken(P place) {
|
||||
return toToken(getParameters(place));
|
||||
}
|
||||
|
||||
private String toToken(Map<String, String> parameters) {
|
||||
|
||||
private String toToken(Map<String, Set<String>> parameters) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
for (Map.Entry<String, String> entry : parameters.entrySet()) {
|
||||
if(entry.getValue() == null || entry.getValue().isEmpty()) {
|
||||
|
||||
for (Map.Entry<String, Set<String>> entry : parameters.entrySet()) {
|
||||
if (entry.getValue() == null || entry.getValue().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if(stringBuilder.length() > 0) {
|
||||
stringBuilder.append("&");
|
||||
for (String val : entry.getValue()) {
|
||||
if (stringBuilder.length() > 0) {
|
||||
stringBuilder.append("&");
|
||||
}
|
||||
stringBuilder.append(entry.getKey() + "=" + val);
|
||||
}
|
||||
stringBuilder.append(entry.getKey() + "=" + entry.getValue());
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
private Map<String, String> toParameterMap(String placeParametersAsToken) {
|
||||
|
||||
private Map<String, Set<String>> toParameterMap(String placeParametersAsToken) {
|
||||
List<String> list = Arrays.asList(placeParametersAsToken.split("&"));
|
||||
|
||||
|
||||
if (list == null || list.size() < 1) {
|
||||
logger.warning("Token empty, no-op");
|
||||
Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
Map<String, Set<String>> result = new HashMap<>();
|
||||
for (String listItem : list) {
|
||||
String[] nvPair = listItem.split("=");
|
||||
if (nvPair == null || nvPair.length != 2) {
|
||||
logger.warning("Invalid parameters");
|
||||
continue;
|
||||
}
|
||||
result.put(nvPair[0], nvPair[1]);
|
||||
Util.addToValueSet(result, nvPair[0], nvPair[1]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+4
@@ -31,6 +31,10 @@
|
||||
padding: 1.4em .666666666666667em .733333333333333em 1.333333333333333em;
|
||||
}
|
||||
|
||||
.textCellWordWrap {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.buttonCell {
|
||||
text-align: right;
|
||||
vertical-align: middle;
|
||||
|
||||
+2
@@ -13,6 +13,8 @@ public interface DesignedCellTableResources extends CellTable.Resources {
|
||||
|
||||
public interface DesignedCellTableStyle extends CellTable.Style {
|
||||
String buttonCell();
|
||||
|
||||
String textCellWordWrap();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
@@ -9,6 +9,7 @@ import com.sap.sailing.news.EventNewsService;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.statistics.TrackedRaceStatisticsCache;
|
||||
import com.sap.sse.gwt.dispatch.client.system.DispatchContext;
|
||||
import com.sap.sse.security.SecurityService;
|
||||
|
||||
/**
|
||||
* {@link DispatchContext} implementation, which is passed to backend-side {@link SailingAction} executions to provide
|
||||
@@ -36,6 +37,9 @@ public interface SailingDispatchContext extends DispatchContext {
|
||||
@GwtIncompatible
|
||||
Date getCurrentClientTime();
|
||||
|
||||
@GwtIncompatible
|
||||
SecurityService getSecurityService();
|
||||
|
||||
<T> T getPreferenceForCurrentUser(String preferenceKey);
|
||||
|
||||
void setPreferenceForCurrentUser(String preferenceKey, Object preference);
|
||||
|
||||
+2
-1
@@ -51,7 +51,8 @@ public class GetAnniversariesAction implements SailingAction<ResultWithTTL<Anniv
|
||||
});
|
||||
|
||||
TimeToLiveCalculator timeToLiveCalculator = new TimeToLiveCalculator();
|
||||
HomeServiceUtil.forAllPublicEvents(service, context.getRequest(), timeToLiveCalculator);
|
||||
HomeServiceUtil.forAllPublicEventsWithReadPermission(service, context.getRequest(), context.getSecurityService(),
|
||||
timeToLiveCalculator);
|
||||
return new ResultWithTTL<AnniversariesDTO>(timeToLiveCalculator.getTimeToLive(), anniversaries);
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -49,8 +49,12 @@ public class GetCompetitionFormatRacesAction implements
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<ListResult<RaceCompetitionFormatSeriesDTO>> execute(SailingDispatchContext context) throws DispatchException {
|
||||
context.getSecurityService()
|
||||
.checkCurrentUserReadPermission(context.getRacingEventService().getLeaderboardByName(regattaId));
|
||||
context.getSecurityService()
|
||||
.checkCurrentUserReadPermission(context.getRacingEventService().getRegattaByName(regattaId));
|
||||
RaceCompetitionFormatDataCalculator competitionFormatDataCalculator = new RaceCompetitionFormatDataCalculator();
|
||||
EventActionUtil.forRacesOfRegatta(context, eventId, regattaId, competitionFormatDataCalculator);
|
||||
EventActionUtil.forRacesOfRegattaWithReadPermissions(context, eventId, regattaId, competitionFormatDataCalculator);
|
||||
Duration timeToLive = EventActionUtil.getEventStateDependentTTL(context, eventId, Duration.ONE_MINUTE);
|
||||
return new ResultWithTTL<>(timeToLive, new ListResult<>(competitionFormatDataCalculator.getResult()));
|
||||
}
|
||||
|
||||
+2
-1
@@ -19,7 +19,8 @@ public class GetEventListViewAction implements SailingAction<EventListViewDTO>,
|
||||
@GwtIncompatible
|
||||
public EventListViewDTO execute(SailingDispatchContext context) {
|
||||
EventListDataCalculator eventListDataCalculator = new EventListDataCalculator(context.getRacingEventService());
|
||||
HomeServiceUtil.forAllPublicEvents(context.getRacingEventService(), context.getRequest(),
|
||||
HomeServiceUtil.forAllPublicEventsWithReadPermission(context.getRacingEventService(), context.getRequest(),
|
||||
context.getSecurityService(),
|
||||
eventListDataCalculator);
|
||||
return eventListDataCalculator.getResult();
|
||||
}
|
||||
|
||||
+6
-5
@@ -61,6 +61,7 @@ public class GetEventViewAction implements SailingAction<EventViewDTO>, IsClient
|
||||
if (event == null) {
|
||||
throw new RuntimeException("Event not found");
|
||||
}
|
||||
context.getSecurityService().checkCurrentUserReadPermission(event);
|
||||
|
||||
final EventViewDTO dto = new EventViewDTO();
|
||||
HomeServiceUtil.mapToMetadataDTO(event, dto, context.getRacingEventService());
|
||||
@@ -89,16 +90,16 @@ public class GetEventViewAction implements SailingAction<EventViewDTO>, IsClient
|
||||
final Set<RegattaMetadataDTO> regattasOfEvent = new HashSet<>();
|
||||
final Set<LeaderboardGroup> relevantLeaderboardGroupsOfEvent = new HashSet<>();
|
||||
|
||||
EventActionUtil.forLeaderboardsOfEvent(context, event, new LeaderboardCallback() {
|
||||
EventActionUtil.forLeaderboardsOfEventWithReadPermissions(context, event, new LeaderboardCallback() {
|
||||
@Override
|
||||
public void doForLeaderboard(LeaderboardContext context) {
|
||||
public void doForLeaderboard(LeaderboardContext lcontext) {
|
||||
try {
|
||||
Util.addAll(context.getLeaderboardGroups(), relevantLeaderboardGroupsOfEvent);
|
||||
RegattaMetadataDTO regattaDTO = context.asRegattaMetadataDTO();
|
||||
Util.addAll(lcontext.getLeaderboardGroups(), relevantLeaderboardGroupsOfEvent);
|
||||
RegattaMetadataDTO regattaDTO = lcontext.asRegattaMetadataDTO();
|
||||
regattasOfEvent.add(regattaDTO);
|
||||
dto.getRegattas().add(regattaDTO);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Catched exception while reading data for leaderboard " + context.getLeaderboardName(), e);
|
||||
logger.log(Level.SEVERE, "Catched exception while reading data for leaderboard " + lcontext.getLeaderboardName(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ public class GetFinishedRacesAction implements SailingAction<ResultWithTTL<ListR
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<ListResult<RaceListRaceDTO>> execute(SailingDispatchContext context) {
|
||||
RaceListDataCalculator raceListDataCalculator = new RaceListDataCalculator();
|
||||
EventActionUtil.forRacesOfRegatta(context, eventId, regattaId, raceListDataCalculator);
|
||||
EventActionUtil.forRacesOfRegattaWithReadPermissions(context, eventId, regattaId, raceListDataCalculator);
|
||||
|
||||
return new ResultWithTTL<>(EventActionUtil.getEventStateDependentTTL(context, eventId,
|
||||
Duration.ONE_MINUTE.times(5)), new ListResult<>(raceListDataCalculator.getResult()));
|
||||
|
||||
+2
-2
@@ -50,11 +50,11 @@ public class GetLiveRacesForEventAction implements SailingAction<ResultWithTTL<S
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<SortedSetResult<LiveRaceDTO>> execute(final SailingDispatchContext context) {
|
||||
return EventActionUtil.withLiveRaceOrDefaultSchedule(context, eventId, new CalculationWithEvent<SortedSetResult<LiveRaceDTO>>() {
|
||||
return EventActionUtil.withLiveRaceOrDefaultScheduleWithReadPermissions(context, eventId, new CalculationWithEvent<SortedSetResult<LiveRaceDTO>>() {
|
||||
@Override
|
||||
public ResultWithTTL<SortedSetResult<LiveRaceDTO>> calculateWithEvent(Event event) {
|
||||
LiveRaceCalculator liveRaceCalculator = new LiveRaceCalculator();
|
||||
EventActionUtil.forRacesOfEvent(context, eventId, liveRaceCalculator);
|
||||
EventActionUtil.forRacesOfEventWithReadPermissions(context, eventId, liveRaceCalculator);
|
||||
return liveRaceCalculator.getResult();
|
||||
}
|
||||
});
|
||||
|
||||
+2
-2
@@ -53,11 +53,11 @@ public class GetLiveRacesForRegattaAction implements SailingAction<ResultWithTTL
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<SortedSetResult<LiveRaceDTO>> execute(final SailingDispatchContext context) {
|
||||
return EventActionUtil.withLiveRaceOrDefaultSchedule(context, eventId, new CalculationWithEvent<SortedSetResult<LiveRaceDTO>>() {
|
||||
return EventActionUtil.withLiveRaceOrDefaultScheduleWithReadPermissions(context, eventId, new CalculationWithEvent<SortedSetResult<LiveRaceDTO>>() {
|
||||
@Override
|
||||
public ResultWithTTL<SortedSetResult<LiveRaceDTO>> calculateWithEvent(Event event) {
|
||||
LiveRaceCalculator liveRaceCalculator = new LiveRaceCalculator();
|
||||
EventActionUtil.forRacesOfRegatta(context, eventId, regattaName, liveRaceCalculator);
|
||||
EventActionUtil.forRacesOfRegattaWithReadPermissions(context, eventId, regattaName, liveRaceCalculator);
|
||||
return liveRaceCalculator.getResult();
|
||||
}
|
||||
});
|
||||
|
||||
+2
-1
@@ -48,8 +48,9 @@ public class GetRegattaListViewAction implements SailingAction<ResultWithTTL<Sor
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<SortedSetResult<RegattaWithProgressDTO>> execute(final SailingDispatchContext context) {
|
||||
context.getSecurityService().checkCurrentUserReadPermission(context.getRacingEventService().getEvent(eventId));
|
||||
final List<RegattaWithProgressDTO> result = new LinkedList<>();
|
||||
EventActionUtil.forLeaderboardsOfEvent(context, eventId, new LeaderboardCallback() {
|
||||
EventActionUtil.forLeaderboardsOfEventWithReadPermissions(context, eventId, new LeaderboardCallback() {
|
||||
@Override
|
||||
public void doForLeaderboard(LeaderboardContext leaderboardContext) {
|
||||
result.add(leaderboardContext.getRegattaWithProgress());
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class GetRegattaStatisticsAction implements SailingAction<ResultWithTTL<E
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<EventStatisticsDTO> execute(SailingDispatchContext context) throws DispatchException {
|
||||
StatisticsCalculator statisticsCalculator = new StatisticsCalculator(context.getTrackedRaceStatisticsCache());
|
||||
statisticsCalculator.doForLeaderboard(EventActionUtil.getLeaderboardContext(context, eventId, regattaId));
|
||||
statisticsCalculator.doForLeaderboard(EventActionUtil.getLeaderboardContextWithReadPermissions(context, eventId, regattaId));
|
||||
return statisticsCalculator.getResult();
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -48,8 +48,11 @@ public class GetRegattaWithProgressAction implements SailingAction<ResultWithTTL
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<RegattaWithProgressDTO> execute(SailingDispatchContext context) {
|
||||
context.getSecurityService().checkCurrentUserReadPermission(context.getRacingEventService().getEvent(eventId));
|
||||
context.getSecurityService()
|
||||
.checkCurrentUserReadPermission(context.getRacingEventService().getRegattaByName(regattaId));
|
||||
return new ResultWithTTL<>(EventActionUtil.getEventStateDependentTTL(context, eventId, Duration.ONE_MINUTE.times(5)),
|
||||
EventActionUtil.getLeaderboardContext(context, eventId, regattaId).getRegattaWithProgress());
|
||||
EventActionUtil.getLeaderboardContextWithReadPermissions(context, eventId, regattaId).getRegattaWithProgress());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-3
@@ -52,12 +52,13 @@ public class GetRegattasAndLiveRacesForEventAction implements SailingAction<Resu
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<RegattasAndLiveRacesDTO> execute(SailingDispatchContext context) {
|
||||
context.getSecurityService().checkCurrentUserReadPermission(context.getRacingEventService().getEvent(eventId));
|
||||
final Map<String, RegattaMetadataDTO> regattas = mapRegattas(context);
|
||||
final TreeMap<RegattaMetadataDTO, TreeSet<LiveRaceDTO>> regattasWithRaces = new TreeMap<>();
|
||||
final TreeSet<RegattaMetadataDTO> regattasWithoutRaces = new TreeSet<>();
|
||||
final RaceRefreshCalculator refreshCalculator = new RaceRefreshCalculator();
|
||||
|
||||
EventActionUtil.forRacesOfEvent(context, eventId, raceContent -> {
|
||||
EventActionUtil.forRacesOfEventWithReadPermissions(context, eventId, raceContent -> {
|
||||
Optional<LiveRaceDTO> liveRace = Optional.ofNullable(raceContent.getLiveRaceOrNull());
|
||||
liveRace.ifPresent(r -> ensureRegatta(raceContent, regattas, regattasWithRaces).add(r));
|
||||
refreshCalculator.doForRace(raceContent);
|
||||
@@ -66,13 +67,13 @@ public class GetRegattasAndLiveRacesForEventAction implements SailingAction<Resu
|
||||
.forEach(regattasWithoutRaces::add);
|
||||
RegattasAndLiveRacesDTO dto = new RegattasAndLiveRacesDTO(regattasWithRaces, regattasWithoutRaces);
|
||||
ResultWithTTL<RegattasAndLiveRacesDTO> result = new ResultWithTTL<>(refreshCalculator.getTTL(), dto);
|
||||
return EventActionUtil.withLiveRaceOrDefaultSchedule(context, eventId, event -> result, dto);
|
||||
return EventActionUtil.withLiveRaceOrDefaultScheduleWithReadPermissions(context, eventId, event -> result, dto);
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private Map<String, RegattaMetadataDTO> mapRegattas(SailingDispatchContext context) {
|
||||
final Map<String, RegattaMetadataDTO> result = new HashMap<>();
|
||||
EventActionUtil.forLeaderboardsOfEvent(context, eventId, new LeaderboardCallback() {
|
||||
EventActionUtil.forLeaderboardsOfEventWithReadPermissions(context, eventId, new LeaderboardCallback() {
|
||||
@Override
|
||||
public void doForLeaderboard(LeaderboardContext context) {
|
||||
result.put(context.getLeaderboardName(), context.asRegattaMetadataDTO());
|
||||
|
||||
+6
-1
@@ -45,7 +45,12 @@ public class GetSeriesStatisticsAction implements SailingAction<ResultWithTTL<Ev
|
||||
public ResultWithTTL<EventStatisticsDTO> execute(SailingDispatchContext context) throws DispatchException {
|
||||
StatisticsCalculator statisticsCalculator = new StatisticsCalculator(context.getTrackedRaceStatisticsCache());
|
||||
final LeaderboardGroup leaderboardGroupByID = context.getRacingEventService().getLeaderboardGroupByID(seriesLeaderboardGroupId);
|
||||
leaderboardGroupByID.getLeaderboards().forEach(statisticsCalculator::addLeaderboard);
|
||||
context.getSecurityService().checkCurrentUserReadPermission(leaderboardGroupByID);
|
||||
leaderboardGroupByID.getLeaderboards().forEach(t -> {
|
||||
if (context.getSecurityService().hasCurrentUserReadPermission(t)) {
|
||||
statisticsCalculator.addLeaderboard(t);
|
||||
}
|
||||
});
|
||||
return statisticsCalculator.getResult();
|
||||
}
|
||||
|
||||
|
||||
+25
@@ -43,4 +43,29 @@ public class SimpleCompetitorWithIdDTO extends SimpleCompetitorDTO implements Re
|
||||
? this.idAsString.compareTo(((SimpleCompetitorWithIdDTO) obj).idAsString) : compareTo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result + ((idAsString == null) ? 0 : idAsString.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (!super.equals(obj))
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
SimpleCompetitorWithIdDTO other = (SimpleCompetitorWithIdDTO) obj;
|
||||
if (idAsString == null) {
|
||||
if (other.idAsString != null)
|
||||
return false;
|
||||
} else if (!idAsString.equals(other.idAsString))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ public class GetMiniLeaderbordAction implements SailingAction<ResultWithTTL<GetM
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<GetMiniLeaderboardDTO> execute(SailingDispatchContext context) {
|
||||
return EventActionUtil.getLeaderboardContext(context, eventId, leaderboardName).calculateMiniLeaderboard(context.getRacingEventService(), limit);
|
||||
return EventActionUtil.getLeaderboardContextWithReadPermissions(context, eventId, leaderboardName).calculateMiniLeaderboard(context.getRacingEventService(), limit);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-1
@@ -4,6 +4,7 @@ import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.gwt.common.communication.routing.ProvidesLeaderboardRouting;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
@@ -63,11 +64,16 @@ public class GetMiniOverallLeaderbordAction implements SailingAction<ResultWithT
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<GetMiniLeaderboardDTO> execute(SailingDispatchContext context) {
|
||||
LeaderboardGroup leaderboardGroup = context.getRacingEventService().getLeaderboardGroupByID(leaderboardGroupUUID);
|
||||
context.getSecurityService().checkCurrentUserReadPermission(leaderboardGroup);
|
||||
if(leaderboardGroup == null) {
|
||||
throw new RuntimeException("Invalid leaderboardGroupID");
|
||||
}
|
||||
Event event = HomeServiceUtil.determineBestMatchingEvent(context.getRacingEventService(), leaderboardGroup);
|
||||
LeaderboardContext lctx = new LeaderboardContext(context, event, event.getLeaderboardGroups(), leaderboardGroup.getOverallLeaderboard());
|
||||
context.getSecurityService().checkCurrentUserReadPermission(event);
|
||||
Leaderboard overallLeaderBoard = leaderboardGroup.getOverallLeaderboard();
|
||||
context.getSecurityService().checkCurrentUserReadPermission(overallLeaderBoard);
|
||||
LeaderboardContext lctx = new LeaderboardContext(context, event, event.getLeaderboardGroups(),
|
||||
overallLeaderBoard);
|
||||
return lctx.calculateMiniLeaderboard(context.getRacingEventService(), limit);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ public class GetEventOverviewNewsAction implements SailingAction<ResultWithTTL<L
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<ListResult<NewsEntryDTO>> execute(final SailingDispatchContext context) {
|
||||
return EventActionUtil.withLiveRaceOrDefaultSchedule(context, eventId, new CalculationWithEvent<ListResult<NewsEntryDTO>>() {
|
||||
return EventActionUtil.withLiveRaceOrDefaultScheduleWithReadPermissions(context, eventId, new CalculationWithEvent<ListResult<NewsEntryDTO>>() {
|
||||
@Override
|
||||
public ResultWithTTL<ListResult<NewsEntryDTO>> calculateWithEvent(Event event) {
|
||||
return new ResultWithTTL<>(Duration.ONE_MINUTE.times(2), new ListResult<NewsEntryDTO>(getNews(context, event)));
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ public class GetEventStatisticsAction implements SailingAction<ResultWithTTL<Eve
|
||||
@GwtIncompatible
|
||||
public ResultWithTTL<EventStatisticsDTO> execute(SailingDispatchContext context) throws DispatchException {
|
||||
StatisticsCalculator statisticsCalculator = new StatisticsCalculator(context.getTrackedRaceStatisticsCache());
|
||||
EventActionUtil.forLeaderboardsOfEvent(context, eventId, statisticsCalculator);
|
||||
EventActionUtil.forLeaderboardsOfEventWithReadPermissions(context, eventId, statisticsCalculator);
|
||||
return statisticsCalculator.getResult();
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -41,7 +41,8 @@ public class GetRecentEventsAction implements SailingAction<ListResult<EventQuic
|
||||
@GwtIncompatible
|
||||
public ListResult<EventQuickfinderDTO> execute(final SailingDispatchContext context) throws DispatchException {
|
||||
final SortedSet<EventQuickfinderDTO> events = new TreeSet<>();
|
||||
HomeServiceUtil.forAllPublicEvents(context.getRacingEventService(), context.getRequest(), new EventVisitor() {
|
||||
HomeServiceUtil.forAllPublicEventsWithReadPermission(context.getRacingEventService(), context.getRequest(),
|
||||
context.getSecurityService(), new EventVisitor() {
|
||||
@Override
|
||||
public void visit(EventBase event, boolean onRemoteServer, URL baseURL) {
|
||||
EventQuickfinderDTO dto = new EventQuickfinderDTO();
|
||||
|
||||
+2
-1
@@ -36,7 +36,8 @@ public class GetStagedEventsAction implements SailingAction<ListResult<EventStag
|
||||
@GwtIncompatible
|
||||
public ListResult<EventStageDTO> execute(final SailingDispatchContext context) throws DispatchException {
|
||||
EventStageCandidateCalculator stageCandidateCalculator = new EventStageCandidateCalculator();
|
||||
HomeServiceUtil.forAllPublicEvents(context.getRacingEventService(), context.getRequest(),
|
||||
HomeServiceUtil.forAllPublicEventsWithReadPermission(context.getRacingEventService(), context.getRequest(),
|
||||
context.getSecurityService(),
|
||||
stageCandidateCalculator);
|
||||
ListResult<EventStageDTO> result = new ListResult<>();
|
||||
int count = 0;
|
||||
|
||||
+2
-1
@@ -47,7 +47,8 @@ public class GetStartViewAction implements SailingAction<StartViewDTO>, IsClient
|
||||
public StartViewDTO execute(SailingDispatchContext context) {
|
||||
EventStageCandidateCalculator stageCandidateCalculator = new EventStageCandidateCalculator();
|
||||
RecentEventsCalculator recentEventsCalculator = new RecentEventsCalculator();
|
||||
HomeServiceUtil.forAllPublicEvents(context.getRacingEventService(), context.getRequest(), stageCandidateCalculator, recentEventsCalculator);
|
||||
HomeServiceUtil.forAllPublicEventsWithReadPermission(context.getRacingEventService(), context.getRequest(),
|
||||
context.getSecurityService(), stageCandidateCalculator, recentEventsCalculator);
|
||||
StartViewDTO result = new StartViewDTO();
|
||||
int count = 0;
|
||||
for (Pair<StageEventType, EventHolder> pair : stageCandidateCalculator.getFeaturedEvents()) {
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
|
||||
/** This object represents a badge in a sailor profile {@link SailorProfileDTO} */
|
||||
public class BadgeDTO implements Serializable {
|
||||
private static final long serialVersionUID = 2374312724838738559L;
|
||||
|
||||
private UUID key;
|
||||
private String name;
|
||||
|
||||
protected BadgeDTO() {
|
||||
|
||||
}
|
||||
|
||||
public BadgeDTO(UUID key, String name) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public UUID getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BadgeDTO other = (BadgeDTO) obj;
|
||||
if (key == null) {
|
||||
if (other.key != null)
|
||||
return false;
|
||||
} else if (!key.equals(other.key))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* This object contains the name and id with a fixed set of Participated regattas ({@link ParticipatedRegattaDTO} in a
|
||||
* {@link SailorProfileDTO} which is loaded asynchronously.
|
||||
*/
|
||||
public class ParticipatedEventDTO implements Serializable {
|
||||
private static final long serialVersionUID = -716458570343167392L;
|
||||
|
||||
private String eventName;
|
||||
private String eventId;
|
||||
private ArrayList<ParticipatedRegattaDTO> participatedRegattas = new ArrayList<>();
|
||||
|
||||
protected ParticipatedEventDTO() {
|
||||
}
|
||||
|
||||
public ParticipatedEventDTO(String eventName, String eventId,
|
||||
Iterable<ParticipatedRegattaDTO> participatedRegattas) {
|
||||
super();
|
||||
this.eventName = eventName;
|
||||
this.eventId = eventId;
|
||||
Util.addAll(participatedRegattas, this.participatedRegattas);
|
||||
}
|
||||
|
||||
public String getEventName() {
|
||||
return eventName;
|
||||
}
|
||||
|
||||
public String getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public Iterable<ParticipatedRegattaDTO> getParticipatedRegattas() {
|
||||
return participatedRegattas;
|
||||
}
|
||||
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
|
||||
/**
|
||||
* This object contains all relevant data of a regatta, a competitor ({@link #competitorDto}) participated in.
|
||||
* Additionally to the name of the regatta and the unique IDs of the regatta and the containing event, this objects
|
||||
* contains information about the rank and points of the participating competitor.
|
||||
*/
|
||||
public class ParticipatedRegattaDTO implements Serializable {
|
||||
private static final long serialVersionUID = -126348629933556831L;
|
||||
|
||||
private String regattaName;
|
||||
private int regattaRank;
|
||||
private SimpleCompetitorWithIdDTO competitorDto;
|
||||
private String regattaId;
|
||||
private String eventId;
|
||||
private double sumPoints;
|
||||
|
||||
protected ParticipatedRegattaDTO() {
|
||||
}
|
||||
|
||||
public ParticipatedRegattaDTO(String regattaName, int regattaRank, SimpleCompetitorWithIdDTO competitorDto,
|
||||
String regattaId, String eventId, double sumPoints) {
|
||||
super();
|
||||
this.regattaName = regattaName;
|
||||
this.regattaRank = regattaRank;
|
||||
this.competitorDto = competitorDto;
|
||||
this.regattaId = regattaId;
|
||||
this.eventId = eventId;
|
||||
this.sumPoints = sumPoints;
|
||||
}
|
||||
|
||||
public String getRegattaName() {
|
||||
return regattaName;
|
||||
}
|
||||
|
||||
public int getRegattaRank() {
|
||||
return regattaRank;
|
||||
}
|
||||
|
||||
public SimpleCompetitorWithIdDTO getCompetitorDto() {
|
||||
return competitorDto;
|
||||
}
|
||||
|
||||
public String getRegattaId() {
|
||||
return regattaId;
|
||||
}
|
||||
|
||||
public String getEventId() {
|
||||
return eventId;
|
||||
}
|
||||
|
||||
public double getSumPoints() {
|
||||
return sumPoints;
|
||||
}
|
||||
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.Result;
|
||||
|
||||
/**
|
||||
* This objects contains all data related to displaying a SailorProfile in the frontend UI. Since this object is also
|
||||
* used when querying a sailor profile with a key from the backend, there is a field {@link #notFoundOnServer} to
|
||||
* intercept the case that there is no corresponding sailor profile.<br/>
|
||||
* <br/>
|
||||
* Events and statistics are loaded asynchronously with {@link SailorProfileEventsDTO} and
|
||||
* {@link SailorProfileStatisticDTO}.
|
||||
*/
|
||||
public class SailorProfileDTO implements Result, Serializable {
|
||||
private static final long serialVersionUID = -5957161570595861618L;
|
||||
|
||||
/** {@link #notFoundOnServer} is true, if the {@link #key} does has no corresponding sailor profile. */
|
||||
private boolean notFoundOnServer;
|
||||
|
||||
private UUID key;
|
||||
private String name;
|
||||
private ArrayList<SimpleCompetitorWithIdDTO> competitors = new ArrayList<>();
|
||||
private ArrayList<BadgeDTO> badges = new ArrayList<>();
|
||||
private ArrayList<BoatClassDTO> boatclasses = new ArrayList<>();
|
||||
|
||||
protected SailorProfileDTO() {
|
||||
|
||||
}
|
||||
|
||||
public SailorProfileDTO(boolean notFound) {
|
||||
this.notFoundOnServer = notFound;
|
||||
}
|
||||
|
||||
public SailorProfileDTO(UUID key, String name) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public SailorProfileDTO(UUID key, String name, Iterable<SimpleCompetitorWithIdDTO> competitors,
|
||||
Iterable<BadgeDTO> badges, Iterable<BoatClassDTO> boatclasses) {
|
||||
super();
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
Util.addAll(competitors, this.competitors);
|
||||
Util.addAll(badges, this.badges);
|
||||
Util.addAll(boatclasses, this.boatclasses);
|
||||
}
|
||||
|
||||
public boolean isNotFoundOnServer() {
|
||||
return notFoundOnServer;
|
||||
}
|
||||
|
||||
public UUID getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Collection<SimpleCompetitorWithIdDTO> getCompetitors() {
|
||||
return competitors;
|
||||
}
|
||||
|
||||
public Collection<BadgeDTO> getBadges() {
|
||||
return badges;
|
||||
}
|
||||
|
||||
public Iterable<BoatClassDTO> getBoatclasses() {
|
||||
return boatclasses;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((key == null) ? 0 : key.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
SailorProfileDTO other = (SailorProfileDTO) obj;
|
||||
if (key == null) {
|
||||
if (other.key != null)
|
||||
return false;
|
||||
} else if (!key.equals(other.key))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setName(String newName) {
|
||||
this.name = newName;
|
||||
}
|
||||
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.Result;
|
||||
|
||||
/**
|
||||
* Since the Events are loaded asynchronously after loading the {@link SailorProfileDTO}, this object contains a list of
|
||||
* {@link ParticipatedEventDTO}.
|
||||
*/
|
||||
public class SailorProfileEventsDTO implements Serializable, Result {
|
||||
private static final long serialVersionUID = 4658596949068331464L;
|
||||
|
||||
private ArrayList<ParticipatedEventDTO> participatedEvents = new ArrayList<>();
|
||||
|
||||
protected SailorProfileEventsDTO() {
|
||||
}
|
||||
|
||||
public SailorProfileEventsDTO(Iterable<ParticipatedEventDTO> participatedEvents) {
|
||||
Util.addAll(participatedEvents, this.participatedEvents);
|
||||
}
|
||||
|
||||
public Iterable<ParticipatedEventDTO> getParticipatedEvents() {
|
||||
return participatedEvents;
|
||||
}
|
||||
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import com.sap.sailing.gwt.ui.raceboard.RaceBoardModes;
|
||||
|
||||
/** current types of statistics currently supported in the SailorProfiles and the corresponding backend service */
|
||||
public enum SailorProfileNumericStatisticType {
|
||||
MAX_SPEED(StatisticType.HIGHEST_IS_BEST, RaceBoardModes.PLAYER), BEST_DISTANCE_TO_START(
|
||||
StatisticType.LOWEST_IS_BEST,
|
||||
RaceBoardModes.START_ANALYSIS), BEST_STARTLINE_SPEED(StatisticType.HIGHEST_IS_BEST,
|
||||
RaceBoardModes.START_ANALYSIS), AVERAGE_STARTLINE_DISTANCE(StatisticType.AVERAGE, null);
|
||||
|
||||
private StatisticType type;
|
||||
private RaceBoardModes mode;
|
||||
|
||||
SailorProfileNumericStatisticType(StatisticType type, RaceBoardModes mode) {
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
public StatisticType getAggregationType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public RaceBoardModes getPlayerMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public static enum StatisticType {
|
||||
LOWEST_IS_BEST, HIGHEST_IS_BEST, AVERAGE
|
||||
}
|
||||
|
||||
}
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.Result;
|
||||
|
||||
/**
|
||||
* Contains the result of a single statistic, to allow asynchronous loading of statistics without blocking loading the
|
||||
* sailor profile or the events
|
||||
**/
|
||||
public class SailorProfileStatisticDTO implements Result, Serializable {
|
||||
private static final long serialVersionUID = 2924378586764418626L;
|
||||
// keep as specified as possible to save gwt compiler time
|
||||
private HashMap<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> result = new HashMap<>();
|
||||
private String dataMiningQuery;
|
||||
|
||||
// GWTSerialisation only
|
||||
protected SailorProfileStatisticDTO() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SailorProfileStatisticDTO(Map<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> result,
|
||||
String dataMiningQuery) {
|
||||
this.result.putAll(result);
|
||||
this.dataMiningQuery = dataMiningQuery;
|
||||
}
|
||||
|
||||
public HashMap<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getDataMiningQuery() {
|
||||
return dataMiningQuery;
|
||||
}
|
||||
|
||||
public static class SingleEntry implements Serializable {
|
||||
private static final long serialVersionUID = -7722750678632551505L;
|
||||
|
||||
@GwtIncompatible
|
||||
public SingleEntry(Double value, RegattaAndRaceIdentifier relatedRaceOrNull, TimePoint relatedTimePointOrNull,
|
||||
TimePoint relatedRaceStartTimePointOrNull, String leaderboardNameOrNull,
|
||||
String leaderboardGroupNameOrNull, UUID eventIdOrNull, String raceNameOrNull) {
|
||||
super();
|
||||
this.value = value;
|
||||
this.relatedRaceOrNull = relatedRaceOrNull;
|
||||
this.leaderboardNameOrNull = leaderboardNameOrNull;
|
||||
this.leaderboardGroupNameOrNull = leaderboardGroupNameOrNull;
|
||||
this.eventIdOrNull = eventIdOrNull;
|
||||
this.raceNameOrNull = raceNameOrNull;
|
||||
if (relatedTimePointOrNull != null) {
|
||||
// not all TimePoints are GWT compatible, ensure we have a compatible one!
|
||||
if (relatedTimePointOrNull instanceof MillisecondsTimePoint) {
|
||||
this.relatedTimePointOrNull = (MillisecondsTimePoint) relatedTimePointOrNull;
|
||||
} else {
|
||||
this.relatedTimePointOrNull = new MillisecondsTimePoint(relatedTimePointOrNull.asMillis());
|
||||
}
|
||||
}
|
||||
if (relatedRaceStartTimePointOrNull != null) {
|
||||
if (relatedRaceStartTimePointOrNull instanceof MillisecondsTimePoint) {
|
||||
this.relatedRaceStartTimePointOrNull = (MillisecondsTimePoint) relatedRaceStartTimePointOrNull;
|
||||
} else {
|
||||
this.relatedRaceStartTimePointOrNull = new MillisecondsTimePoint(
|
||||
relatedRaceStartTimePointOrNull.asMillis());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GWTSerialisation only
|
||||
protected SingleEntry() {
|
||||
}
|
||||
|
||||
private Double value;
|
||||
private RegattaAndRaceIdentifier relatedRaceOrNull;
|
||||
// not generic, to reduce possible permutations for gwt compiler
|
||||
private MillisecondsTimePoint relatedTimePointOrNull;
|
||||
private MillisecondsTimePoint relatedRaceStartTimePointOrNull;
|
||||
private String leaderboardNameOrNull;
|
||||
private String leaderboardGroupNameOrNull;
|
||||
private String raceNameOrNull;
|
||||
private UUID eventIdOrNull;
|
||||
|
||||
/**
|
||||
* All values will be in SI Units if not otherwise stated in the Type documentation
|
||||
*/
|
||||
public Double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public RegattaAndRaceIdentifier getRelatedRaceOrNull() {
|
||||
return relatedRaceOrNull;
|
||||
}
|
||||
|
||||
public MillisecondsTimePoint getRelatedTimePointOrNull() {
|
||||
return relatedTimePointOrNull;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "SingleEntry [value=" + value + ", relatedRaceOrNull=" + relatedRaceOrNull
|
||||
+ ", relatedTimePointOrNull=" + relatedTimePointOrNull + ", relatedRaceStartTimePointOrNull="
|
||||
+ relatedRaceStartTimePointOrNull + ", leaderboardNameOrNull=" + leaderboardNameOrNull
|
||||
+ ", leaderboardGroupNameOrNull=" + leaderboardGroupNameOrNull + ", raceNameOrNull="
|
||||
+ raceNameOrNull + ", eventIdOrNull=" + eventIdOrNull + "]";
|
||||
}
|
||||
|
||||
public String getLeaderboardNameOrNull() {
|
||||
return leaderboardNameOrNull;
|
||||
}
|
||||
|
||||
public UUID getEventIdOrNull() {
|
||||
return eventIdOrNull;
|
||||
}
|
||||
|
||||
public String getLeaderboardGroupNameOrNull() {
|
||||
return leaderboardGroupNameOrNull;
|
||||
}
|
||||
|
||||
public MillisecondsTimePoint getRelatedRaceStartTimePointOrNull() {
|
||||
return relatedRaceStartTimePointOrNull;
|
||||
}
|
||||
|
||||
public String getRaceNameOrNull() {
|
||||
return raceNameOrNull;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.Result;
|
||||
|
||||
/**
|
||||
* This domain object contains a list of {@link SailorProfileDTO} objects which is loaded to display the sailor profile
|
||||
* overview.
|
||||
*/
|
||||
public class SailorProfilesDTO implements Result, Serializable {
|
||||
private static final long serialVersionUID = -7062326258445057995L;
|
||||
private ArrayList<SailorProfileDTO> entries = new ArrayList<>();
|
||||
|
||||
protected SailorProfilesDTO() {
|
||||
|
||||
}
|
||||
|
||||
public SailorProfilesDTO(Iterable<SailorProfileDTO> entries) {
|
||||
super();
|
||||
Util.addAll(entries, this.entries);
|
||||
}
|
||||
|
||||
public List<SailorProfileDTO> getEntries() {
|
||||
return entries;
|
||||
}
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
|
||||
/**
|
||||
* {@link UpdateSailorProfileAction} implementation to create a new sailor profile for the currently logged in user with
|
||||
* a UUID and a name.
|
||||
*/
|
||||
public class CreateSailorProfileAction extends UpdateSailorProfileAction {
|
||||
|
||||
private String name;
|
||||
|
||||
public CreateSailorProfileAction(UUID uuid, String name) {
|
||||
super(uuid);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected CreateSailorProfileAction() {
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
@Override
|
||||
protected SailorProfilePreference updatePreference(CompetitorAndBoatStore store, SailorProfilePreference p) {
|
||||
return new SailorProfilePreference(store, uuid, name);
|
||||
}
|
||||
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardContext;
|
||||
import com.sap.sailing.datamining.data.HasLeaderboardGroupContext;
|
||||
import com.sap.sailing.datamining.data.HasRaceOfCompetitorContext;
|
||||
import com.sap.sailing.datamining.data.HasTrackedRaceContext;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.datamining.shared.DataMiningQuerySerializer;
|
||||
import com.sap.sse.datamining.shared.dto.StatisticQueryDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.AggregationProcessorDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverChainDefinitionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.DataRetrieverLevelDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.FunctionDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.LocalizedTypeDTO;
|
||||
import com.sap.sse.datamining.shared.impl.dto.ModifiableStatisticQueryDefinitionDTO;
|
||||
|
||||
public final class DataMiningQueryCreatorForSailorProfiles {
|
||||
private DataMiningQueryCreatorForSailorProfiles() {
|
||||
}
|
||||
|
||||
private static final String leaderboardGroupRetrievalProcessorName = "com.sap.sailing.datamining.impl.components.LeaderboardGroupRetrievalProcessor";
|
||||
private static final String leaderboardRetrievalProcessorName = "com.sap.sailing.datamining.impl.components.LeaderboardRetrievalProcessor";
|
||||
private static final String trackedRaceRetrievalProcessorName = "com.sap.sailing.datamining.impl.components.TrackedRaceRetrievalProcessor";
|
||||
private static final String raceCompetitorRetrievalProcessorName = "com.sap.sailing.datamining.impl.components.RaceOfCompetitorRetrievalProcessor";
|
||||
|
||||
public static final String getSerializedDataMiningQuery(SailorProfileNumericStatisticType type,
|
||||
List<String> competitorNames) {
|
||||
switch (type) {
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
return DataMiningQuerySerializer.toBase64String(createQueryForAverageStartlineDistance(competitorNames));
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static StatisticQueryDefinitionDTO createQueryForAverageStartlineDistance(
|
||||
final List<String> competitorNames) {
|
||||
FunctionDTO statistic = new FunctionDTO(false, "getDistanceToStartLineAtStart()",
|
||||
HasRaceOfCompetitorContext.class.getName(), Distance.class.getName(), new ArrayList<String>(), "", 0);
|
||||
AggregationProcessorDefinitionDTO aggregator = new AggregationProcessorDefinitionDTO("Minimum",
|
||||
Distance.class.getName(), Distance.class.getName(), "");
|
||||
|
||||
ArrayList<DataRetrieverLevelDTO> retrieverLevels = new ArrayList<>();
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(0, leaderboardGroupRetrievalProcessorName,
|
||||
new LocalizedTypeDTO(HasLeaderboardGroupContext.class.getName(), ""), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(1, leaderboardRetrievalProcessorName,
|
||||
new LocalizedTypeDTO(HasLeaderboardContext.class.getName(), ""), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(2, trackedRaceRetrievalProcessorName,
|
||||
new LocalizedTypeDTO(HasTrackedRaceContext.class.getName(), ""), null));
|
||||
retrieverLevels.add(new DataRetrieverLevelDTO(3, raceCompetitorRetrievalProcessorName,
|
||||
new LocalizedTypeDTO(HasRaceOfCompetitorContext.class.getName(), ""), null));
|
||||
DataRetrieverChainDefinitionDTO retrieverChain = new DataRetrieverChainDefinitionDTO("",
|
||||
RacingEventService.class.getName(), retrieverLevels);
|
||||
|
||||
ModifiableStatisticQueryDefinitionDTO queryDefinition = new ModifiableStatisticQueryDefinitionDTO("en",
|
||||
statistic, aggregator, retrieverChain);
|
||||
|
||||
HashMap<FunctionDTO, HashSet<? extends Serializable>> retrieverlevel3_FilterSelection = new HashMap<>();
|
||||
FunctionDTO filterDimension0 = new FunctionDTO(true, "getCompetitor().getName()",
|
||||
HasRaceOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
HashSet<Serializable> filterDimension0_Selection = new HashSet<>();
|
||||
competitorNames.forEach(filterDimension0_Selection::add);
|
||||
retrieverlevel3_FilterSelection.put(filterDimension0, filterDimension0_Selection);
|
||||
queryDefinition.setFilterSelectionFor(retrieverChain.getRetrieverLevel(3), retrieverlevel3_FilterSelection);
|
||||
|
||||
FunctionDTO dimensionToGroupBy0 = new FunctionDTO(true, "getTrackedRaceContext().getRace().getName()",
|
||||
HasRaceOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy0);
|
||||
|
||||
FunctionDTO dimensionToGroupBy1 = new FunctionDTO(true, "getCompetitor().getName()",
|
||||
HasRaceOfCompetitorContext.class.getName(), String.class.getName(), new ArrayList<String>(), "", 0);
|
||||
queryDefinition.appendDimensionToGroupBy(dimensionToGroupBy1);
|
||||
|
||||
return queryDefinition;
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfilesDTO;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreferences;
|
||||
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
|
||||
|
||||
/**
|
||||
* {@link SailingAction} implementation to load sailor profiles for the currently logged in user to bee shown on the
|
||||
* sailor profiles overview page, preparing the appropriate data structure.
|
||||
*/
|
||||
public class GetAllSailorProfilesAction implements SailingAction<SailorProfilesDTO>, SailorProfileConverter {
|
||||
|
||||
public GetAllSailorProfilesAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public SailorProfilesDTO execute(SailingDispatchContext ctx) throws DispatchException {
|
||||
SailorProfilePreferences preferences = ctx.getPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME);
|
||||
SailorProfilesDTO result;
|
||||
List<SailorProfileDTO> list = new ArrayList<>();
|
||||
|
||||
// load sailor profile from preferences if available
|
||||
if (preferences != null) {
|
||||
StreamSupport.stream(preferences.getSailorProfiles().spliterator(), false)
|
||||
.forEach(s -> list.add(convertSailorProfilePreferenceToDto(s,
|
||||
ctx.getRacingEventService().getCompetitorAndBoatStore(), ctx.getRacingEventService())));
|
||||
}
|
||||
result = new SailorProfilesDTO(list);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.NoWindException;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.ParticipatedEventDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.ParticipatedRegattaDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileEventsDTO;
|
||||
import com.sap.sailing.gwt.server.HomeServiceUtil;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreferences;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
|
||||
|
||||
/**
|
||||
* {@link SailingAction} implementation to load all events, the competitors in a sailor profile with a specific uuid for
|
||||
* the currently logged in user have participated in to be shown on the sailor profile details page in the events
|
||||
* container.
|
||||
*/
|
||||
public class GetEventsForSailorProfileAction implements SailingAction<SailorProfileEventsDTO>, SailorProfileConverter {
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public GetEventsForSailorProfileAction(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
public GetEventsForSailorProfileAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public SailorProfileEventsDTO execute(SailingDispatchContext ctx) throws DispatchException {
|
||||
|
||||
CompetitorAndBoatStore store = ctx.getRacingEventService().getCompetitorAndBoatStore();
|
||||
|
||||
SailorProfilePreferences prefs = ctx.getPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME);
|
||||
SailorProfilePreference pref = findSailorProfile(store, prefs);
|
||||
Collection<ParticipatedEventDTO> participatedEvents = new ArrayList<>();
|
||||
|
||||
// iterate over all existing events
|
||||
for (Event event : ctx.getRacingEventService().getAllEvents()) {
|
||||
Collection<ParticipatedRegattaDTO> participatedRegattas = new ArrayList<>();
|
||||
// iterate over the leaderboard groups
|
||||
for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) {
|
||||
if (leaderboardGroup.hasOverallLeaderboard()) {
|
||||
leaderboardGroup.getOverallLeaderboard();
|
||||
|
||||
}
|
||||
|
||||
// iterate over the leaderboards in each leaderboard group
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
|
||||
// check if this leaderboard contains at least one of the selected competitors
|
||||
Collection<Competitor> containedCompetitors = new ArrayList<>();
|
||||
for (Competitor competitor : pref.getCompetitors()) {
|
||||
if (leaderboard.getCompetitors() != null
|
||||
&& Util.contains(leaderboard.getCompetitors(), competitor)) {
|
||||
containedCompetitors.add(competitor);
|
||||
}
|
||||
}
|
||||
|
||||
// skip if none of the selected competitors is in this leaderboard
|
||||
if (containedCompetitors.size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// create and add ParticipatedRegattaDTO for each of the selected competitors who was in this
|
||||
// leaderboard
|
||||
for (Competitor competitor : containedCompetitors) {
|
||||
int rank = 0;
|
||||
try {
|
||||
rank = leaderboard.getTotalRankOfCompetitor(competitor, MillisecondsTimePoint.now());
|
||||
} catch (NoWindException e1) {
|
||||
// ignore
|
||||
}
|
||||
// final String leaderboardName = leaderboard.getDisplayName();
|
||||
final double points = leaderboard.getNetPoints(competitor, MillisecondsTimePoint.now());
|
||||
|
||||
// regatta name is equal to the leaderboard name
|
||||
String regattaName = leaderboard.getName();
|
||||
|
||||
Regatta regatta = ctx.getRacingEventService().getRegattaByName(regattaName);
|
||||
|
||||
if (regatta == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// skip, if the regatta is not part of this event (e.g. shared leaderboard group)
|
||||
if (!HomeServiceUtil.isPartOfEvent(event, leaderboard)) {
|
||||
|
||||
// skip, if overall leaderboard is not part of this event, don't skip if this is a regatta
|
||||
// during an event which is not part of an overall leaderboard
|
||||
if (leaderboardGroup.hasOverallLeaderboard()
|
||||
&& !HomeServiceUtil.isPartOfEvent(event, leaderboardGroup.getOverallLeaderboard()))
|
||||
continue;
|
||||
}
|
||||
|
||||
participatedRegattas.add(
|
||||
new ParticipatedRegattaDTO(regattaName, rank, new SimpleCompetitorWithIdDTO(competitor),
|
||||
"" + regatta.getId(), "" + event.getId(), points));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (participatedRegattas.size() > 0) {
|
||||
participatedEvents
|
||||
.add(new ParticipatedEventDTO(event.getName(), event.getId().toString(), participatedRegattas));
|
||||
}
|
||||
}
|
||||
|
||||
return new SailorProfileEventsDTO(participatedEvents);
|
||||
}
|
||||
|
||||
/** @return find SailorProfilePreference in SailorProfilePreferences by using {@link #uuid} */
|
||||
@GwtIncompatible
|
||||
private SailorProfilePreference findSailorProfile(CompetitorAndBoatStore store, SailorProfilePreferences prefs) {
|
||||
if (prefs == null) {
|
||||
throw new NullPointerException("no sailor profile present");
|
||||
} else {
|
||||
for (SailorProfilePreference p : prefs.getSailorProfiles()) {
|
||||
if (p.getUuid().equals(uuid)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
+348
@@ -0,0 +1,348 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.NavigableSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.base.Regatta;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.tracking.GPSFixMoving;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.domain.tracking.MarkPassing;
|
||||
import com.sap.sailing.domain.tracking.TrackedRace;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType.StatisticType;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileStatisticDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileStatisticDTO.SingleEntry;
|
||||
import com.sap.sailing.gwt.server.HomeServiceUtil;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreferences;
|
||||
import com.sap.sse.common.Distance;
|
||||
import com.sap.sse.common.Speed;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sse.common.settings.GwtIncompatible;
|
||||
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
|
||||
|
||||
/**
|
||||
* {@link SailingAction} implementation to load all events, the competitors in a sailor profile with a specific uuid for
|
||||
* the currently logged in user have participated in to be shown on the sailor profile details page in the events
|
||||
* container.
|
||||
*/
|
||||
public class GetNumericStatisticForSailorProfileAction
|
||||
implements SailingAction<SailorProfileStatisticDTO>, SailorProfileConverter {
|
||||
|
||||
private SailorProfileNumericStatisticType type;
|
||||
private UUID uuid;
|
||||
|
||||
public GetNumericStatisticForSailorProfileAction(UUID uuid, SailorProfileNumericStatisticType type) {
|
||||
this.uuid = uuid;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* GWT serialization only
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private GetNumericStatisticForSailorProfileAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public SailorProfileStatisticDTO execute(SailingDispatchContext ctx) throws DispatchException {
|
||||
final Map<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> result = new HashMap<>();
|
||||
|
||||
CompetitorAndBoatStore store = ctx.getRacingEventService().getCompetitorAndBoatStore();
|
||||
|
||||
SailorProfilePreferences prefs = ctx.getPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME);
|
||||
SailorProfilePreference pref = findSailorProfile(store, prefs);
|
||||
|
||||
for (Competitor competitor : pref.getCompetitors()) {
|
||||
final Aggregator aggregator = determineAggregator();
|
||||
if (aggregator == null) {
|
||||
continue;
|
||||
}
|
||||
for (Event event : ctx.getRacingEventService().getAllEvents()) {
|
||||
// determine end of event, or now in live case
|
||||
TimePoint end = event.getEndDate();
|
||||
if (end == null) {
|
||||
end = MillisecondsTimePoint.now();
|
||||
}
|
||||
for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
// check if this leaderboard contains at least one of the selected competitors
|
||||
if (!Util.contains(leaderboard.getCompetitors(), competitor)) {
|
||||
continue;
|
||||
}
|
||||
String regattaName = leaderboard.getName();
|
||||
Regatta regatta = ctx.getRacingEventService().getRegattaByName(regattaName);
|
||||
if (regatta == null) {
|
||||
continue;
|
||||
}
|
||||
// skip, if the leaderboard is not part of this event (e.g. shared leaderboard group)
|
||||
if (!HomeServiceUtil.isPartOfEvent(event, leaderboard)) {
|
||||
continue;
|
||||
}
|
||||
for (TrackedRace tr : leaderboard.getTrackedRaces()) {
|
||||
if (Util.contains(tr.getRace().getCompetitors(), competitor)) {
|
||||
extractValue(competitor, aggregator, end, leaderboard, tr, leaderboardGroup, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.put(new SimpleCompetitorWithIdDTO(competitor), aggregator.getResult());
|
||||
}
|
||||
List<String> competitorNames = StreamSupport.stream(pref.getCompetitors().spliterator(), false)
|
||||
.map(Competitor::getName).collect(Collectors.toList());
|
||||
String serializedQuery = DataMiningQueryCreatorForSailorProfiles.getSerializedDataMiningQuery(type,
|
||||
competitorNames);
|
||||
|
||||
keepOnlyBestIfNecessary(result, type.getAggregationType());
|
||||
return new SailorProfileStatisticDTO(result, serializedQuery);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is responsible for getting a Value and adding it to the aggregator based on the
|
||||
* SailorProfileNumericStatisticType
|
||||
*/
|
||||
@GwtIncompatible
|
||||
private void extractValue(Competitor competitor, final Aggregator aggregator, TimePoint end,
|
||||
Leaderboard leaderboard, TrackedRace tr, LeaderboardGroup leaderboardGroup, Event event) {
|
||||
switch (type) {
|
||||
case MAX_SPEED:
|
||||
getMaxSpeedInRaces(leaderboard, competitor, aggregator, tr, end, leaderboardGroup.getName(), event.getId());
|
||||
break;
|
||||
case BEST_DISTANCE_TO_START:
|
||||
aggregator.add(tr.getDistanceToStartLine(competitor, 0), tr.getStartOfRace(), tr.getStartOfRace(),
|
||||
tr.getRaceIdentifier(), leaderboard.getName(), leaderboardGroup.getName(), event.getId(),
|
||||
tr.getRace().getName());
|
||||
break;
|
||||
case BEST_STARTLINE_SPEED:
|
||||
Speed speed = tr.getSpeedWhenCrossingStartLine(competitor);
|
||||
aggregator.add(speed, tr.getStartOfRace(), tr.getStartOfRace(), tr.getRaceIdentifier(),
|
||||
leaderboard.getName(), leaderboardGroup.getName(), event.getId(), tr.getRace().getName());
|
||||
break;
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
Distance distance = tr.getDistanceToStartLine(competitor, 0);
|
||||
aggregator.add(distance, null, null, null, null, null, null, null);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** reduces result map to only the best competitor if statistic is not average */
|
||||
@GwtIncompatible
|
||||
private void keepOnlyBestIfNecessary(Map<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> results,
|
||||
StatisticType type) {
|
||||
|
||||
final Set<SimpleCompetitorWithIdDTO> competitorsToRemove = new HashSet<>();
|
||||
if (type == StatisticType.HIGHEST_IS_BEST || type == StatisticType.LOWEST_IS_BEST) {
|
||||
|
||||
// set best value to min/max depending whether highest/lowest is best
|
||||
double best = (type == StatisticType.HIGHEST_IS_BEST) ? Double.MIN_VALUE : Double.MAX_VALUE;
|
||||
SimpleCompetitorWithIdDTO bestCompetitor = null;
|
||||
|
||||
for (Entry<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> mapEntry : results.entrySet()) {
|
||||
for (SingleEntry statisticEntry : mapEntry.getValue()) {
|
||||
|
||||
// lower is better -> best must be bigger then the value of this entry to update the best
|
||||
// higher is better -> best must be smaller then the value of this entry to update the best
|
||||
if ((type == StatisticType.LOWEST_IS_BEST && best > statisticEntry.getValue())
|
||||
|| type == StatisticType.HIGHEST_IS_BEST && best < statisticEntry.getValue()) {
|
||||
best = statisticEntry.getValue();
|
||||
competitorsToRemove.add(bestCompetitor);
|
||||
bestCompetitor = mapEntry.getKey();
|
||||
} else {
|
||||
competitorsToRemove.add(mapEntry.getKey());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
competitorsToRemove.forEach(competitor -> results.remove(competitor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the required aggregator based on SailorProfileNumericStatisticType
|
||||
*/
|
||||
@GwtIncompatible
|
||||
private Aggregator determineAggregator() {
|
||||
final Aggregator aggregator;
|
||||
switch (type.getAggregationType()) {
|
||||
case AVERAGE:
|
||||
aggregator = new AverageAggregator();
|
||||
break;
|
||||
case HIGHEST_IS_BEST:
|
||||
aggregator = new MinMaxAggregator(true);
|
||||
break;
|
||||
case LOWEST_IS_BEST:
|
||||
aggregator = new MinMaxAggregator(false);
|
||||
break;
|
||||
default:
|
||||
aggregator = null;
|
||||
break;
|
||||
}
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private SingleEntry getMaxSpeedInRaces(Leaderboard leaderboard, Competitor competitor, Aggregator aggregator,
|
||||
TrackedRace tr, TimePoint endOfEvent, String bestLeaderboardGroupName, UUID eventId) {
|
||||
Pair<GPSFixMoving, Speed> bestFix = leaderboard.getMaximumSpeedOverGround(competitor, endOfEvent);
|
||||
SingleEntry newBetterResult = null;
|
||||
if (bestFix != null) {
|
||||
NavigableSet<MarkPassing> markPassings = tr.getMarkPassings(competitor);
|
||||
if (!markPassings.isEmpty()) {
|
||||
TimePoint from = markPassings.first().getTimePoint();
|
||||
// only count to last known markpassing (and finish as race end this way)
|
||||
TimePoint to = markPassings.last().getTimePoint();
|
||||
com.sap.sse.common.Util.Pair<GPSFixMoving, Speed> maxSpeed = tr.getTrack(competitor)
|
||||
.getMaximumSpeedOverGround(from, to);
|
||||
|
||||
if (maxSpeed != null && maxSpeed.getA() != null && maxSpeed.getB() != null) {
|
||||
aggregator.add(maxSpeed.getB(), bestFix.getA().getTimePoint(), tr.getStartOfRace(),
|
||||
tr.getRaceIdentifier(), leaderboard.getName(), bestLeaderboardGroupName, eventId,
|
||||
tr.getRace().getName());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return newBetterResult;
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private SailorProfilePreference findSailorProfile(CompetitorAndBoatStore store, SailorProfilePreferences prefs) {
|
||||
if (prefs == null) {
|
||||
throw new NullPointerException("no sailor profile present");
|
||||
} else {
|
||||
for (SailorProfilePreference p : prefs.getSailorProfiles()) {
|
||||
if (p.getUuid().equals(uuid)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper to reduce redundant code, that offers a simple interface to add new values. This class should be null
|
||||
* safe so that the caller does not have to ensure this
|
||||
*/
|
||||
@GwtIncompatible
|
||||
interface Aggregator {
|
||||
default void add(Distance distance, TimePoint bestTimePointOrNull, TimePoint startTimePointOrNull,
|
||||
RegattaAndRaceIdentifier regattaAndRaceIdentifierOrNull, String bestLeaderboardName,
|
||||
String bestLeaderboardGroupName, UUID eventId, String bestRaceName) {
|
||||
if (distance != null) {
|
||||
add(distance.getMeters(), bestTimePointOrNull, startTimePointOrNull, regattaAndRaceIdentifierOrNull,
|
||||
bestLeaderboardName, bestLeaderboardGroupName, eventId, bestRaceName);
|
||||
}
|
||||
}
|
||||
|
||||
void add(Double value, TimePoint bestTime, TimePoint startTime, RegattaAndRaceIdentifier race,
|
||||
String bestLeaderboardName, String bestLeaderboardGroupName, UUID bestEventId, String bestRaceName);
|
||||
|
||||
default void add(Speed speed, TimePoint bestTimePointOrNull, TimePoint startTimePointOrNull,
|
||||
RegattaAndRaceIdentifier regattaAndRaceIdentifierOrNull, String bestLeaderboardName,
|
||||
String bestLeaderboardGroupName, UUID eventId, String bestRaceName) {
|
||||
if (speed != null) {
|
||||
add(speed.getKnots(), bestTimePointOrNull, startTimePointOrNull, regattaAndRaceIdentifierOrNull,
|
||||
bestLeaderboardName, bestLeaderboardGroupName, eventId, bestRaceName);
|
||||
}
|
||||
}
|
||||
|
||||
ArrayList<SingleEntry> getResult();
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private static class MinMaxAggregator implements Aggregator {
|
||||
private boolean max;
|
||||
private Double bestValue;
|
||||
private String bestLeaderboardName;
|
||||
private String bestLeaderboardGroupName;
|
||||
private String bestRaceName;
|
||||
private UUID bestEventId;
|
||||
private TimePoint bestTimePoint;
|
||||
private TimePoint startTimePoint;
|
||||
private RegattaAndRaceIdentifier bestRace;
|
||||
|
||||
public MinMaxAggregator(boolean max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Double value, TimePoint bestTime, TimePoint startTime, RegattaAndRaceIdentifier race,
|
||||
String bestLeaderboardName, String bestLeaderboardGroupName, UUID bestEventId, String bestRaceName) {
|
||||
if (value != null) {
|
||||
if (this.bestValue == null || ((max && value > bestValue) || (!max && value < bestValue))) {
|
||||
this.bestValue = value;
|
||||
this.bestTimePoint = bestTime;
|
||||
this.startTimePoint = startTime;
|
||||
this.bestRace = race;
|
||||
this.bestLeaderboardName = bestLeaderboardName;
|
||||
this.bestLeaderboardGroupName = bestLeaderboardGroupName;
|
||||
this.bestEventId = bestEventId;
|
||||
this.bestRaceName = bestRaceName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<SingleEntry> getResult() {
|
||||
ArrayList<SingleEntry> result = new ArrayList<>();
|
||||
if (bestValue != null) {
|
||||
// not all timepoints are serializable, ensure we use a compatible one
|
||||
result.add(new SingleEntry(bestValue, bestRace, new MillisecondsTimePoint(bestTimePoint.asMillis()),
|
||||
new MillisecondsTimePoint(startTimePoint.asMillis()), bestLeaderboardName,
|
||||
bestLeaderboardGroupName, bestEventId, bestRaceName));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private static class AverageAggregator implements Aggregator {
|
||||
double averageCount = 0;
|
||||
Double average = null;
|
||||
|
||||
@Override
|
||||
public void add(Double value, TimePoint bestTime, TimePoint startTime, RegattaAndRaceIdentifier race,
|
||||
String bestLeaderboardName, String bestLeaderboardGroupName, UUID eventId, String bestRaceName) {
|
||||
if (value != null) {
|
||||
averageCount++;
|
||||
if (average == null) {
|
||||
average = value;
|
||||
} else {
|
||||
average = average * ((averageCount - 1) / averageCount) + value * (1 / averageCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<SingleEntry> getResult() {
|
||||
ArrayList<SingleEntry> result = new ArrayList<>();
|
||||
if (averageCount > 0) {
|
||||
result.add(new SingleEntry(average, null, null, null, null, null, null, null));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreferences;
|
||||
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
|
||||
|
||||
/**
|
||||
* {@link SailingAction} implementation to load a sailor profile with a specific uuid for the currently logged in user
|
||||
* to bee shown on the sailor profile details page, preparing the appropriate data structure.
|
||||
*/
|
||||
public class GetSailorProfileAction implements SailingAction<SailorProfileDTO>, SailorProfileConverter {
|
||||
|
||||
private UUID uuid;
|
||||
|
||||
public GetSailorProfileAction(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
protected GetSailorProfileAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public SailorProfileDTO execute(SailingDispatchContext ctx) throws DispatchException {
|
||||
CompetitorAndBoatStore store = ctx.getRacingEventService().getCompetitorAndBoatStore();
|
||||
|
||||
SailorProfilePreferences prefs = ctx.getPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME);
|
||||
SailorProfilePreference pref = findSailorProfile(store, prefs);
|
||||
|
||||
return convertSailorProfilePreferenceToDto(pref, store, ctx.getRacingEventService());
|
||||
}
|
||||
|
||||
/** find the SailorProfilePreference in SailorProfilePreferences from the {@link #uuid} */
|
||||
@GwtIncompatible
|
||||
private SailorProfilePreference findSailorProfile(CompetitorAndBoatStore store, SailorProfilePreferences prefs) {
|
||||
SailorProfilePreference result = null;
|
||||
if (prefs != null) {
|
||||
for (SailorProfilePreference p : prefs.getSailorProfiles()) {
|
||||
if (p.getUuid().equals(uuid)) {
|
||||
result = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* {@link UpdateSailorProfileAction} implementation to remove a sailor profile identified by the UUID for the currently
|
||||
* logged in user.
|
||||
*/
|
||||
public class RemoveSailorProfileAction extends UpdateSailorProfileAction {
|
||||
|
||||
public RemoveSailorProfileAction(UUID uuid) {
|
||||
super(uuid);
|
||||
}
|
||||
|
||||
protected RemoveSailorProfileAction() {
|
||||
}
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.domain.base.CompetitorWithBoat;
|
||||
import com.sap.sailing.domain.base.Event;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.domain.leaderboard.Leaderboard;
|
||||
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.BadgeDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.server.RacingEventService;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
|
||||
public interface SailorProfileConverter {
|
||||
/**
|
||||
* converts the {@link SailorProfilePreference} to a {@link SailorProfileDTO} by converting the competitors and
|
||||
* retrieve the corresponding boatclasses.
|
||||
*
|
||||
* @param notFoundOnServer
|
||||
* @return converted {@link SailorProfileDTO} from {@link SailorProfilePreference}
|
||||
*/
|
||||
@GwtIncompatible
|
||||
default SailorProfileDTO convertSailorProfilePreferenceToDto(final SailorProfilePreference pref,
|
||||
final CompetitorAndBoatStore store, RacingEventService racingEventService) {
|
||||
SailorProfileDTO result;
|
||||
if (pref == null) {
|
||||
result = new SailorProfileDTO(true);
|
||||
} else {
|
||||
result = new SailorProfileDTO(pref.getUuid(), pref.getName(),
|
||||
convertCompetitorsToDTOs(pref.getCompetitors()), new ArrayList<BadgeDTO>(),
|
||||
getCorrespondingBoatClassesDTOs(pref.getCompetitors(), store, racingEventService));
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
/** @return converted list of SimpleCompetitorWithIdDTOs from Competitors without null values */
|
||||
@GwtIncompatible
|
||||
default List<SimpleCompetitorWithIdDTO> convertCompetitorsToDTOs(final Iterable<Competitor> comps) {
|
||||
return StreamSupport.stream(comps.spliterator(), false).filter(c -> c != null)
|
||||
.map(c -> new SimpleCompetitorWithIdDTO(c)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* get the corresponding boat class for each competitor in the list of competitors from the
|
||||
* {@link CompetitorAndBoatStore} and convert it to {@link BoatClassDTO}
|
||||
*/
|
||||
@GwtIncompatible
|
||||
default Set<BoatClassDTO> getCorrespondingBoatClassesDTOs(final Iterable<Competitor> comps,
|
||||
final CompetitorAndBoatStore store, RacingEventService racingEventService) {
|
||||
final Set<BoatClassDTO> boatclasses = new HashSet<>();
|
||||
for (Competitor c : comps) {
|
||||
if (c != null) {
|
||||
CompetitorWithBoat cwd = store.getExistingCompetitorWithBoatById(c.getId());
|
||||
if (cwd != null && cwd.hasBoat() && cwd.getBoat().getBoatClass() != null) {
|
||||
BoatClassDTO dto = convertBoatClassToDTO(cwd.getBoat().getBoatClass());
|
||||
boatclasses.add(dto);
|
||||
} else {
|
||||
BoatClass boatclass = getBoatClassForCompetitorWithoutBoatClass(racingEventService, c);
|
||||
if (boatclass != null) {
|
||||
boatclasses.add(convertBoatClassToDTO(boatclass));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return boatclasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* get the corresponding boat class for each competitor in the list of competitors from the leaderboard via the
|
||||
* {@link RacingEventService}
|
||||
*/
|
||||
@GwtIncompatible
|
||||
default BoatClass getBoatClassForCompetitorWithoutBoatClass(RacingEventService racingEventService, Competitor c) {
|
||||
for (Event event : racingEventService.getAllEvents()) {
|
||||
for (LeaderboardGroup leaderboardGroup : event.getLeaderboardGroups()) {
|
||||
for (Leaderboard leaderboard : leaderboardGroup.getLeaderboards()) {
|
||||
for (Competitor competitor : leaderboard.getCompetitors()) {
|
||||
if (competitor.getId().equals(c.getId())) {
|
||||
if (leaderboard.getBoatClass() != null) {
|
||||
return leaderboard.getBoatClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return converted BoatClassDTO from BoatClass */
|
||||
@GwtIncompatible
|
||||
default BoatClassDTO convertBoatClassToDTO(BoatClass bc) {
|
||||
return new BoatClassDTO(bc.getName(), bc.getDisplayName(), bc.getHullLength(), bc.getHullBeam());
|
||||
}
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.gwt.home.communication.SailingAction;
|
||||
import com.sap.sailing.gwt.home.communication.SailingDispatchContext;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreferences;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.gwt.dispatch.shared.exceptions.DispatchException;
|
||||
|
||||
/**
|
||||
* {@link SailingAction} implementation to update attributes of a sailor profile identified by its UUID for the
|
||||
* currently logged in user. Returns an updated SailorProfileDTO to bee shown on the sailor profile details page,
|
||||
* preparing the appropriate data structure.
|
||||
*/
|
||||
public abstract class UpdateSailorProfileAction implements SailingAction<SailorProfileDTO>, SailorProfileConverter {
|
||||
|
||||
protected UUID uuid;
|
||||
|
||||
public UpdateSailorProfileAction(UUID uuid) {
|
||||
this.uuid = uuid;
|
||||
}
|
||||
|
||||
protected UpdateSailorProfileAction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@GwtIncompatible
|
||||
public SailorProfileDTO execute(SailingDispatchContext ctx) throws DispatchException {
|
||||
CompetitorAndBoatStore store = ctx.getRacingEventService().getCompetitorAndBoatStore();
|
||||
|
||||
SailorProfilePreferences prefs = ctx.getPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME);
|
||||
if (prefs == null) {
|
||||
prefs = new SailorProfilePreferences(store);
|
||||
}
|
||||
Pair<SailorProfilePreferences, SailorProfilePreference> pair = findAndUpdateCorrectPreference(store, prefs);
|
||||
prefs = pair.getA();
|
||||
ctx.setPreferenceForCurrentUser(SailorProfilePreferences.PREF_NAME, prefs);
|
||||
return pair.getB() != null
|
||||
? convertSailorProfilePreferenceToDto(pair.getB(), store, ctx.getRacingEventService())
|
||||
: null;
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
private Pair<SailorProfilePreferences, SailorProfilePreference> findAndUpdateCorrectPreference(
|
||||
CompetitorAndBoatStore store, SailorProfilePreferences prefs) {
|
||||
List<SailorProfilePreference> sailorProfilePreferences = new ArrayList<>();
|
||||
SailorProfilePreference sp = null;
|
||||
if (prefs == null) {
|
||||
throw new NullPointerException("no sailor profile present");
|
||||
} else {
|
||||
// 1) copy existing SailorProfilePreference objects from SailorProfilePreferences into list except the
|
||||
// changed
|
||||
// SailorProfilePreference
|
||||
// 2) add the new version of the SailorProfilePreference to the list
|
||||
// 3) add the list to a new SailorProfilePreferences
|
||||
for (SailorProfilePreference p : prefs.getSailorProfiles()) {
|
||||
if (!p.getUuid().equals(uuid)) {
|
||||
sailorProfilePreferences.add(p);
|
||||
} else {
|
||||
sp = updatePreference(store, p);
|
||||
if (sp != null) {
|
||||
sailorProfilePreferences.add(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if might be a new SailorProfile (unknown UUID), so create a new preference for it
|
||||
if (sp == null) {
|
||||
sp = updatePreference(store, null);
|
||||
if (sp != null) {
|
||||
sailorProfilePreferences.add(sp);
|
||||
}
|
||||
}
|
||||
|
||||
prefs = new SailorProfilePreferences(store);
|
||||
prefs.setSailorProfiles(sailorProfilePreferences);
|
||||
}
|
||||
return new Pair<SailorProfilePreferences, SailorProfilePreference>(prefs, sp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the updated SailorProfilePreference from the original {@link p}. If this returns null, p will be removed
|
||||
*/
|
||||
@GwtIncompatible
|
||||
protected SailorProfilePreference updatePreference(CompetitorAndBoatStore store, SailorProfilePreference p) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
/**
|
||||
* {@link UpdateSailorProfileAction} implementation to update the competitors of a sailor profile identified by the UUID
|
||||
* for the currently logged in user.
|
||||
*/
|
||||
public class UpdateSailorProfileCompetitorsAction extends UpdateSailorProfileAction {
|
||||
|
||||
private ArrayList<SimpleCompetitorWithIdDTO> competitors = new ArrayList<>();
|
||||
|
||||
public UpdateSailorProfileCompetitorsAction(UUID uuid, Iterable<SimpleCompetitorWithIdDTO> competitors) {
|
||||
super(uuid);
|
||||
Util.addAll(competitors, this.competitors);
|
||||
}
|
||||
|
||||
protected UpdateSailorProfileCompetitorsAction() {
|
||||
}
|
||||
|
||||
/** convert SimpleCompetitorIdWithDTOs to Competitors */
|
||||
@GwtIncompatible
|
||||
private Iterable<Competitor> convertCompetitorDTOs(final Iterable<SimpleCompetitorWithIdDTO> comps,
|
||||
CompetitorAndBoatStore store) {
|
||||
return StreamSupport.stream(comps.spliterator(), false)
|
||||
.map(c -> store.getExistingCompetitorByIdAsString(c.getIdAsString())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
@Override
|
||||
protected SailorProfilePreference updatePreference(CompetitorAndBoatStore store, SailorProfilePreference p) {
|
||||
return new SailorProfilePreference(store, p, convertCompetitorDTOs(this.competitors, store));
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.gwt.home.communication.user.profile.sailorprofile;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GwtIncompatible;
|
||||
import com.sap.sailing.domain.base.CompetitorAndBoatStore;
|
||||
import com.sap.sailing.server.impl.preferences.model.SailorProfilePreference;
|
||||
|
||||
/**
|
||||
* {@link UpdateSailorProfileAction} implementation to load update the title of a sailor profile with the UUID for the
|
||||
* currently logged in user.
|
||||
*/
|
||||
public class UpdateSailorProfileTitleAction extends UpdateSailorProfileAction {
|
||||
|
||||
private String title;
|
||||
|
||||
public UpdateSailorProfileTitleAction(UUID uuid, String title) {
|
||||
super(uuid);
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
protected UpdateSailorProfileTitleAction() {
|
||||
}
|
||||
|
||||
@GwtIncompatible
|
||||
@Override
|
||||
protected SailorProfilePreference updatePreference(CompetitorAndBoatStore store, SailorProfilePreference p) {
|
||||
return new SailorProfilePreference(store, p, this.title);
|
||||
}
|
||||
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
package com.sap.sailing.gwt.home.desktop.partials.desktopaccordion;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.SpanElement;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.mobile.partials.section.MobileSection;
|
||||
import com.sap.sailing.gwt.home.shared.utils.CollapseAnimation;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
|
||||
/**
|
||||
* This object is similar to the accordion ({@link MobileSection})on mobile. It has a header with a title and a
|
||||
* collapsable content panel.
|
||||
*/
|
||||
public class DesktopAccordion extends Composite {
|
||||
|
||||
interface DesktopAccordionUiBinder extends UiBinder<Widget, DesktopAccordion> {
|
||||
}
|
||||
|
||||
private static DesktopAccordionUiBinder uiBinder = GWT.create(DesktopAccordionUiBinder.class);
|
||||
|
||||
@UiField
|
||||
SpanElement titleUi;
|
||||
@UiField
|
||||
FlowPanel contentPanelUi;
|
||||
@UiField
|
||||
HTMLPanel headerDivUi;
|
||||
@UiField
|
||||
StringMessages i18n;
|
||||
|
||||
private boolean isContentVisible;
|
||||
|
||||
private final CollapseAnimation animation;
|
||||
|
||||
/** true, as soon as the accordion was expanded once. */
|
||||
private boolean wasOpenend;
|
||||
private List<AccordionExpansionListener> accordionListeners;
|
||||
|
||||
private boolean expanded;
|
||||
|
||||
public interface AccordionExpansionListener {
|
||||
void onExpansion(boolean expanded);
|
||||
}
|
||||
|
||||
public DesktopAccordion() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public DesktopAccordion(boolean showInitial) {
|
||||
accordionListeners = new ArrayList<>();
|
||||
DesktopAccordionResources.INSTANCE.css().ensureInjected();
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
|
||||
this.titleUi.setInnerText("Title");
|
||||
|
||||
headerDivUi.addDomHandler(new ClickHandler() {
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
onHeaderCicked();
|
||||
}
|
||||
}, ClickEvent.getType());
|
||||
|
||||
isContentVisible = showInitial;
|
||||
animation = new CollapseAnimation(contentPanelUi.getElement(), showInitial);
|
||||
updateAccordionState();
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
titleUi.setInnerText(title);
|
||||
}
|
||||
|
||||
private void onHeaderCicked() {
|
||||
isContentVisible = !isContentVisible;
|
||||
updateContentVisibility();
|
||||
}
|
||||
|
||||
private void updateContentVisibility() {
|
||||
animation.animate(isContentVisible);
|
||||
updateAccordionState();
|
||||
}
|
||||
|
||||
public void addWidget(Widget w) {
|
||||
contentPanelUi.add(w);
|
||||
}
|
||||
|
||||
private void updateAccordionState() {
|
||||
if (isContentVisible) {
|
||||
getElement().removeClassName(DesktopAccordionResources.INSTANCE.css().accordionCollapsed());
|
||||
if (!wasOpenend) {
|
||||
wasOpenend = true;
|
||||
expanded = true;
|
||||
for (AccordionExpansionListener accordionListener : accordionListeners) {
|
||||
accordionListener.onExpansion(expanded);
|
||||
}
|
||||
accordionListeners.clear();
|
||||
}
|
||||
} else {
|
||||
expanded = false;
|
||||
getElement().addClassName(DesktopAccordionResources.INSTANCE.css().accordionCollapsed());
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
contentPanelUi.clear();
|
||||
accordionListeners.clear();
|
||||
}
|
||||
|
||||
public void addAccordionListener(AccordionExpansionListener listener) {
|
||||
accordionListeners.add(listener);
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return expanded;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="shr" type="com.sap.sailing.gwt.home.shared.resources.SharedHomeResources" />
|
||||
<ui:with field="ares"
|
||||
type="com.sap.sailing.gwt.home.desktop.partials.desktopaccordion.DesktopAccordionResources" />
|
||||
|
||||
<g:HTMLPanel>
|
||||
<div class="{ares.css.accordion}">
|
||||
<g:HTMLPanel ui:field="headerDivUi" addStyleNames="{ares.css.accordionHeader}">
|
||||
<div class="{res.mediaCss.grid}">
|
||||
<div class="{res.mediaCss.small2} {res.mediaCss.columns}">
|
||||
<div class="{ares.css.accordionTitle}">
|
||||
<span ui:field="titleUi" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="{res.mediaCss.small10} {res.mediaCss.columns} {ares.css.accordionHeaderRight}">
|
||||
<div class="{ares.css.accordionHeaderRightArrow}">
|
||||
<img src="{shr.arrowDownGrey.getSafeUri}" class="{ares.css.accordionArrowImage}"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
<g:FlowPanel addStyleNames="{ares.css.accordionContentPanel}" ui:field="contentPanelUi" />
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
.accordionTitle {
|
||||
padding: 1.11111111111111em;
|
||||
font-size: 1.2em;
|
||||
font-weight: 700;
|
||||
line-height: 1.333333333em;
|
||||
}
|
||||
|
||||
.accordionHeader {
|
||||
background-color: #f2f2f2;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
|
||||
.accordionHeaderRight {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.accordionHeaderRightArrow {
|
||||
padding: 1.11111111em;
|
||||
font-size: 1.2em;
|
||||
font-weight: 700;
|
||||
line-height: 1.333333333em;
|
||||
right: 1.111111111111em;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.accordionCollapsed .accordionArrowImage {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
-ms-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.accordionArrowImage {
|
||||
width: 1.3333333333em;
|
||||
vertical-align: middle;
|
||||
-webkit-transform: rotate(180deg);
|
||||
-moz-transform: rotate(180deg);
|
||||
-ms-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
-webkit-transition: -webkit-transform 0.4s;
|
||||
-moz-transition: -moz-transform 0.4s;
|
||||
transition: transform 0.4s;
|
||||
}
|
||||
|
||||
.accordion {
|
||||
border: 1px solid #dedede;
|
||||
border-radius: .333333333333333em;
|
||||
-webkit-transition: opacity 0.1s;
|
||||
-moz-transition: opacity 0.1s;
|
||||
transition: opacity 0.1s;
|
||||
}
|
||||
|
||||
.accordionContentPanel {
|
||||
float: none;
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
.accordionEmptyMessage {
|
||||
margin: 1.033333333333333em;
|
||||
font-style: italic;
|
||||
line-height: 2em;
|
||||
text-align: center;
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.sap.sailing.gwt.home.desktop.partials.desktopaccordion;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
|
||||
public interface DesktopAccordionResources extends ClientBundle {
|
||||
|
||||
public static final DesktopAccordionResources INSTANCE = GWT.create(DesktopAccordionResources.class);
|
||||
|
||||
@Source("DesktopAccordionResources.gss")
|
||||
SailorProfilesCss css();
|
||||
|
||||
public interface SailorProfilesCss extends CssResource {
|
||||
|
||||
String accordionTitle();
|
||||
|
||||
String accordionHeader();
|
||||
|
||||
String accordionHeaderRight();
|
||||
|
||||
String accordionHeaderRightArrow();
|
||||
|
||||
String accordionArrowImage();
|
||||
|
||||
String accordionCollapsed();
|
||||
|
||||
String accordion();
|
||||
|
||||
String accordionContentPanel();
|
||||
|
||||
String accordionEmptyMessage();
|
||||
}
|
||||
}
|
||||
+3
@@ -16,6 +16,9 @@
|
||||
.accordion_content {
|
||||
font-size: inherit;
|
||||
}
|
||||
.accordion_panel {
|
||||
float: none;
|
||||
}
|
||||
.eventsoverviewrecent {
|
||||
font-size: 1rem;
|
||||
padding-top: 2em;
|
||||
|
||||
+1
@@ -16,6 +16,7 @@ public interface EventsOverviewRecentResources extends ClientBundle {
|
||||
String accordion();
|
||||
String accordion_trigger();
|
||||
String accordion_content();
|
||||
String accordion_panel();
|
||||
String eventsoverviewrecent();
|
||||
String eventsoverviewrecent_year();
|
||||
String accordioncollapsed();
|
||||
|
||||
+48
-5
@@ -1,30 +1,73 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.event.regatta.leaderboardtab;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.google.gwt.place.shared.Prefix;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.regatta.AbstractEventRegattaPlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.PlaceTokenPrefixes;
|
||||
import com.sap.sailing.gwt.home.shared.places.event.AbstractEventPlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.event.EventContext;
|
||||
import com.sap.sse.common.Util;
|
||||
|
||||
public class RegattaLeaderboardPlace extends AbstractEventRegattaPlace {
|
||||
public RegattaLeaderboardPlace(String id, String regattaId) {
|
||||
|
||||
private final Set<String> selectedCompetitors = new HashSet<>();
|
||||
|
||||
public RegattaLeaderboardPlace(String id, String regattaId, Set<String> selectedCompetitors) {
|
||||
super(id, regattaId);
|
||||
if (selectedCompetitors != null) {
|
||||
this.selectedCompetitors.addAll(selectedCompetitors);
|
||||
}
|
||||
}
|
||||
|
||||
public RegattaLeaderboardPlace(EventContext context) {
|
||||
|
||||
public RegattaLeaderboardPlace(String id, String regattaId) {
|
||||
this(id, regattaId, null);
|
||||
}
|
||||
|
||||
public RegattaLeaderboardPlace(EventContext context, Set<String> selectedCompetitors) {
|
||||
super(context);
|
||||
if (selectedCompetitors != null) {
|
||||
this.selectedCompetitors.addAll(selectedCompetitors);
|
||||
}
|
||||
}
|
||||
|
||||
public RegattaLeaderboardPlace(EventContext context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractEventRegattaPlace newInstanceWithContext(EventContext ctx) {
|
||||
return new RegattaLeaderboardPlace(ctx);
|
||||
return new RegattaLeaderboardPlace(ctx, null);
|
||||
}
|
||||
|
||||
public Set<String> getSelectedCompetitors() {
|
||||
return selectedCompetitors;
|
||||
}
|
||||
|
||||
@Prefix(PlaceTokenPrefixes.RegattaLeaderboard)
|
||||
public static class Tokenizer extends AbstractEventPlace.Tokenizer<RegattaLeaderboardPlace> {
|
||||
|
||||
/** short parameter name to decrease total URL length */
|
||||
private static final String PARAM_SELECTED_COMPETITORS = "sc";
|
||||
|
||||
@Override
|
||||
protected Map<String, Set<String>> getParameters(RegattaLeaderboardPlace place) {
|
||||
Map<String, Set<String>> map = super.getParameters(place);
|
||||
place.getSelectedCompetitors().forEach(value -> Util.addToValueSet(map, PARAM_SELECTED_COMPETITORS, value));
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegattaLeaderboardPlace getRealPlace(EventContext context, Map<String, Set<String>> parameters) {
|
||||
return new RegattaLeaderboardPlace(context, parameters.get(PARAM_SELECTED_COMPETITORS));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RegattaLeaderboardPlace getRealPlace(EventContext context) {
|
||||
return new RegattaLeaderboardPlace(context);
|
||||
// Is not called since the calling method is overridden above
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-3
@@ -1,5 +1,9 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.event.regatta.leaderboardtab;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
@@ -14,6 +18,7 @@ import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.sap.sailing.domain.common.DetailType;
|
||||
import com.sap.sailing.domain.common.RaceIdentifier;
|
||||
import com.sap.sailing.domain.common.dto.CompetitorDTO;
|
||||
import com.sap.sailing.domain.common.dto.LeaderboardDTO;
|
||||
import com.sap.sailing.domain.common.dto.RaceColumnDTO;
|
||||
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
|
||||
@@ -33,15 +38,13 @@ import com.sap.sailing.gwt.home.shared.refresh.RefreshManager;
|
||||
import com.sap.sailing.gwt.home.shared.refresh.RefreshManagerWithErrorAndBusy;
|
||||
import com.sap.sailing.gwt.home.shared.refresh.RefreshableWidget;
|
||||
import com.sap.sailing.gwt.settings.client.leaderboard.MultiRaceLeaderboardSettings;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateListener;
|
||||
import com.sap.sailing.gwt.ui.client.LeaderboardUpdateProvider;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.leaderboard.MultiRaceLeaderboardPanel;
|
||||
import com.sap.sse.gwt.client.shared.settings.DefaultOnSettingsLoadedCallback;
|
||||
import com.sap.sse.gwt.dispatch.shared.commands.CollectionResult;
|
||||
|
||||
/**
|
||||
* Created by pgtaboada on 25.11.14.
|
||||
*/
|
||||
public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<RegattaLeaderboardPlace> {
|
||||
interface MyBinder extends UiBinder<FlowPanel, RegattaLeaderboardTabView> {
|
||||
}
|
||||
@@ -119,6 +122,43 @@ public class RegattaLeaderboardTabView extends SharedLeaderboardRegattaTabView<R
|
||||
if (leaderboardPanel.getLeaderboard() != null) {
|
||||
leaderboard.updatedLeaderboard(leaderboardPanel.getLeaderboard());
|
||||
}
|
||||
|
||||
selectCompetitorsFromURLArgumentsWhenReady(myPlace, leaderboardPanel);
|
||||
}
|
||||
|
||||
private void selectCompetitorsFromURLArgumentsWhenReady(final RegattaLeaderboardPlace myPlace,
|
||||
MultiRaceLeaderboardPanel leaderboardPanel) {
|
||||
// select competitors from URL arguments if present
|
||||
leaderboardPanel.addLeaderboardUpdateListener(new LeaderboardUpdateListener() {
|
||||
@Override
|
||||
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
|
||||
if (!myPlace.getSelectedCompetitors().isEmpty()) {
|
||||
Collection<CompetitorDTO> newSelection = new ArrayList<>();
|
||||
for (String selectedCompetitorId : myPlace.getSelectedCompetitors()) {
|
||||
try {
|
||||
UUID uuid = UUID.fromString(selectedCompetitorId);
|
||||
for (CompetitorDTO competitor : leaderboard.competitors) {
|
||||
if (selectedCompetitorId.equals(competitor.getIdAsString())) {
|
||||
newSelection.add(competitor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
//
|
||||
} catch (IllegalArgumentException e) {
|
||||
GWT.log(e.getMessage());
|
||||
}
|
||||
}
|
||||
leaderboardPanel.setSelection(newSelection);
|
||||
if(!newSelection.isEmpty()) {
|
||||
leaderboardPanel.removeLeaderboardUpdateListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void currentRaceSelected(RaceIdentifier raceIdentifier, RaceColumnDTO raceColumn) {
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
if (leaderboardPanel == null) {
|
||||
|
||||
+1
@@ -19,6 +19,7 @@
|
||||
<g:HTMLPanel addStyleNames="{res.mediaCss.grid}">
|
||||
<h1 class="{res.mediaCss.small12} {res.mediaCss.columns}"><ui:text from="{i18n.moreLoginInformationHeadline}" /></h1>
|
||||
<p class="{res.mediaCss.small12} {res.mediaCss.columns}"><ui:text from="{i18n.moreLoginInformationIntroduction}" /></p>
|
||||
<login:MoreLoginInformationContent addStyleNames="{style.clear}" title="{i18n.moreLoginInformationSectionSailorProfilesHeading}" image="{local_res.sailorprofiles}" imageOnLeft="false" content="{i18n.moreLoginInformationSectionSailorProfilesDescription}" />
|
||||
<login:MoreLoginInformationContent addStyleNames="{style.clear}" title="{i18n.moreLoginInformationSectionUserSettingsHeading}" image="{local_res.settings}" imageOnLeft="true" content="{i18n.moreLoginInformationSectionUserSettingsDescription}" />
|
||||
<login:MoreLoginInformationContent title="{i18n.strategySimulator}" image="{local_res.simulator}" imageOnLeft="false" content="{i18n.moreLoginInformationSectionStrategySimulatorDescription}" />
|
||||
<login:MoreLoginInformationContent title="{i18n.moreLoginInformationSectionUserNotificationsHeading}" image="{local_res.notifications}" imageOnLeft="true" content="{i18n.moreLoginInformationSectionUserNotificationsDescription}" />
|
||||
|
||||
+6
@@ -13,6 +13,7 @@ import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanel;
|
||||
import com.sap.sailing.gwt.common.client.controls.tabbar.TabPanelPlaceSelectionEvent;
|
||||
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.preferencestab.UserProfilePreferencesTabView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileTabView;
|
||||
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
@@ -41,6 +42,9 @@ public class TabletAndDesktopUserProfileView extends Composite implements UserPr
|
||||
@UiField(provided = true)
|
||||
UserProfilePreferencesTabView preferencesTabUi;
|
||||
|
||||
@UiField(provided = true)
|
||||
SailorProfileTabView sailorProfileTabUi;
|
||||
|
||||
private final FlagImageResolver flagImageResolver;
|
||||
|
||||
public TabletAndDesktopUserProfileView(FlagImageResolver flagImageResolver) {
|
||||
@@ -56,6 +60,8 @@ public class TabletAndDesktopUserProfileView extends Composite implements UserPr
|
||||
|
||||
preferencesTabUi = new UserProfilePreferencesTabView(flagImageResolver);
|
||||
|
||||
sailorProfileTabUi = new SailorProfileTabView(flagImageResolver);
|
||||
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -15,6 +15,9 @@
|
||||
<c:tabcontent title="{i18n.favoritesAndNotifications}">
|
||||
<s:preferencestab.UserProfilePreferencesTabView ui:field="preferencesTabUi" />
|
||||
</c:tabcontent>
|
||||
<c:tabcontent title="{i18n.sailorProfiles}">
|
||||
<s:sailorprofiletab.SailorProfileTabView ui:field="sailorProfileTabUi" />
|
||||
</c:tabcontent>
|
||||
<c:tabcontent title="{i18n.settings}">
|
||||
<s:settingstab.UserProfileSettingsTabView ui:field="settingsTabUi" />
|
||||
</c:tabcontent>
|
||||
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile;
|
||||
|
||||
import com.sap.sailing.gwt.home.shared.app.ClientFactoryWithDispatch;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.ui.client.SailingClientFactory;
|
||||
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
|
||||
import com.sap.sse.security.ui.authentication.WithAuthenticationManager;
|
||||
import com.sap.sse.security.ui.authentication.WithUserService;
|
||||
|
||||
public interface UserProfileClientFactory extends ClientFactoryWithDispatch, SailingClientFactory, ErrorAndBusyClientFactory, WithAuthenticationManager, WithUserService {
|
||||
public interface UserProfileClientFactory
|
||||
extends SailingClientFactory, WithAuthenticationManager, ClientFactoryWithDispatchAndErrorAndUserService {
|
||||
}
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.HasLoginFormAndFactory;
|
||||
|
||||
/**
|
||||
* simple adapter to use the client factory from a {@link UserProfileView.Presenter} as a client factory in
|
||||
* {@link HasLoginFormAndFactory}
|
||||
*/
|
||||
public class ClientFactoryAdapter implements HasLoginFormAndFactory {
|
||||
private final UserProfileView.Presenter presenter;
|
||||
|
||||
public ClientFactoryAdapter(UserProfileView.Presenter presenter) {
|
||||
this.presenter = presenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTriggerLoginForm() {
|
||||
presenter.doTriggerLoginForm();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientFactoryWithDispatchAndErrorAndUserService getClientFactory() {
|
||||
return presenter.getClientFactory();
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
|
||||
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
|
||||
|
||||
public interface SailingProfileOverviewPresenter extends NotLoggedInPresenter, NeedsAuthenticationContext {
|
||||
EditSailorProfileDetailsView.Presenter getSharedSailorProfilePresenter();
|
||||
|
||||
ClientFactoryWithDispatchAndErrorAndUserService getClientFactory();
|
||||
|
||||
FlagImageResolver getFlagImageResolver();
|
||||
|
||||
void removeSailorProfile(UUID uuid);
|
||||
}
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
import com.google.gwt.safehtml.client.SafeHtmlTemplates;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeUri;
|
||||
|
||||
public interface SailorProfileDesktopResources extends ClientBundle {
|
||||
|
||||
public static final SailorProfileDesktopResources INSTANCE = GWT.create(SailorProfileDesktopResources.class);
|
||||
public static final SailorProfileDesktopTemplates TEMPLATE = GWT.create(SailorProfileDesktopTemplates.class);
|
||||
|
||||
@Source("SailorProfiles.gss")
|
||||
SailorProfilesCss css();
|
||||
|
||||
public interface SailorProfileDesktopTemplates extends SafeHtmlTemplates {
|
||||
@Template("<a href='{0}'><img src='{1}' style='-webkit-transform: rotate(270deg);-moz-transform: rotate(270deg);-ms-transform: rotate(270deg); transform: rotate(270deg);width:1.33333333333em; cursor:pointer; min-width:1.33333333em'/></a>")
|
||||
SafeHtml navigator(SafeUri url, SafeUri imageUrl);
|
||||
|
||||
@Template("<button type='button' tabindex='-1' style='background-color: #e94a1b'>{0}</button>")
|
||||
SafeHtml removeButtonCell(SafeHtml title);
|
||||
}
|
||||
|
||||
public interface SailorProfilesCss extends CssResource {
|
||||
String showAndEditHeader();
|
||||
|
||||
String eventsTable();
|
||||
|
||||
String eventsTableTitle();
|
||||
|
||||
String eventsTableEmpty();
|
||||
|
||||
String eventsTablePanel();
|
||||
|
||||
String overviewTable();
|
||||
|
||||
String overviewTableFooter();
|
||||
|
||||
String overviewTableEmpty();
|
||||
|
||||
String clickableColumn();
|
||||
|
||||
String statisticsTableHeaderIcon();
|
||||
|
||||
String statisticsTableHeader();
|
||||
|
||||
String statisticsTableHeaderRight();
|
||||
|
||||
String addButton();
|
||||
|
||||
String marginLastTable();
|
||||
|
||||
String boatClassColumn();
|
||||
}
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.ButtonCell;
|
||||
import com.google.gwt.cell.client.TextCell;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.gwt.common.client.BoatClassImageResolver;
|
||||
import com.sap.sailing.gwt.common.client.SharedResources;
|
||||
import com.sap.sailing.gwt.common.theme.component.celltable.DesignedCellTableResources;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.BadgeDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events.NavigatorColumn;
|
||||
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
|
||||
import com.sap.sailing.gwt.home.shared.partials.dialog.ConfirmDialogFactory;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileOverview;
|
||||
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.celltable.SortedCellTable;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
|
||||
|
||||
/** Sailor Profile Overview where all the sailor profiles are listed */
|
||||
public class SailorProfileOverviewImpl extends Composite implements SailorProfileOverview {
|
||||
private static ApplicationHistoryMapper historyMapper = GWT.create(ApplicationHistoryMapper.class);
|
||||
|
||||
interface MyBinder extends UiBinder<Widget, SailorProfileOverviewImpl> {
|
||||
}
|
||||
|
||||
private static MyBinder uiBinder = GWT.create(MyBinder.class);
|
||||
private SailingProfileOverviewPresenter presenter;
|
||||
|
||||
@UiField
|
||||
StringMessages i18n;
|
||||
|
||||
@UiField(provided = true)
|
||||
final SortedCellTable<SailorProfileDTO> sailorProfilesTable = new SortedCellTable<>(0,
|
||||
DesignedCellTableResources.INSTANCE);
|
||||
|
||||
@UiField
|
||||
FlowPanel footerUi;
|
||||
|
||||
@UiField(provided = true)
|
||||
AuthorizedContentDecoratorDesktop decoratorUi;
|
||||
|
||||
@Override
|
||||
public void setPresenter(SailingProfileOverviewPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
SharedSailorProfileResources.INSTANCE.css().ensureInjected();
|
||||
SailorProfileDesktopResources.INSTANCE.css().ensureInjected();
|
||||
SharedResources.INSTANCE.mainCss().ensureInjected();
|
||||
|
||||
decoratorUi = new AuthorizedContentDecoratorDesktop(presenter);
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
setupTable();
|
||||
createFooter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileList(Collection<SailorProfileDTO> entries) {
|
||||
sailorProfilesTable.setPageSize(entries.size());
|
||||
sailorProfilesTable.setList(entries);
|
||||
}
|
||||
|
||||
private void setupTable() {
|
||||
|
||||
sailorProfilesTable.addColumn(profileNameColumn, i18n.profileName());
|
||||
// sailorProfilesTable.addColumn(badgeColumn, i18n.badges());
|
||||
sailorProfilesTable.addColumn(competitorColumn, i18n.competitors());
|
||||
sailorProfilesTable.addColumn(boatClassColumn, i18n.boatClasses());
|
||||
sailorProfilesTable.addColumn(navigatorColumn);
|
||||
sailorProfilesTable.addColumn(removeColumn);
|
||||
// sailorProfilesTable.setColumnWidth(boatClassColumn, "6em");
|
||||
|
||||
addWordwrapStyle(profileNameColumn);
|
||||
addWordwrapStyle(badgeColumn);
|
||||
addWordwrapStyle(competitorColumn);
|
||||
addBoatclassStyle(boatClassColumn);
|
||||
|
||||
addButtonStyle(navigatorColumn);
|
||||
navigatorColumn.setFieldUpdater((int index, SailorProfileDTO entry, String value) -> presenter
|
||||
.getClientFactory().getPlaceController().goTo(getTargetPlace(entry)));
|
||||
|
||||
removeColumn.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell());
|
||||
removeColumn.setFieldUpdater((int index, SailorProfileDTO dto, String value) -> ConfirmDialogFactory
|
||||
.showConfirmDialog(StringMessages.INSTANCE.sailorProfileRemoveMessage(), new DialogCallback<Void>() {
|
||||
@Override
|
||||
public void ok(Void editedObject) {
|
||||
presenter.removeSailorProfile(dto.getKey());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
}));
|
||||
|
||||
sailorProfilesTable.addCellPreviewHandler(e -> {
|
||||
/* no navigation for remove column */
|
||||
if ("click".equals(e.getNativeEvent().getType()) && e.getColumn() != 5) {
|
||||
presenter.getClientFactory().getPlaceController().goTo(new SailorProfilePlace(e.getValue().getKey()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addWordwrapStyle(Column<SailorProfileDTO, ?> col) {
|
||||
col.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().textCellWordWrap() + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().clickableColumn());
|
||||
}
|
||||
|
||||
private void addBoatclassStyle(Column<SailorProfileDTO, ?> col) {
|
||||
col.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().textCellWordWrap() + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().clickableColumn() + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().boatClassColumn());
|
||||
}
|
||||
|
||||
private void addButtonStyle(Column<?, ?> col) {
|
||||
col.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell() + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().clickableColumn());
|
||||
}
|
||||
|
||||
private void createFooter() {
|
||||
Button addButton = new Button(i18n.addSailorProfileMessage());
|
||||
addButton.addStyleName(SharedResources.INSTANCE.mainCss().buttonprimary());
|
||||
addButton.addStyleName(SharedResources.INSTANCE.mainCss().button());
|
||||
addButton.addStyleName(SailorProfileDesktopResources.INSTANCE.css().addButton());
|
||||
footerUi.add(addButton);
|
||||
addButton.addClickHandler(
|
||||
event -> presenter.getClientFactory().getPlaceController().goTo(new SailorProfilePlace(true)));
|
||||
}
|
||||
|
||||
private final Column<SailorProfileDTO, String> profileNameColumn = new Column<SailorProfileDTO, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(SailorProfileDTO entry) {
|
||||
return entry.getName();
|
||||
}
|
||||
};
|
||||
private final Column<SailorProfileDTO, String> badgeColumn = new Column<SailorProfileDTO, String>(new TextCell()) {
|
||||
@Override
|
||||
public String getValue(SailorProfileDTO entry) {
|
||||
if (entry != null && entry.getBadges() != null) {
|
||||
return entry.getBadges().stream().map(BadgeDTO::getName).collect(Collectors.joining(", "));
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
private final Column<SailorProfileDTO, SailorProfileDTO> boatClassColumn = new Column<SailorProfileDTO, SailorProfileDTO>(
|
||||
new AbstractCell<SailorProfileDTO>() {
|
||||
@Override
|
||||
public void render(Context context, SailorProfileDTO value, SafeHtmlBuilder sb) {
|
||||
for (BoatClassDTO boatclass : value.getBoatclasses()) {
|
||||
sb.append(SharedSailorProfileResources.TEMPLATES.buildBoatclassIcon(BoatClassImageResolver
|
||||
.getBoatClassIconResource(boatclass.getName()).getSafeUri().asString()));
|
||||
}
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public SailorProfileDTO getValue(SailorProfileDTO object) {
|
||||
return object;
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<SailorProfileDTO, String> competitorColumn = new Column<SailorProfileDTO, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(SailorProfileDTO entry) {
|
||||
if (entry != null && entry.getCompetitors() != null) {
|
||||
return entry.getCompetitors().stream().map(c -> c.getName()).collect(Collectors.joining(", "));
|
||||
}
|
||||
return "-";
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<SailorProfileDTO, String> navigatorColumn = new NavigatorColumn<SailorProfileDTO>() {
|
||||
@Override
|
||||
public String getValue(SailorProfileDTO object) {
|
||||
return "#" + historyMapper.getToken(getTargetPlace(object));
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<SailorProfileDTO, String> removeColumn = new Column<SailorProfileDTO, String>(
|
||||
new RemoveButtonCell()) {
|
||||
@Override
|
||||
public String getValue(SailorProfileDTO entry) {
|
||||
return "X";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public NeedsAuthenticationContext authentificationContextConsumer() {
|
||||
return decoratorUi;
|
||||
}
|
||||
|
||||
private SailorProfilePlace getTargetPlace(SailorProfileDTO entry) {
|
||||
return new SailorProfilePlace(entry.getKey());
|
||||
}
|
||||
|
||||
private class RemoveButtonCell extends ButtonCell {
|
||||
@Override
|
||||
public void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
sb.append(SailorProfileDesktopResources.TEMPLATE.removeButtonCell(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
|
||||
xmlns:c="urn:import:com.google.gwt.user.cellview.client">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res"
|
||||
type="com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources" />
|
||||
<um:AuthorizedContentDecoratorDesktop ui:field="decoratorUi">
|
||||
<um:content>
|
||||
<g:HTMLPanel addStyleNames="{res.mediaCss.grid} {res.mainCss.spacermarginbottommediumsmall}">
|
||||
<div class="{res.mediaCss.column} {res.mediaCss.small12} {res.mainCss.spacermargintopmedium}">
|
||||
<c:CellTable ui:field="sailorProfilesTable" addStyleNames="{local_res.css.overviewTable}">
|
||||
<c:emptyTableWidget>
|
||||
<g:Label text="{i18n.noDataFound}" addStyleNames="{local_res.css.overviewTableEmpty}" />
|
||||
</c:emptyTableWidget>
|
||||
</c:CellTable>
|
||||
<g:FlowPanel addStyleNames="{local_res.css.overviewTableFooter}" ui:field="footerUi" />
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</um:content>
|
||||
</um:AuthorizedContentDecoratorDesktop>
|
||||
</ui:UiBinder>
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfilesDTO;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView.Presenter;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfilePresenter;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.HasLoginFormAndFactory;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileOverview;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileView;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
|
||||
|
||||
public class SailorProfileOverviewImplPresenter implements SailingProfileOverviewPresenter {
|
||||
|
||||
private final SailorProfileView view;
|
||||
private final HasLoginFormAndFactory loginAndFactory;
|
||||
private final EditSailorProfileDetailsView.Presenter sharedSailorProfilePresenter;
|
||||
private final FlagImageResolver flagImageResolver;
|
||||
|
||||
public SailorProfileOverviewImplPresenter(final SailorProfileView view,
|
||||
final HasLoginFormAndFactory loginAndFactory, final FlagImageResolver flagImageResolver) {
|
||||
this(view, loginAndFactory, flagImageResolver,
|
||||
new EditSailorProfilePresenter(loginAndFactory.getClientFactory()));
|
||||
}
|
||||
|
||||
public SailorProfileOverviewImplPresenter(final SailorProfileView view,
|
||||
final HasLoginFormAndFactory loginAndFactory, final FlagImageResolver flagImageResolver, final EditSailorProfilePresenter presenter) {
|
||||
this.view = view;
|
||||
this.loginAndFactory = loginAndFactory;
|
||||
this.sharedSailorProfilePresenter = presenter;
|
||||
this.flagImageResolver = flagImageResolver;
|
||||
view.setPresenter(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientFactoryWithDispatchAndErrorAndUserService getClientFactory() {
|
||||
return loginAndFactory.getClientFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Presenter getSharedSailorProfilePresenter() {
|
||||
return sharedSailorProfilePresenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
|
||||
view.authentificationContextConsumer().setAuthenticationContext(authenticationContext);
|
||||
if (authenticationContext.isLoggedIn() && view instanceof SailorProfileOverview) {
|
||||
sharedSailorProfilePresenter.getDataProvider().loadSailorProfiles(new AsyncCallback<SailorProfilesDTO>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfilesDTO result) {
|
||||
((SailorProfileOverview) view).setProfileList(result.getEntries());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
GWT.log(caught.getMessage(), caught);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSailorProfile(UUID uuid) {
|
||||
sharedSailorProfilePresenter.getDataProvider().removeSailorProfile(uuid, new AsyncCallback<SailorProfileDTO>() {
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
GWT.log(caught.getMessage(), caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfileDTO result) {
|
||||
sharedSailorProfilePresenter.getDataProvider()
|
||||
.loadSailorProfiles(new AsyncCallback<SailorProfilesDTO>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfilesDTO result) {
|
||||
if (view instanceof SailorProfileOverview) {
|
||||
((SailorProfileOverview) view).setProfileList(result.getEntries());
|
||||
} else {
|
||||
getClientFactory().getPlaceController().goTo(new SailorProfilePlace(null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
GWT.log(caught.getMessage(), caught);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doTriggerLoginForm() {
|
||||
loginAndFactory.doTriggerLoginForm();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlagImageResolver getFlagImageResolver() {
|
||||
return this.flagImageResolver;
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.sap.sailing.gwt.common.client.controls.tabbar.TabView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileTabView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.UserProfileView;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.SailorProfileDetails;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileView;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.security.ui.authentication.app.AuthenticationContext;
|
||||
|
||||
/** main entry point for sailor profiles overview on desktop */
|
||||
public class SailorProfileTabView extends Composite implements UserProfileTabView<SailorProfilePlace> {
|
||||
|
||||
private SailingProfileOverviewPresenter currentPresenter;
|
||||
private final FlagImageResolver flagImageResolver;
|
||||
|
||||
private UserProfileView.Presenter ownPresenter;
|
||||
private AcceptsOneWidget contentArea;
|
||||
private SailorProfilePlace place;
|
||||
|
||||
public SailorProfileTabView(FlagImageResolver flagImageResolver) {
|
||||
this.flagImageResolver = flagImageResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<SailorProfilePlace> getPlaceClassForActivation() {
|
||||
return SailorProfilePlace.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabView.State getState() {
|
||||
return TabView.State.VISIBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(SailorProfilePlace myPlace, AcceptsOneWidget contentArea) {
|
||||
this.place = myPlace;
|
||||
this.contentArea = contentArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationContext(AuthenticationContext authenticationContext) {
|
||||
UUID uuid = place.getSailorProfileUuid();
|
||||
SailorProfileView view;
|
||||
if (uuid != null || place.isCreateNew()) {
|
||||
view = new SailorProfileDetails();
|
||||
} else {
|
||||
view = new SailorProfileOverviewImpl();
|
||||
}
|
||||
|
||||
this.currentPresenter = new SailorProfileOverviewImplPresenter(view,
|
||||
new ClientFactoryAdapter(this.ownPresenter), flagImageResolver);
|
||||
currentPresenter.setAuthenticationContext(authenticationContext);
|
||||
contentArea.setWidget(view);
|
||||
|
||||
if (authenticationContext.isLoggedIn()) {
|
||||
if (uuid != null || place.isCreateNew()) {
|
||||
if (place.isCreateNew()) {
|
||||
currentPresenter.getSharedSailorProfilePresenter().getDataProvider()
|
||||
.createNewEntry(UUID.randomUUID(), StringMessages.INSTANCE.newSailorProfileName());
|
||||
} else {
|
||||
currentPresenter.getSharedSailorProfilePresenter().getDataProvider()
|
||||
.loadSailorProfile(place.getSailorProfileUuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SailorProfilePlace placeToFire() {
|
||||
return new SailorProfilePlace(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(UserProfileView.Presenter ownPresenter) {
|
||||
this.ownPresenter = ownPresenter;
|
||||
}
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
.showAndEditHeader {
|
||||
font-size: 1.866666666666667em;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-left: 1em;
|
||||
margin-top: 0.7143em;
|
||||
}
|
||||
|
||||
.eventsTable {
|
||||
width: 100%;
|
||||
border-radius: 0px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.eventsTable .eventsTableEmpty {
|
||||
margin: 1.033333333333333em;
|
||||
font-style: italic;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.eventsTable td {
|
||||
vertical-align: middle;
|
||||
padding-top: 0.73333335em;
|
||||
}
|
||||
|
||||
.eventsTableTitle {
|
||||
background-color: #008FCC;
|
||||
vertical-align: middle;
|
||||
padding-top: 1.333em;
|
||||
padding-bottom: 1.3333em;
|
||||
padding-left: 1.333em;
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.eventsTablePanel {
|
||||
border: 1px solid #dedede;
|
||||
border-radius: .333333333333333em;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.marginLastTable:last-child {
|
||||
margin-bottom: 1.333333333333333em;
|
||||
}
|
||||
|
||||
.overviewTable {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.overviewTable .overviewTableEmpty {
|
||||
margin: 1.033333333333333em;
|
||||
font-style: italic;
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.overviewTable td {
|
||||
vertical-align: middle;
|
||||
padding-top: 0.73333335em;
|
||||
}
|
||||
|
||||
.overviewTableFooter {
|
||||
padding-top: 1.333em;
|
||||
}
|
||||
|
||||
.clickableColumn {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.statisticsTableHeaderIcon {
|
||||
width: 2em;
|
||||
height: auto;
|
||||
margin-right: 1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.statisticsTableHeader {
|
||||
padding-left: 1em;
|
||||
padding-bottom: 1em;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.statisticsTableHeaderRight {
|
||||
display: inline-block;
|
||||
right: 1em;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-transform: rotate(270deg);
|
||||
-moz-transform: rotate(270deg);
|
||||
-o-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
|
||||
.addButton {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.boatClassColumn {
|
||||
min-width: 120px;
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailingProfileOverviewPresenter;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView;
|
||||
import com.sap.sailing.gwt.home.shared.usermanagement.decorator.AuthorizedContentDecoratorDesktop;
|
||||
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
|
||||
|
||||
/**
|
||||
* View element which wraps around {@link ShowAndEditSailorProfile} and provides an
|
||||
* {@link AuthorizedContentDecoratorDesktop}
|
||||
*/
|
||||
public class SailorProfileDetails extends Composite implements SailorProfileDetailsView {
|
||||
|
||||
interface MyBinder extends UiBinder<Widget, SailorProfileDetails> {
|
||||
}
|
||||
|
||||
private static MyBinder uiBinder = GWT.create(MyBinder.class);
|
||||
|
||||
@UiField(provided = true)
|
||||
AuthorizedContentDecoratorDesktop decoratorUi;
|
||||
@UiField(provided = true)
|
||||
ShowAndEditSailorProfile editSailorProfileUi;
|
||||
|
||||
@Override
|
||||
public void setPresenter(SailingProfileOverviewPresenter presenter) {
|
||||
decoratorUi = new AuthorizedContentDecoratorDesktop(presenter);
|
||||
editSailorProfileUi = new ShowAndEditSailorProfile(presenter.getSharedSailorProfilePresenter(),
|
||||
presenter.getFlagImageResolver(), this, presenter.getClientFactory().getUserService());
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
presenter.getSharedSailorProfilePresenter().getDataProvider().setView(editSailorProfileUi);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NeedsAuthenticationContext authentificationContextConsumer() {
|
||||
return decoratorUi;
|
||||
}
|
||||
|
||||
public EditSailorProfileDetailsView getEditView() {
|
||||
return editSailorProfileUi;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
|
||||
xmlns:up="urn:import:com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details">
|
||||
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:style>
|
||||
.table {
|
||||
width: 100%;
|
||||
}
|
||||
.table .empty {
|
||||
margin: 1.033333333333333em;
|
||||
font-style: italic;
|
||||
line-height: 2em;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel addStyleNames="{res.mediaCss.grid} {res.mainCss.spacermarginbottommediumsmall}">
|
||||
<um:AuthorizedContentDecoratorDesktop ui:field="decoratorUi">
|
||||
<um:content>
|
||||
<up:ShowAndEditSailorProfile ui:field="editSailorProfileUi" />
|
||||
</um:content>
|
||||
</um:AuthorizedContentDecoratorDesktop>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details;
|
||||
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileView;
|
||||
|
||||
public interface SailorProfileDetailsView extends SailorProfileView {
|
||||
|
||||
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.ParticipatedEventDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileEventsDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileStatisticDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileStatisticDTO.SingleEntry;
|
||||
import com.sap.sailing.gwt.home.desktop.partials.desktopaccordion.DesktopAccordion;
|
||||
import com.sap.sailing.gwt.home.desktop.partials.desktopaccordion.DesktopAccordion.AccordionExpansionListener;
|
||||
import com.sap.sailing.gwt.home.desktop.partials.desktopaccordion.DesktopAccordionResources;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events.SailorProfileEventsTable;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.statistic.SailorProfileStatisticTable;
|
||||
import com.sap.sailing.gwt.home.shared.partials.editable.EditableSuggestedMultiSelectionCompetitor;
|
||||
import com.sap.sailing.gwt.home.shared.partials.editable.InlineEditLabel;
|
||||
import com.sap.sailing.gwt.home.shared.partials.listview.BoatClassListView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.DataMiningQueryForSailorProfilesPersistor;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.shared.settings.SailingSettingsConstants;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.gwt.client.Notification;
|
||||
import com.sap.sse.gwt.client.Notification.NotificationType;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
* Implementation of {@link EditSailorProfileDetailsView} where users can view the details of a SailorProfile and edit
|
||||
* them. The data is loaded when the accordion is opened for the first time.
|
||||
*/
|
||||
public class ShowAndEditSailorProfile extends Composite implements EditSailorProfileDetailsView {
|
||||
|
||||
private static SharedSailorProfileUiBinder uiBinder = GWT.create(SharedSailorProfileUiBinder.class);
|
||||
|
||||
interface SharedSailorProfileUiBinder extends UiBinder<Widget, ShowAndEditSailorProfile> {
|
||||
}
|
||||
|
||||
@UiField
|
||||
StringMessages i18n;
|
||||
|
||||
@UiField(provided = true)
|
||||
EditableSuggestedMultiSelectionCompetitor competitorSelectionUi;
|
||||
@UiField
|
||||
InlineEditLabel titleUi;
|
||||
@UiField
|
||||
BoatClassListView boatClassesUi;
|
||||
|
||||
@UiField
|
||||
DesktopAccordion accordionEventsUi;
|
||||
@UiField
|
||||
DesktopAccordion accordionStatisticsUi;
|
||||
@UiField
|
||||
DesktopAccordion accordionPolarDiagramUi;
|
||||
|
||||
Label eventsEmptyUi;
|
||||
|
||||
private final EditSailorProfileDetailsView.Presenter presenter;
|
||||
|
||||
private FlagImageResolver flagImageResolver;
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public ShowAndEditSailorProfile(EditSailorProfileDetailsView.Presenter presenter,
|
||||
FlagImageResolver flagImageResolver, SailorProfileDetailsView parent, UserService userService) {
|
||||
this.presenter = presenter;
|
||||
this.flagImageResolver = flagImageResolver;
|
||||
this.userService = userService;
|
||||
presenter.getDataProvider().setView(this);
|
||||
competitorSelectionUi = new EditableSuggestedMultiSelectionCompetitor(presenter.getCompetitorPresenter(),
|
||||
flagImageResolver);
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
SharedSailorProfileResources.INSTANCE.css().ensureInjected();
|
||||
SailorProfileDesktopResources.INSTANCE.css().ensureInjected();
|
||||
boatClassesUi.setText(i18n.boatClasses());
|
||||
accordionPolarDiagramUi.setVisible(false);
|
||||
}
|
||||
|
||||
private void setupTitleChangeListener(final UUID uuid) {
|
||||
// setup title change handler
|
||||
titleUi.clearTextChangeHandlers();
|
||||
titleUi.addTextChangeHandler((text) -> {
|
||||
presenter.getDataProvider().updateTitle(uuid, text);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntry(SailorProfileDTO entry) {
|
||||
competitorSelectionUi.setSelectedItems(entry.getCompetitors());
|
||||
titleUi.setText(entry.getName());
|
||||
boatClassesUi.setEmptyMessage(StringMessages.INSTANCE.pleaseSelectCompetitorFirst());
|
||||
boatClassesUi.setItems(entry.getBoatclasses());
|
||||
accordionEventsUi.clear();
|
||||
|
||||
// Get events asynchronously
|
||||
presenter.getDataProvider().getEvents(entry.getKey(), new AsyncCallback<SailorProfileEventsDTO>() {
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
GWT.log(caught.getMessage(), caught);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfileEventsDTO result) {
|
||||
appendEmptyMessageIfNecessary(result);
|
||||
for (ParticipatedEventDTO dto : result.getParticipatedEvents()) {
|
||||
SailorProfileEventsTable table = new SailorProfileEventsTable(flagImageResolver,
|
||||
presenter.getPlaceController(), dto);
|
||||
accordionEventsUi.addWidget(table);
|
||||
}
|
||||
}
|
||||
|
||||
/** adds empty widget */
|
||||
private void appendEmptyMessageIfNecessary(SailorProfileEventsDTO result) {
|
||||
if (Util.isEmpty(result.getParticipatedEvents())) {
|
||||
createEventsEmptyUiIfNecessary();
|
||||
accordionEventsUi.addWidget(eventsEmptyUi);
|
||||
} else if (eventsEmptyUi != null && eventsEmptyUi.isAttached()) {
|
||||
eventsEmptyUi.removeFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
/** creates empty widget */
|
||||
private void createEventsEmptyUiIfNecessary() {
|
||||
if (eventsEmptyUi == null) {
|
||||
eventsEmptyUi = new Label(StringMessages.INSTANCE.noEventsFoundForCompetitors());
|
||||
DesktopAccordionResources.INSTANCE.css().ensureInjected();
|
||||
eventsEmptyUi.addStyleName(DesktopAccordionResources.INSTANCE.css().accordionEmptyMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
accordionStatisticsUi.clear();
|
||||
|
||||
setupTables(entry);
|
||||
setupTitleChangeListener(entry.getKey());
|
||||
|
||||
}
|
||||
|
||||
/** create tables for statistic types */
|
||||
private void setupTables(SailorProfileDTO entry) {
|
||||
DataMiningQueryForSailorProfilesPersistor.removeDMQueriesFromLocalStorage();
|
||||
for (SailorProfileNumericStatisticType type : SailorProfileNumericStatisticType.values()) {
|
||||
SailorProfileStatisticTable table = new SailorProfileStatisticTable(flagImageResolver, type, i18n,
|
||||
userService);
|
||||
accordionStatisticsUi.addWidget(table);
|
||||
if (accordionStatisticsUi.isExpanded()) {
|
||||
updateStatistic(entry, type, table);
|
||||
} else {
|
||||
// load the statistic data when the accordion is expanded for the first time
|
||||
accordionStatisticsUi.addAccordionListener(new AccordionExpansionListener() {
|
||||
@Override
|
||||
public void onExpansion(boolean expanded) {
|
||||
if (expanded) {
|
||||
updateStatistic(entry, type, table);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** retrieve and update the statistic for a given type of a sailor profile entry */
|
||||
private void updateStatistic(SailorProfileDTO entry, SailorProfileNumericStatisticType type,
|
||||
SailorProfileStatisticTable table) {
|
||||
presenter.getDataProvider().getStatisticFor(entry.getKey(), type,
|
||||
new AsyncCallback<SailorProfileStatisticDTO>() {
|
||||
|
||||
private String navigationUrl;
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
Notification.notify(i18n.couldNotDetermineStatistic(), NotificationType.WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfileStatisticDTO answer) {
|
||||
ArrayList<Pair<SimpleCompetitorWithIdDTO, SingleEntry>> data = new ArrayList<>();
|
||||
for (Entry<SimpleCompetitorWithIdDTO, ArrayList<SingleEntry>> entry : answer.getResult()
|
||||
.entrySet()) {
|
||||
for (SingleEntry value : entry.getValue()) {
|
||||
data.add(new Pair<SimpleCompetitorWithIdDTO, SingleEntry>(entry.getKey(), value));
|
||||
}
|
||||
}
|
||||
if (answer.getDataMiningQuery() != null) {
|
||||
final String identifier = SailingSettingsConstants.DATAMINING_QUERY_PREFIX
|
||||
+ UUID.randomUUID().toString();
|
||||
navigationUrl = "DataMining.html?q=" + identifier;
|
||||
table.setNavigationTarget(this::func);
|
||||
DataMiningQueryForSailorProfilesPersistor.writeDMQueriesToLocalStorageIfPossible(answer,
|
||||
identifier);
|
||||
}
|
||||
table.setData(data);
|
||||
}
|
||||
|
||||
String func(Object o) {
|
||||
return navigationUrl;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:lv="urn:import:com.sap.sailing.gwt.home.shared.partials.listview"
|
||||
xmlns:dac="urn:import:com.sap.sailing.gwt.home.desktop.partials.desktopaccordion"
|
||||
xmlns:ms="urn:import:com.sap.sailing.gwt.home.shared.partials.editable">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="sprd"
|
||||
type="com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources" />
|
||||
|
||||
<g:HTMLPanel addStyleNames="{res.mediaCss.grid} {res.mainCss.spacermarginbottommediumsmall}">
|
||||
<ms:InlineEditLabel ui:field="titleUi" addStyleNames="{sprd.css.showAndEditHeader}" />
|
||||
<div class="{res.mediaCss.column}">
|
||||
<ms:EditableSuggestedMultiSelectionCompetitor
|
||||
ui:field="competitorSelectionUi"
|
||||
addStyleNames="{res.mediaCss.column} {res.mainCss.spacermargintopmediumsmall} {res.mediaCss.small12} {res.mediaCss.medium6}" />
|
||||
<lv:BoatClassListView ui:field="boatClassesUi"
|
||||
addStyleNames="{res.mediaCss.column} {res.mainCss.spacermargintopmediumsmall} {res.mediaCss.small12} {res.mediaCss.medium6}" />
|
||||
<div class="{res.mediaCss.column} {res.mainCss.spacermargintopmediumsmall} {res.mediaCss.small12}">
|
||||
<dac:DesktopAccordion ui:field="accordionEventsUi" title="{i18n.events}" />
|
||||
</div>
|
||||
<div class="{res.mediaCss.column} {res.mainCss.spacermargintopmediumsmall} {res.mediaCss.small12}">
|
||||
<dac:DesktopAccordion ui:field="accordionStatisticsUi" title="{i18n.statistics}" />
|
||||
</div>
|
||||
<div class="{res.mediaCss.column} {res.mainCss.spacermargintopmediumsmall} {res.mediaCss.small12}">
|
||||
<dac:DesktopAccordion ui:field="accordionPolarDiagramUi"
|
||||
title="{i18n.polarSheetChart}" />
|
||||
</div>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.SpanElement;
|
||||
import com.google.gwt.dom.client.Style.Position;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorDTO;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
|
||||
public class CompetitorWithoutClubnameItemDescription extends Widget {
|
||||
|
||||
private static LocalUiBinder uiBinder = GWT.create(LocalUiBinder.class);
|
||||
|
||||
interface LocalUiBinder extends UiBinder<Element, CompetitorWithoutClubnameItemDescription> {
|
||||
}
|
||||
|
||||
@UiField DivElement flagImageUi;
|
||||
@UiField SpanElement sailIdUi;
|
||||
|
||||
public CompetitorWithoutClubnameItemDescription(SimpleCompetitorDTO competitor,
|
||||
FlagImageResolver flagImageResolver) {
|
||||
setElement(uiBinder.createAndBindUi(this));
|
||||
flagImageUi.getStyle().setBackgroundImage("url('" + flagImageResolver.getFlagImageUri(
|
||||
competitor.getFlagImageURL(), competitor.getTwoLetterIsoCountryCode()).asString() + "')");
|
||||
sailIdUi.setInnerText(competitor.getShortInfo());
|
||||
}
|
||||
|
||||
public void fixFlagPosition(int offsetTop) {
|
||||
flagImageUi.getStyle().setPosition(Position.RELATIVE);
|
||||
flagImageUi.getStyle().setTop(offsetTop, Unit.PX);
|
||||
}
|
||||
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res"
|
||||
type="com.sap.sailing.gwt.home.shared.partials.multiselection.SuggestedMultiSelectionResources" />
|
||||
<ui:with field="spr" type="com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources" />
|
||||
<ui:style>
|
||||
.middle-aligned {
|
||||
vertical-align:middle;
|
||||
}
|
||||
</ui:style>
|
||||
<div>
|
||||
<div class="{local_res.css.suggestionsItemDescriptionImage} {spr.css.competitorWithoutClubnameItemDescription} {style.middle-aligned}"
|
||||
ui:field="flagImageUi"></div>
|
||||
<span class="{local_res.css.suggestionsItemDescriptionId} {style.middle-aligned}" ui:field="sailIdUi"></span>
|
||||
</div>
|
||||
</ui:UiBinder>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events;
|
||||
|
||||
import static com.google.gwt.dom.client.BrowserEvents.CLICK;
|
||||
import static com.google.gwt.dom.client.BrowserEvents.KEYDOWN;
|
||||
import static com.google.gwt.dom.client.BrowserEvents.TOUCHEND;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractSafeHtmlCell;
|
||||
import com.google.gwt.cell.client.ValueUpdater;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.safehtml.shared.SafeUri;
|
||||
import com.google.gwt.safehtml.shared.UriUtils;
|
||||
import com.google.gwt.text.shared.SafeHtmlRenderer;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources;
|
||||
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
|
||||
|
||||
/**
|
||||
* NavigatorColumn with a navigator arrow. After a click on the column, it will redirect to the associated URL,
|
||||
* specified in the overwritten {@link #getValue(Object)}-method.
|
||||
*/
|
||||
public abstract class NavigatorColumn<T> extends Column<T, String> {
|
||||
|
||||
public NavigatorColumn() {
|
||||
super(new NavigatorCell());
|
||||
}
|
||||
|
||||
private static class NavigatorCell extends AbstractSafeHtmlCell<String> {
|
||||
public NavigatorCell() {
|
||||
super(new SafeHtmlRenderer<String>() {
|
||||
|
||||
@Override
|
||||
public SafeHtml render(String url) {
|
||||
if (url != null) {
|
||||
SafeUri src = SharedHomeResources.INSTANCE.arrowDownGrey().getSafeUri();
|
||||
return SailorProfileDesktopResources.TEMPLATE.navigator(UriUtils.fromSafeConstant(url), src);
|
||||
}
|
||||
return new SafeHtmlBuilder().toSafeHtml();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(String object, SafeHtmlBuilder builder) {
|
||||
builder.append(render(object));
|
||||
}
|
||||
}, CLICK, KEYDOWN, TOUCHEND);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Context context, Element parent, String value, NativeEvent event,
|
||||
ValueUpdater<String> valueUpdater) {
|
||||
super.onBrowserEvent(context, parent, value, event, valueUpdater);
|
||||
if (valueUpdater != null) {
|
||||
valueUpdater.update(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void render(Context context, SafeHtml data, SafeHtmlBuilder sb) {
|
||||
if (data != null) {
|
||||
sb.append(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.FieldUpdater;
|
||||
import com.google.gwt.cell.client.NumberCell;
|
||||
import com.google.gwt.cell.client.TextCell;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.SpanElement;
|
||||
import com.google.gwt.place.shared.PlaceController;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.common.theme.component.celltable.DesignedCellTableResources;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.ParticipatedEventDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.ParticipatedRegattaDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.event.regatta.leaderboardtab.RegattaLeaderboardPlace;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.ShowAndEditSailorProfile;
|
||||
import com.sap.sailing.gwt.home.shared.app.ApplicationHistoryMapper;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.gwt.client.celltable.SortedCellTable;
|
||||
|
||||
/** This element displays the events a sailor has participated in in the {@link ShowAndEditSailorProfile} view. */
|
||||
public class SailorProfileEventsTable extends Composite {
|
||||
|
||||
interface MyBinder extends UiBinder<Widget, SailorProfileEventsTable> {
|
||||
}
|
||||
|
||||
private static MyBinder uiBinder = GWT.create(MyBinder.class);
|
||||
private ApplicationHistoryMapper historyMapper = GWT.create(ApplicationHistoryMapper.class);
|
||||
private PlaceController placeController;
|
||||
|
||||
@UiField(provided = true)
|
||||
final SortedCellTable<ParticipatedRegattaDTO> sailorProfilesTable = new SortedCellTable<>(0,
|
||||
DesignedCellTableResources.INSTANCE);
|
||||
|
||||
@UiField
|
||||
SpanElement titleUi;
|
||||
|
||||
private FlagImageResolver flagImageResolver;
|
||||
|
||||
public SailorProfileEventsTable(FlagImageResolver flagImageResolver, PlaceController placeController,
|
||||
ParticipatedEventDTO event) {
|
||||
this.flagImageResolver = flagImageResolver;
|
||||
this.placeController = placeController;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
setupTable(event.getParticipatedRegattas());
|
||||
|
||||
titleUi.setInnerText(event.getEventName());
|
||||
}
|
||||
|
||||
private void setupTable(Iterable<ParticipatedRegattaDTO> regattas) {
|
||||
sailorProfilesTable.addColumn(regattaNameColumn, StringMessages.INSTANCE.regattaName());
|
||||
sailorProfilesTable.addColumn(regattaRank, StringMessages.INSTANCE.regattaRank());
|
||||
sailorProfilesTable.addColumn(competitorColumn, StringMessages.INSTANCE.competitor());
|
||||
sailorProfilesTable.addColumn(clubNameColumn, StringMessages.INSTANCE.name());
|
||||
sailorProfilesTable.addColumn(sumPointsColumn, "\u2211");
|
||||
sailorProfilesTable.addColumn(navigatorColumn);
|
||||
|
||||
navigatorColumn.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell());
|
||||
navigatorColumn.setFieldUpdater(new FieldUpdater<ParticipatedRegattaDTO, String>() {
|
||||
@Override
|
||||
public void update(int index, ParticipatedRegattaDTO entry, String value) {
|
||||
placeController.goTo(getTargetPlace(entry));
|
||||
}
|
||||
});
|
||||
|
||||
sailorProfilesTable.setPageSize(Util.size(regattas));
|
||||
sailorProfilesTable.setList(regattas);
|
||||
|
||||
addButtonStyle(regattaNameColumn);
|
||||
addButtonStyle(regattaRank);
|
||||
addButtonStyle(competitorColumn);
|
||||
addButtonStyle(clubNameColumn);
|
||||
addButtonStyle(sumPointsColumn);
|
||||
addButtonStyle(navigatorColumn);
|
||||
|
||||
sailorProfilesTable.addCellPreviewHandler(e -> {
|
||||
if ("click".equals(e.getNativeEvent().getType())) {
|
||||
placeController.goTo(getTargetPlace(e.getValue()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addButtonStyle(Column<?, ?> col) {
|
||||
col.setCellStyleNames(col.getCellStyleNames(null, null) + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().clickableColumn());
|
||||
}
|
||||
|
||||
private RegattaLeaderboardPlace getTargetPlace(ParticipatedRegattaDTO entry) {
|
||||
return new RegattaLeaderboardPlace(entry.getEventId(), entry.getRegattaId(),
|
||||
new HashSet<>(Arrays.asList(entry.getCompetitorDto().getIdAsString())));
|
||||
}
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, String> regattaNameColumn = new Column<ParticipatedRegattaDTO, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(ParticipatedRegattaDTO entry) {
|
||||
return entry.getRegattaName();
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, Number> regattaRank = new Column<ParticipatedRegattaDTO, Number>(
|
||||
new NumberCell()) {
|
||||
@Override
|
||||
public Number getValue(ParticipatedRegattaDTO entry) {
|
||||
return entry.getRegattaRank();
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, ParticipatedRegattaDTO> competitorColumn = new Column<ParticipatedRegattaDTO, ParticipatedRegattaDTO>(
|
||||
new AbstractCell<ParticipatedRegattaDTO>() {
|
||||
@Override
|
||||
public void render(Context context, ParticipatedRegattaDTO value, SafeHtmlBuilder sb) {
|
||||
sb.appendHtmlConstant(
|
||||
new CompetitorWithoutClubnameItemDescription(value.getCompetitorDto(), flagImageResolver)
|
||||
.getElement().getInnerHTML());
|
||||
}
|
||||
}) {
|
||||
@Override
|
||||
public ParticipatedRegattaDTO getValue(ParticipatedRegattaDTO object) {
|
||||
return object;
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, String> clubNameColumn = new Column<ParticipatedRegattaDTO, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(ParticipatedRegattaDTO entry) {
|
||||
return entry.getCompetitorDto().getName();
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, Number> sumPointsColumn = new Column<ParticipatedRegattaDTO, Number>(
|
||||
new NumberCell()) {
|
||||
@Override
|
||||
public Number getValue(ParticipatedRegattaDTO entry) {
|
||||
return entry.getSumPoints();
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<ParticipatedRegattaDTO, String> navigatorColumn = new NavigatorColumn<ParticipatedRegattaDTO>() {
|
||||
@Override
|
||||
public String getValue(ParticipatedRegattaDTO object) {
|
||||
return "#" + historyMapper.getToken(getTargetPlace(object));
|
||||
}
|
||||
};
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||
xmlns:um="urn:import:com.sap.sailing.gwt.home.shared.usermanagement.decorator"
|
||||
xmlns:up="urn:import:com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile"
|
||||
xmlns:c="urn:import:com.google.gwt.user.cellview.client">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="spr"
|
||||
type="com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources" />
|
||||
<ui:style>
|
||||
</ui:style>
|
||||
<g:HTMLPanel
|
||||
addStyleNames="{res.mediaCss.column} {res.mediaCss.small12} {res.mainCss.spacermargintopmediumsmall} {spr.css.marginLastTable}">
|
||||
<div class="{res.mediaCss.grid} {spr.css.eventsTablePanel}">
|
||||
<div class="{spr.css.eventsTableTitle}">
|
||||
<span ui:field="titleUi" />
|
||||
</div>
|
||||
<c:CellTable ui:field="sailorProfilesTable" addStyleNames="{spr.css.eventsTable}">
|
||||
<c:emptyTableWidget>
|
||||
<g:Label text="{i18n.noEventsFoundForCompetitors}" addStyleNames="{spr.css.eventsTableEmpty}" />
|
||||
</c:emptyTableWidget>
|
||||
</c:CellTable>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.statistic;
|
||||
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.safehtml.shared.SafeUri;
|
||||
import com.google.gwt.safehtml.shared.UriUtils;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType;
|
||||
import com.sap.sailing.gwt.home.shared.partials.statistics.StatisticsBoxResources;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.common.TimePoint;
|
||||
|
||||
/** contains methods for formatting numeric statistics in sailor profiles */
|
||||
public final class SailorProfileNumericStatisticTypeFormatter {
|
||||
|
||||
private SailorProfileNumericStatisticTypeFormatter() {
|
||||
}
|
||||
|
||||
private static final DateTimeFormat dateToHoursAndMinutesFormat = DateTimeFormat.getFormat("HH:mm");
|
||||
|
||||
public static String getDisplayName(SailorProfileNumericStatisticType type, StringMessages stringMessages) {
|
||||
switch (type) {
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
return stringMessages.averageDistanceToStartLine();
|
||||
case BEST_DISTANCE_TO_START:
|
||||
return stringMessages.shortestDistanceToStartline();
|
||||
case BEST_STARTLINE_SPEED:
|
||||
return stringMessages.maxStartLineSpeed();
|
||||
case MAX_SPEED:
|
||||
return stringMessages.maxSpeedTitle();
|
||||
default:
|
||||
return type.name();
|
||||
}
|
||||
}
|
||||
|
||||
/** @return an icon safe uri corresponding to the given statistic type */
|
||||
public static SafeUri getIcon(SailorProfileNumericStatisticType type) {
|
||||
switch (type) {
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
return StatisticsBoxResources.INSTANCE.fastestSailorWhite().getSafeUri();
|
||||
case BEST_DISTANCE_TO_START:
|
||||
return StatisticsBoxResources.INSTANCE.fastestSailorWhite().getSafeUri();
|
||||
case BEST_STARTLINE_SPEED:
|
||||
return StatisticsBoxResources.INSTANCE.maxSpeedWhite().getSafeUri();
|
||||
case MAX_SPEED:
|
||||
return StatisticsBoxResources.INSTANCE.maxSpeedWhite().getSafeUri();
|
||||
default:
|
||||
return UriUtils.fromSafeConstant("");
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the {@link #timePoint} formatted as hours and minutes */
|
||||
public static String format(TimePoint timePoint) {
|
||||
return dateToHoursAndMinutesFormat.format(timePoint.asDate());
|
||||
}
|
||||
|
||||
/** @return the formatted value with unit corresponding to the given statistic type */
|
||||
public static String format(SailorProfileNumericStatisticType type, Double value, StringMessages stringMessages) {
|
||||
switch (type) {
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
return "\u00D8 " + stringMessages.metersValue(value);
|
||||
case BEST_DISTANCE_TO_START:
|
||||
return stringMessages.metersValue(value);
|
||||
case BEST_STARTLINE_SPEED:
|
||||
case MAX_SPEED:
|
||||
return stringMessages.knotsValue(value);
|
||||
default:
|
||||
return "" + value;
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the column heading name corresponding to the given statistic type */
|
||||
public static String getColumnHeadingName(SailorProfileNumericStatisticType type, StringMessages stringMessages) {
|
||||
switch (type) {
|
||||
case AVERAGE_STARTLINE_DISTANCE:
|
||||
case BEST_DISTANCE_TO_START:
|
||||
return stringMessages.distance();
|
||||
case BEST_STARTLINE_SPEED:
|
||||
case MAX_SPEED:
|
||||
return stringMessages.speed();
|
||||
default:
|
||||
return stringMessages.value();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
package com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.statistic;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.FieldUpdater;
|
||||
import com.google.gwt.cell.client.TextCell;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.SpanElement;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.cellview.client.Column;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Anchor;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.Image;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.RegattaAndRaceIdentifier;
|
||||
import com.sap.sailing.domain.common.security.SecuredDomainType;
|
||||
import com.sap.sailing.gwt.common.theme.component.celltable.DesignedCellTableResources;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileNumericStatisticType.StatisticType;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileStatisticDTO.SingleEntry;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.ShowAndEditSailorProfile;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events.CompetitorWithoutClubnameItemDescription;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.details.events.NavigatorColumn;
|
||||
import com.sap.sailing.gwt.home.shared.resources.SharedHomeResources;
|
||||
import com.sap.sailing.gwt.settings.client.EntryPointWithSettingsLinkFactory;
|
||||
import com.sap.sailing.gwt.settings.client.raceboard.RaceBoardPerspectiveOwnSettings;
|
||||
import com.sap.sailing.gwt.settings.client.raceboard.RaceboardContextDefinition;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapLifecycle;
|
||||
import com.sap.sailing.gwt.ui.client.shared.racemap.RaceMapSettings;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.common.impl.InvertibleComparatorAdapter;
|
||||
import com.sap.sse.common.impl.MillisecondsDurationImpl;
|
||||
import com.sap.sse.common.settings.Settings;
|
||||
import com.sap.sse.gwt.client.celltable.SortedCellTable;
|
||||
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
|
||||
import com.sap.sse.security.ui.client.UserService;
|
||||
|
||||
/**
|
||||
* This element displays a given statistic for each sailor in a sailor profile in the {@link ShowAndEditSailorProfile}
|
||||
* view.
|
||||
*/
|
||||
public class SailorProfileStatisticTable extends Composite {
|
||||
|
||||
interface MyBinder extends UiBinder<Widget, SailorProfileStatisticTable> {
|
||||
}
|
||||
|
||||
private static MyBinder uiBinder = GWT.create(MyBinder.class);
|
||||
|
||||
@UiField(provided = true)
|
||||
final SortedCellTable<Pair<SimpleCompetitorWithIdDTO, SingleEntry>> sailorProfilesTable = new SortedCellTable<>(0,
|
||||
DesignedCellTableResources.INSTANCE);
|
||||
|
||||
@UiField
|
||||
SpanElement titleUi;
|
||||
|
||||
@UiField
|
||||
Image titleIconUi;
|
||||
|
||||
@UiField
|
||||
Anchor anchor;
|
||||
|
||||
private final Image titleHeaderRight;
|
||||
|
||||
private final FlagImageResolver flagImageResolver;
|
||||
|
||||
private final SailorProfileNumericStatisticType type;
|
||||
|
||||
private final StringMessages stringMessages;
|
||||
|
||||
private Function<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> navigationTarget;
|
||||
|
||||
private String dataMiningUrl;
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public SailorProfileStatisticTable(FlagImageResolver flagImageResolver, SailorProfileNumericStatisticType type,
|
||||
StringMessages stringMessages, UserService userService) {
|
||||
this.userService = userService;
|
||||
this.flagImageResolver = flagImageResolver;
|
||||
this.type = type;
|
||||
this.stringMessages = stringMessages;
|
||||
|
||||
SailorProfileDesktopResources.INSTANCE.css().ensureInjected();
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
titleHeaderRight = new Image();
|
||||
titleHeaderRight.addStyleName(SailorProfileDesktopResources.INSTANCE.css().statisticsTableHeaderRight());
|
||||
setupTable();
|
||||
titleUi.setInnerText(SailorProfileNumericStatisticTypeFormatter.getDisplayName(type, stringMessages));
|
||||
titleIconUi.setUrl(SailorProfileNumericStatisticTypeFormatter.getIcon(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param isAverage
|
||||
* false -> {@link #navigationTarget} is called when the arrow in each row is clicked <br/>
|
||||
* true -> {@link #navigationTarget} is called when the arrow in the table header is clicked
|
||||
* @param navigationTarget
|
||||
*/
|
||||
private void setNavigationTarget(Function<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> navigationTarget,
|
||||
boolean isAverage) {
|
||||
if (isAverage) {
|
||||
setNavigationTarget(navigationTarget);
|
||||
titleHeaderRight.setVisible(true);
|
||||
sailorProfilesTable.removeColumn(navigatorColumn);
|
||||
} else {
|
||||
this.navigationTarget = navigationTarget;
|
||||
titleHeaderRight.setVisible(false);
|
||||
sailorProfilesTable.addColumn(navigatorColumn);
|
||||
}
|
||||
}
|
||||
|
||||
/** sets {@link #navigationTarget} which is called when the arrow in the table header is clicked */
|
||||
public void setNavigationTarget(Function<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> navigationTarget) {
|
||||
titleHeaderRight.setUrl(SharedHomeResources.INSTANCE.arrowDownWhite().getSafeUri());
|
||||
anchor.getElement().appendChild(titleHeaderRight.getElement());
|
||||
this.navigationTarget = navigationTarget;
|
||||
}
|
||||
|
||||
public void setData(final List<Pair<SimpleCompetitorWithIdDTO, SingleEntry>> data) {
|
||||
sailorProfilesTable.setPageSize(data.size());
|
||||
if (data.size() > 0) {
|
||||
dataMiningUrl = navigationTarget.apply(data.get(0));
|
||||
anchor.setHref(dataMiningUrl);
|
||||
}
|
||||
if (!userService.hasPermission(SecuredDomainType.DATA_MINING.getStringPermission())) {
|
||||
anchor.setVisible(false);
|
||||
}
|
||||
sailorProfilesTable.setList(data);
|
||||
}
|
||||
|
||||
private void setupTable() {
|
||||
boolean isAverage = type.getAggregationType() == StatisticType.AVERAGE;
|
||||
|
||||
if (!isAverage) {
|
||||
sailorProfilesTable.addColumn(eventNameColumn, StringMessages.INSTANCE.eventName());
|
||||
sailorProfilesTable.addColumn(timeColumn, StringMessages.INSTANCE.time());
|
||||
}
|
||||
|
||||
actualValueColumn.setSortable(true);
|
||||
sailorProfilesTable.getColumnSortList().push(actualValueColumn);
|
||||
sailorProfilesTable.setInitialSortColumn(actualValueColumn);
|
||||
sailorProfilesTable.setDefaultSortOrder(actualValueColumn, true);
|
||||
|
||||
sailorProfilesTable.addColumn(actualValueColumn,
|
||||
SailorProfileNumericStatisticTypeFormatter.getColumnHeadingName(type, stringMessages),
|
||||
new InvertibleComparatorAdapter<Pair<SimpleCompetitorWithIdDTO, SingleEntry>>(true) {
|
||||
@Override
|
||||
public int compare(Pair<SimpleCompetitorWithIdDTO, SingleEntry> o1,
|
||||
Pair<SimpleCompetitorWithIdDTO, SingleEntry> o2) {
|
||||
return o1.getB().getValue().compareTo(o2.getB().getValue());
|
||||
}
|
||||
}, true);
|
||||
sailorProfilesTable.addColumn(competitorColumn, StringMessages.INSTANCE.competitor());
|
||||
sailorProfilesTable.addColumn(clubNameColumn, StringMessages.INSTANCE.name());
|
||||
|
||||
navigatorColumn.setCellStyleNames(DesignedCellTableResources.INSTANCE.cellTableStyle().buttonCell());
|
||||
navigatorColumn.setFieldUpdater(new FieldUpdater<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String>() {
|
||||
@Override
|
||||
public void update(int index, Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry, String value) {
|
||||
Window.Location.assign(value);
|
||||
}
|
||||
});
|
||||
if (!isAverage) {
|
||||
setNavigationTarget(this::createRaceboardURL, false);
|
||||
} else {
|
||||
// navigation target is set from outside
|
||||
}
|
||||
|
||||
if (userService.hasPermission(SecuredDomainType.DATA_MINING.getStringPermission())
|
||||
|| !isAverage) {
|
||||
addButtonStyle(actualValueColumn);
|
||||
addButtonStyle(clubNameColumn);
|
||||
addButtonStyle(competitorColumn);
|
||||
addButtonStyle(eventNameColumn);
|
||||
addButtonStyle(navigatorColumn);
|
||||
addButtonStyle(timeColumn);
|
||||
|
||||
sailorProfilesTable.addCellPreviewHandler(e -> {
|
||||
if ("click".equals(e.getNativeEvent().getType())) {
|
||||
Window.Location.assign(navigationTarget.apply(e.getValue()));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addButtonStyle(Column<?, ?> col) {
|
||||
col.setCellStyleNames(col.getCellStyleNames(null, null) + " "
|
||||
+ SailorProfileDesktopResources.INSTANCE.css().clickableColumn());
|
||||
}
|
||||
|
||||
private String createRaceboardURL(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
String result = null;
|
||||
if (type.getAggregationType() != StatisticType.AVERAGE) {
|
||||
final RegattaAndRaceIdentifier raceIdentifier = entry.getB().getRelatedRaceOrNull();
|
||||
|
||||
// create raceboard context
|
||||
RaceboardContextDefinition raceboardContext = new RaceboardContextDefinition(
|
||||
raceIdentifier.getRegattaName(), raceIdentifier.getRaceName(),
|
||||
entry.getB().getLeaderboardNameOrNull(), entry.getB().getLeaderboardGroupNameOrNull(),
|
||||
entry.getB().getEventIdOrNull(), type.getPlayerMode().name(), entry.getA().getIdAsString());
|
||||
RaceBoardPerspectiveOwnSettings perspectiveOwnSettings = new RaceBoardPerspectiveOwnSettings(
|
||||
new MillisecondsDurationImpl(entry.getB().getRelatedTimePointOrNull().asMillis()
|
||||
- entry.getB().getRelatedRaceStartTimePointOrNull().asMillis()));
|
||||
|
||||
// create raceboard settings
|
||||
HashMap<String, Settings> innerSettings = new HashMap<>();
|
||||
innerSettings.put(RaceMapLifecycle.ID, RaceMapSettings.getDefaultWithShowMapControls(true));
|
||||
PerspectiveCompositeSettings<RaceBoardPerspectiveOwnSettings> settings = new PerspectiveCompositeSettings<>(
|
||||
perspectiveOwnSettings, innerSettings);
|
||||
result = EntryPointWithSettingsLinkFactory.createRaceBoardLink(raceboardContext, settings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> navigatorColumn = new NavigatorColumn<Pair<SimpleCompetitorWithIdDTO, SingleEntry>>() {
|
||||
@Override
|
||||
public String getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
return navigationTarget.apply(entry);
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> actualValueColumn = new Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
return SailorProfileNumericStatisticTypeFormatter.format(type, entry.getB().getValue(), stringMessages);
|
||||
}
|
||||
};
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, SimpleCompetitorWithIdDTO> competitorColumn = new Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, SimpleCompetitorWithIdDTO>(
|
||||
new AbstractCell<SimpleCompetitorWithIdDTO>() {
|
||||
@Override
|
||||
public void render(Context context, SimpleCompetitorWithIdDTO value, SafeHtmlBuilder sb) {
|
||||
sb.appendHtmlConstant(new CompetitorWithoutClubnameItemDescription(value, flagImageResolver)
|
||||
.getElement().getInnerHTML());
|
||||
}
|
||||
}) {
|
||||
|
||||
@Override
|
||||
public SimpleCompetitorWithIdDTO getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> object) {
|
||||
return object.getA();
|
||||
}
|
||||
};
|
||||
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> clubNameColumn = new Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
return entry.getA().getName();
|
||||
}
|
||||
};
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> eventNameColumn = new Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
return entry.getB().getLeaderboardNameOrNull() + " " + entry.getB().getRaceNameOrNull();
|
||||
}
|
||||
};
|
||||
private final Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String> timeColumn = new Column<Pair<SimpleCompetitorWithIdDTO, SingleEntry>, String>(
|
||||
new TextCell()) {
|
||||
@Override
|
||||
public String getValue(Pair<SimpleCompetitorWithIdDTO, SingleEntry> entry) {
|
||||
return SailorProfileNumericStatisticTypeFormatter.format(entry.getB().getRelatedTimePointOrNull());
|
||||
}
|
||||
};
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
<ui:UiBinder xmlns:ui='urn:ui:com.google.gwt.uibinder' xmlns:g='urn:import:com.google.gwt.user.client.ui'
|
||||
xmlns:c="urn:import:com.google.gwt.user.cellview.client">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="spr"
|
||||
type="com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileDesktopResources" />
|
||||
<g:HTMLPanel
|
||||
addStyleNames="{res.mediaCss.column} {res.mediaCss.small12} {res.mainCss.spacermargintopmediumsmall} {spr.css.marginLastTable}">
|
||||
<div class="{res.mediaCss.grid} {spr.css.eventsTablePanel}">
|
||||
<div class="{spr.css.eventsTableTitle} {spr.css.statisticsTableHeader}">
|
||||
<g:Image addStyleNames="{spr.css.statisticsTableHeaderIcon}" ui:field="titleIconUi" />
|
||||
<span ui:field="titleUi" />
|
||||
<g:Anchor ui:field="anchor" />
|
||||
</div>
|
||||
<c:CellTable ui:field="sailorProfilesTable" addStyleNames="{spr.css.eventsTable}">
|
||||
<c:emptyTableWidget>
|
||||
<g:Label text="{i18n.noDataFound}" addStyleNames="{spr.css.eventsTableEmpty}" />
|
||||
</c:emptyTableWidget>
|
||||
</c:CellTable>
|
||||
</div>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+24
-7
@@ -6,24 +6,41 @@
|
||||
<div class="innerContent">
|
||||
<h5 class="articleSubheadline">October 2018</h5>
|
||||
<ul class="bulletList">
|
||||
<li>Introduction of the Sailor Profiles</li>
|
||||
<ul class="bulletList">
|
||||
<li>Authenticated users can now create sailor profiles in their profile view.</li>
|
||||
<li>Sailor Profiles show information about the selected competitors and help to compare their strengths and weaknesses, like:</li>
|
||||
<ul class="bulletList">
|
||||
<li>The events the sailor has participated in with the rank and points of the sailor.</li>
|
||||
<li>Several statistics for each competitor:
|
||||
<ul class="bulletList">
|
||||
<li>the maximum speed</li>
|
||||
<li>the minimum distance to the start line at race start</li>
|
||||
<li>the average distance to the start line at race start</li>
|
||||
<li>the maximum speed while crossing the start line</li>
|
||||
</ul>
|
||||
<li>It is possible to go from the sailor profile directly to the dynamic place of interest. For example, after clicking on the maximum speed statistic value, the race board will open and the exact point in time where the maximum speed was reached is displayed.</li>
|
||||
</ul>
|
||||
</ul>
|
||||
<li>Searching for phrases containing whitespace characters with double quotes such as "Tobias Schadewaldt" will now work
|
||||
across a distributed server and event landscape.</li>
|
||||
<li>A column showing the used boat can now be shown for each extended race column in leaderboards with multiple races.
|
||||
This new column is activated per default, if the boats change between races. </li>
|
||||
<li>A column showing the used boat can now be shown for each extended race column in leaderboards with multiple races.
|
||||
This new column is activated per default, if the boats change between races. </li>
|
||||
<li>It is now possible to store and load queries in <tt>DataMining.html</tt>. Such queries are saved per user.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<h5 class="articleSubheadline">September 2018</h5>
|
||||
<ul class="bulletList">
|
||||
<li>In <tt>RaceBoard.html</tt> is a new feature available which allows users to create tags consisting of a title
|
||||
and optional comment and/or image per race. These tags can be saved visible only for the creating user or for everbody
|
||||
(requiring special permissions) and can be used to mark interesting situations during a race. Tag buttons allow users to
|
||||
save frequently used tags as a preset which can be used quckily and do not require repeating input of the same tag.
|
||||
and optional comment and/or image per race. These tags can be saved visible only for the creating user or for everybody
|
||||
(requiring special permissions) and can be used to mark interesting situations during a race. Tag buttons allow users to
|
||||
save frequently used tags as a preset which can be used quickly and do not require repeating input of the same tag.
|
||||
Those tags and their comments are also used in order to find the containing leaderboard via the global search.</li>
|
||||
</ul>
|
||||
|
||||
<h5 class="articleSubheadline">August 2018</h5>
|
||||
<ul class="bulletList">
|
||||
<li>The windstreamlets are now colored dynamically according to the wind fields maximum and minimum wind speed.</li>
|
||||
<li>The windstreamlets are now colored dynamically according to the wind fields maximum and minimum wind speed.</li>
|
||||
<li>Changes of <tt>DataMining.html</tt>
|
||||
<ul class="bulletList">
|
||||
<li>The currently selected result tab will be remembered when a query is run. It is now possible
|
||||
|
||||
+3
-4
@@ -24,13 +24,12 @@ import com.sap.sailing.gwt.home.shared.places.user.confirmation.ConfirmationView
|
||||
import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetClientFactory;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.passwordreset.PasswordResetViewImpl;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.ui.client.refresh.BusyView;
|
||||
import com.sap.sailing.gwt.ui.client.refresh.ErrorAndBusyClientFactory;
|
||||
import com.sap.sse.gwt.client.mvp.ErrorView;
|
||||
import com.sap.sse.security.ui.authentication.AuthenticationManager;
|
||||
import com.sap.sse.security.ui.authentication.AuthenticationManagerImpl;
|
||||
import com.sap.sse.security.ui.authentication.WithAuthenticationManager;
|
||||
import com.sap.sse.security.ui.authentication.WithUserService;
|
||||
import com.sap.sse.security.ui.authentication.login.LoginHintContent;
|
||||
import com.sap.sse.security.ui.client.SecureClientFactoryImpl;
|
||||
import com.sap.sse.security.ui.client.i18n.StringMessages;
|
||||
@@ -42,8 +41,8 @@ import com.sap.sse.security.ui.client.i18n.StringMessages;
|
||||
*/
|
||||
public class MobileApplicationClientFactory extends
|
||||
SecureClientFactoryImpl<ApplicationTopLevelView<ResettableNavigationPathDisplay>> implements
|
||||
ErrorAndBusyClientFactory, SearchResultClientFactory, ConfirmationClientFactory, PasswordResetClientFactory,
|
||||
WithAuthenticationManager, WithUserService {
|
||||
SearchResultClientFactory, ConfirmationClientFactory, PasswordResetClientFactory, WithAuthenticationManager,
|
||||
ClientFactoryWithDispatchAndErrorAndUserService {
|
||||
private final MobilePlacesNavigator navigator;
|
||||
private final SailingDispatchSystem dispatch = new SailingDispatchSystemImpl();
|
||||
private final AuthenticationManager authenticationManager;
|
||||
|
||||
+3
@@ -139,3 +139,6 @@
|
||||
.sectionheader_item_adjust_title_right {
|
||||
padding-right: 2.5em;
|
||||
}
|
||||
.sectionheader_element{
|
||||
top: 0.666666666666em;
|
||||
}
|
||||
|
||||
+86
-32
@@ -1,16 +1,21 @@
|
||||
package com.sap.sailing.gwt.home.mobile.partials.sectionHeader;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.AnchorElement;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.HeadingElement;
|
||||
import com.google.gwt.dom.client.Style.Display;
|
||||
import com.google.gwt.dom.client.Style.Unit;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.home.communication.event.LabelType;
|
||||
@@ -24,42 +29,65 @@ import com.sap.sailing.gwt.home.shared.utils.LabelTypeUtil;
|
||||
import com.sap.sse.gwt.client.LinkUtil;
|
||||
|
||||
public class SectionHeaderContent extends Composite {
|
||||
|
||||
|
||||
protected static final String ACCORDION_COLLAPSED_STYLE = SectionHeaderResources.INSTANCE.css().collapsed();
|
||||
private static MyBinder uiBinder = GWT.create(MyBinder.class);
|
||||
|
||||
interface MyBinder extends UiBinder<Widget, SectionHeaderContent> {
|
||||
}
|
||||
|
||||
@UiField SectionHeaderResources local_res;
|
||||
@UiField AnchorElement headerMainUi;
|
||||
@UiField DivElement headerLeftUi;
|
||||
@UiField DivElement titleAndLabelContainerUi;
|
||||
@UiField HeadingElement titleUi;
|
||||
@UiField DivElement labelUi;
|
||||
@UiField DivElement imageUi;
|
||||
@UiField DivElement subtitleUi;
|
||||
@UiField DivElement headerRightUi;
|
||||
@UiField DivElement infoTextUi;
|
||||
@UiField DivElement actionArrowUi;
|
||||
@UiField SimplePanel filterSelectContainerUi;
|
||||
@UiField
|
||||
SectionHeaderResources local_res;
|
||||
@UiField
|
||||
AnchorElement headerMainUi;
|
||||
@UiField
|
||||
DivElement headerLeftUi;
|
||||
@UiField
|
||||
DivElement titleAndLabelContainerUi;
|
||||
@UiField
|
||||
HeadingElement titleUi;
|
||||
@UiField
|
||||
DivElement labelUi;
|
||||
@UiField
|
||||
DivElement imageUi;
|
||||
@UiField
|
||||
DivElement subtitleUi;
|
||||
@UiField
|
||||
HTMLPanel headerRightUi;
|
||||
@UiField
|
||||
DivElement infoTextUi;
|
||||
@UiField
|
||||
DivElement actionArrowUi;
|
||||
@UiField
|
||||
SimplePanel filterSelectContainerUi;
|
||||
@UiField
|
||||
HTMLPanel headerContentUi;
|
||||
|
||||
private boolean expanded = false;;
|
||||
|
||||
private final Collection<AccordionExpansionListener> accordionListeners = new ArrayList<>();
|
||||
|
||||
public interface AccordionExpansionListener {
|
||||
public void onExpansionChange(boolean collapsed);
|
||||
}
|
||||
|
||||
public SectionHeaderContent() {
|
||||
SectionHeaderResources.INSTANCE.css().ensureInjected();
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
headerRightUi.setVisible(false);
|
||||
filterSelectContainerUi.setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
public void setSectionTitle(String sectionHeaderTitle) {
|
||||
titleUi.setInnerText(sectionHeaderTitle);
|
||||
}
|
||||
|
||||
|
||||
public void setSubtitle(String subtitle) {
|
||||
subtitleUi.getStyle().clearDisplay();
|
||||
subtitleUi.setInnerText(subtitle);
|
||||
headerLeftUi.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_itemdoublerow());
|
||||
}
|
||||
|
||||
|
||||
public void setLabelType(LabelType labelType) {
|
||||
if (labelType == null || !labelType.isRendered()) {
|
||||
labelUi.getStyle().setDisplay(Display.NONE);
|
||||
@@ -68,20 +96,20 @@ public class SectionHeaderContent extends Composite {
|
||||
LabelTypeUtil.renderLabelType(labelUi, labelType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setImageUrl(String imageUrl) {
|
||||
imageUi.getStyle().clearDisplay();
|
||||
imageUi.getStyle().setBackgroundImage("url(" + imageUrl + ")");
|
||||
titleAndLabelContainerUi
|
||||
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_left());
|
||||
}
|
||||
|
||||
|
||||
public void setInfoText(String infoText) {
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
infoTextUi.getStyle().clearDisplay();
|
||||
infoTextUi.setInnerText(infoText);
|
||||
}
|
||||
|
||||
|
||||
public void initCollapsibility(Element content, boolean showInitial) {
|
||||
final CollapseAnimation animation = new CollapseAnimation(content, showInitial);
|
||||
setClassName(actionArrowUi, ACCORDION_COLLAPSED_STYLE, !showInitial);
|
||||
@@ -89,26 +117,28 @@ public class SectionHeaderContent extends Composite {
|
||||
@Override
|
||||
public void run() {
|
||||
boolean collapsed = actionArrowUi.hasClassName(ACCORDION_COLLAPSED_STYLE);
|
||||
expanded = collapsed;
|
||||
setClassName(actionArrowUi, ACCORDION_COLLAPSED_STYLE, !collapsed);
|
||||
animation.animate(collapsed);
|
||||
accordionListeners.forEach(l -> l.onExpansionChange(!collapsed));
|
||||
}
|
||||
});
|
||||
actionArrowUi.addClassName(SectionHeaderResources.INSTANCE.css().accordion());
|
||||
titleAndLabelContainerUi
|
||||
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
|
||||
actionArrowUi.getStyle().clearDisplay();
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
public void setClickAction(final PlaceNavigation<?> placeNavigation) {
|
||||
placeNavigation.configureAnchorElement(headerMainUi);
|
||||
this.adjustedActionStyles();
|
||||
titleAndLabelContainerUi
|
||||
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
actionArrowUi.getStyle().clearDisplay();
|
||||
}
|
||||
|
||||
|
||||
public void setClickAction(final String url) {
|
||||
headerMainUi.setHref(url);
|
||||
DOM.setEventListener(headerMainUi, event -> {
|
||||
@@ -119,30 +149,46 @@ public class SectionHeaderContent extends Composite {
|
||||
private void adjustedActionStyles() {
|
||||
titleAndLabelContainerUi
|
||||
.addClassName(SectionHeaderResources.INSTANCE.css().sectionheader_item_adjust_title_right());
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
actionArrowUi.getStyle().clearDisplay();
|
||||
}
|
||||
|
||||
public void setClickAction(final Runnable commandToExecute) {
|
||||
headerMainUi.setHref(Window.Location.getHref());
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
actionArrowUi.getStyle().clearDisplay();
|
||||
LinkUtil.configureForAction(headerMainUi, commandToExecute);
|
||||
}
|
||||
|
||||
|
||||
private void setClassName(Element element, String className, boolean set) {
|
||||
if (set) element.addClassName(className);
|
||||
else element.removeClassName(className);
|
||||
if (set) {
|
||||
element.addClassName(className);
|
||||
} else {
|
||||
element.removeClassName(className);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void appendHeaderElement(Widget widget) {
|
||||
headerRightUi.add(widget);
|
||||
actionArrowUi.getStyle().setMarginRight(.5, Unit.EM);
|
||||
titleAndLabelContainerUi.getStyle().setPaddingRight(4.1, Unit.EM);
|
||||
}
|
||||
|
||||
public void setFirstHeaderElement(Widget widget) {
|
||||
actionArrowUi.removeFromParent();
|
||||
headerRightUi.add(widget);
|
||||
headerRightUi.getElement().appendChild(actionArrowUi);
|
||||
titleAndLabelContainerUi.getStyle().setPaddingRight(4.1, Unit.EM);
|
||||
}
|
||||
|
||||
public void initFilterSelectUi(AbstractSelectionFilter<?, ?> selectionFilter) {
|
||||
headerRightUi.getStyle().clearDisplay();
|
||||
headerRightUi.setVisible(true);
|
||||
filterSelectContainerUi.setVisible(true);
|
||||
filterSelectContainerUi.setWidget(selectionFilter);
|
||||
selectionFilter.addStyleName(local_res.css().sectionheader_item_select());
|
||||
selectionFilter.getElement().setAttribute("dir", "rtl");
|
||||
}
|
||||
|
||||
|
||||
public void initBoatClassPopup(String boatClassName) {
|
||||
BubbleContentBoatClass content = new BubbleContentBoatClass(boatClassName);
|
||||
Bubble.DefaultPresenter presenter = new Bubble.DefaultPresenter(content, getElement(), imageUi,
|
||||
@@ -150,4 +196,12 @@ public class SectionHeaderContent extends Composite {
|
||||
presenter.registerTarget(imageUi);
|
||||
}
|
||||
|
||||
public void addAccordionListener(AccordionExpansionListener listener) {
|
||||
accordionListeners.add((AccordionExpansionListener) listener);
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return expanded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-22
@@ -1,26 +1,40 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res" type="com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderResources" />
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="local_res"
|
||||
type="com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderResources" />
|
||||
<ui:with field="shr" type="com.sap.sailing.gwt.home.shared.resources.SharedHomeResources" />
|
||||
<g:HTMLPanel>
|
||||
<a style="display:block;" ui:field="headerMainUi">
|
||||
<div class="{local_res.css.sectionheader_item}" ui:field="headerLeftUi">
|
||||
<div class="{local_res.css.sectionheader_item_image}" style="display:none;" ui:field="imageUi">
|
||||
<div class="{local_res.css.sectionheader_item_image_seperator}"></div>
|
||||
</div>
|
||||
<div ui:field="titleAndLabelContainerUi">
|
||||
<h2 class="{local_res.css.sectionheader_item_title}" ui:field="titleUi"></h2>
|
||||
<div class="{local_res.css.sectionheader_item_label} {res.mainCss.label}" style="display:none;" ui:field="labelUi"></div>
|
||||
</div>
|
||||
<div class="{local_res.css.sectionheader_item_subtitle}" style="display:none;" ui:field="subtitleUi"></div>
|
||||
</div>
|
||||
<div class="{local_res.css.sectionheader_item} {local_res.css.sectionheader_itemright}" style="display:none;" ui:field="headerRightUi">
|
||||
<div class="{local_res.css.sectionheader_item_infotext}" style="display:none;" ui:field="infoTextUi"></div>
|
||||
<div class="{local_res.css.sectionheader_item_arrow}" style="display:none;" ui:field="actionArrowUi"></div>
|
||||
<g:SimplePanel ui:field="filterSelectContainerUi"></g:SimplePanel>
|
||||
</div>
|
||||
</a>
|
||||
</g:HTMLPanel>
|
||||
|
||||
<ui:style>
|
||||
.headerContentPanel {
|
||||
display:none;
|
||||
position:absolue;
|
||||
right:49px;
|
||||
}
|
||||
</ui:style>
|
||||
<g:HTMLPanel>
|
||||
<a style="display:block;" ui:field="headerMainUi">
|
||||
<div class="{local_res.css.sectionheader_item}" ui:field="headerLeftUi">
|
||||
<div class="{local_res.css.sectionheader_item_image}" style="display:none;" ui:field="imageUi">
|
||||
<div class="{local_res.css.sectionheader_item_image_seperator}"></div>
|
||||
</div>
|
||||
<div ui:field="titleAndLabelContainerUi">
|
||||
<h2 class="{local_res.css.sectionheader_item_title}" ui:field="titleUi"></h2>
|
||||
<div class="{local_res.css.sectionheader_item_label} {res.mainCss.label}" style="display:none;"
|
||||
ui:field="labelUi"></div>
|
||||
</div>
|
||||
<div class="{local_res.css.sectionheader_item_subtitle}" style="display:none;" ui:field="subtitleUi"></div>
|
||||
</div>
|
||||
<g:HTMLPanel addStyleNames="{local_res.css.sectionheader_item} {local_res.css.sectionheader_itemright}"
|
||||
ui:field="headerRightUi">
|
||||
<div class="{local_res.css.sectionheader_item_infotext}" style="display:none;" ui:field="infoTextUi"></div>
|
||||
<div class="{local_res.css.sectionheader_item_arrow}" style="display:none;" ui:field="actionArrowUi"></div>
|
||||
<g:SimplePanel ui:field="filterSelectContainerUi"></g:SimplePanel>
|
||||
</g:HTMLPanel>
|
||||
</a>
|
||||
<g:HTMLPanel
|
||||
addStyleNames="{local_res.css.sectionheader_itemright} {local_res.css.sectionheader_element}"
|
||||
ui:field="headerContentUi" />
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
|
||||
+1
@@ -34,5 +34,6 @@ public interface SectionHeaderResources extends SharedHomeResources {
|
||||
String sectionheader_item_select();
|
||||
String accordion();
|
||||
String collapsed();
|
||||
String sectionheader_element();
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -31,6 +31,11 @@
|
||||
</p>
|
||||
</g:HTMLPanel>
|
||||
</a:header>
|
||||
<a:item>
|
||||
<login:MoreLoginInformationContentMobile
|
||||
title="{i18n.moreLoginInformationSectionSailorProfilesHeading}" image="{local_res.sailorprofiles}"
|
||||
content="{i18n.moreLoginInformationSectionSailorProfilesDescription}" />
|
||||
</a:item>
|
||||
<a:item>
|
||||
<login:MoreLoginInformationContentMobile
|
||||
title="{i18n.moreLoginInformationSectionUserSettingsHeading}" image="{local_res.settings}"
|
||||
|
||||
+5
@@ -33,4 +33,9 @@ public abstract class AbstractUserProfileActivity extends AbstractActivity imple
|
||||
return clientFactory.getNavigator().getUserSettingsNavigation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlaceNavigation<? extends AbstractUserProfilePlace> getSailorProfilesNavigation() {
|
||||
return clientFactory.getNavigator().getSailorProfilesNavigation();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -43,6 +43,7 @@ public class AbstractUserProfileView extends Composite implements UserProfileVie
|
||||
this.layout.quickfinderUi.addPlaceholderItem(i18n.profileQuickfinder());
|
||||
this.layout.quickfinderUi.addItem(i18n.details(), presenter.getUserProfileNavigation());
|
||||
this.layout.quickfinderUi.addItem(i18n.favoritesAndNotifications(), presenter.getUserPreferencesNavigation());
|
||||
this.layout.quickfinderUi.addItem(i18n.sailorProfiles(), presenter.getSailorProfilesNavigation());
|
||||
if(ExperimentalFeatures.SHOW_MY_SETTINGS_IN_USER_PROFILE) {
|
||||
this.layout.quickfinderUi.addItem(i18n.settings(), presenter.getUserSettingsNavigation());
|
||||
}
|
||||
|
||||
+4
@@ -9,9 +9,11 @@ import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.details.UserProfileDetailsActivity;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.preferences.UserProfilePreferencesActivity;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles.SailorProfilesActivity;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.settings.UserProfileSettingsActivity;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.AbstractUserProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.preferences.UserProfilePreferencesPlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.settings.UserProfileSettingsPlace;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolver;
|
||||
import com.sap.sse.gwt.client.mvp.AbstractActivityProxy;
|
||||
@@ -36,6 +38,8 @@ public class UserProfileActivityProxy extends AbstractActivityProxy {
|
||||
withFlagImageResolver(flagImageResolver -> new UserProfilePreferencesActivity(userProfilePrefsPlace, clientFactory, flagImageResolver));
|
||||
} else if(currentPlace instanceof UserProfileSettingsPlace) {
|
||||
super.onSuccess(new UserProfileSettingsActivity((UserProfileSettingsPlace) currentPlace, clientFactory));
|
||||
} else if (currentPlace instanceof SailorProfilePlace) {
|
||||
super.onSuccess(new SailorProfilesActivity((SailorProfilePlace) currentPlace, clientFactory));
|
||||
} else {
|
||||
super.onSuccess(new UserProfileDetailsActivity(currentPlace, clientFactory));
|
||||
}
|
||||
|
||||
+2
-1
@@ -7,10 +7,11 @@ import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
|
||||
import com.sap.sse.security.ui.authentication.decorator.NotLoggedInPresenter;
|
||||
|
||||
public interface UserProfileViewBase extends IsWidget, NeedsAuthenticationContext {
|
||||
|
||||
|
||||
public interface Presenter extends NotLoggedInPresenter {
|
||||
PlaceNavigation<? extends AbstractUserProfilePlace> getUserProfileNavigation();
|
||||
PlaceNavigation<? extends AbstractUserProfilePlace> getUserPreferencesNavigation();
|
||||
PlaceNavigation<? extends AbstractUserProfilePlace> getUserSettingsNavigation();
|
||||
PlaceNavigation<? extends AbstractUserProfilePlace> getSailorProfilesNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles;
|
||||
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.gwt.common.client.BoatClassImageResolver;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources;
|
||||
|
||||
public final class BoatclassElementBuilder {
|
||||
|
||||
private BoatclassElementBuilder() {
|
||||
}
|
||||
|
||||
/** @return a boatclass element for mobile display with the boatclass icon and the corresponding name */
|
||||
public static Element generateBoatclassElementForMobile(final BoatClassDTO boatclass) {
|
||||
SailorProfileMobileResources.INSTANCE.css().ensureInjected();
|
||||
Element elem = DOM.createDiv();
|
||||
elem.setInnerSafeHtml(SharedSailorProfileResources.TEMPLATES.buildBoatclassIconWithName(
|
||||
BoatClassImageResolver.getBoatClassIconResource(boatclass.getName()).getSafeUri().asString(),
|
||||
boatclass.getName()));
|
||||
elem.addClassName(SailorProfileMobileResources.INSTANCE.css().boatclassWithNameEntry());
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
+220
@@ -0,0 +1,220 @@
|
||||
.eventEntryPanel {
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
background-color: white;
|
||||
float: none;
|
||||
padding-left: 2em;
|
||||
padding-right: 2em;
|
||||
}
|
||||
|
||||
.regattaEntryPanel {
|
||||
font-size: 0.8em;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.sumPoints {
|
||||
font-weight: bold;
|
||||
background-color: #f2f2f2;
|
||||
border: 1px solid #cccccc;
|
||||
border-radius: 2px;
|
||||
padding: 0.5em;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.regattaName {
|
||||
margin-top: 1em;
|
||||
font-size: 1.333333em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.regattaRank {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.competitor {
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
margin-bottom: 0.1em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.regattaInfoLeft {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.regattaInfoRight {
|
||||
display: inline-block;
|
||||
right: 3em;
|
||||
position: absolute;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.showLeaderboardButton {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.regattaSplitter1px {
|
||||
margin-left: -1.66666666667em;
|
||||
margin-right: -1.66666666667em;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.detailsSectionPanel {
|
||||
font-size: 1.3333em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.competitorWithClubnameItemDescriptionId {
|
||||
display: inline-block;
|
||||
font-weight: 600;
|
||||
font-size: 0.8em;
|
||||
min-width: 5.5em;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.competitorWithClubnameItemDescriptionClubname {
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.eventTableHeader {
|
||||
font-weight: normal;
|
||||
font-size: 0.8em;
|
||||
padding-left: 0;
|
||||
text-align: center;
|
||||
color: white;
|
||||
background-color: #008fcc;
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overviewPanel h3 {
|
||||
font-size: 1.3333em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 3px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.gotoEventButton {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
margin-right: 1em;
|
||||
-webkit-transform: rotate(270deg);
|
||||
-moz-transform: rotate(270deg);
|
||||
-ms-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
width: 1.33333333333em;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.eventTableHeaderText {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.detailsEventsContainer {
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
}
|
||||
|
||||
.detailsCompetitorsContainer {
|
||||
margin-left: -1em;
|
||||
margin-right: -1em;
|
||||
}
|
||||
|
||||
.overviewTableFooterMobile {
|
||||
cursor: pointer;
|
||||
border-top: 2px solid #ccc;
|
||||
font-size: 1rem;
|
||||
padding: 1em 1em 0;
|
||||
vertical-align: middle;
|
||||
width: auto;
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-left: -1em;
|
||||
margin-right: -1em
|
||||
}
|
||||
|
||||
.inlineTitleUi {
|
||||
padding-left: 1em;
|
||||
font-weight: bold;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.editButton {
|
||||
position: initial !important;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.footerAddButton {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.statisticsHeaderLeft {
|
||||
width: 2em;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
left: 2em;
|
||||
top: 0.666666667em;
|
||||
}
|
||||
|
||||
.statisticsHeaderRight {
|
||||
margin-left: 2em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.boatclassWithNameEntry {
|
||||
margin-left: -1rem;
|
||||
margin-right: -1rem;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding-left: .5em;
|
||||
padding-right: 1em;
|
||||
padding-top: .25em;
|
||||
padding-bottom: .25em;
|
||||
}
|
||||
|
||||
.boatclassWithNameEntry:last-child {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.detailsBoatclassesSelectionPanel {
|
||||
font-size: 1.3333em;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.statisticTime {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.statisticValue {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.statisticCompetitor {
|
||||
margin-top: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.statisticLabel {
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.detailsBoatclassesEmptyLabel {
|
||||
font-size: 1em;
|
||||
font-weight: initial;
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.resources.client.ClientBundle;
|
||||
import com.google.gwt.resources.client.CssResource;
|
||||
|
||||
public interface SailorProfileMobileResources extends ClientBundle {
|
||||
|
||||
public static final SailorProfileMobileResources INSTANCE = GWT.create(SailorProfileMobileResources.class);
|
||||
|
||||
@Source("SailorProfileMobile.gss")
|
||||
SailorProfileMobileCss css();
|
||||
|
||||
public interface SailorProfileMobileCss extends CssResource {
|
||||
|
||||
String eventEntryPanel();
|
||||
|
||||
String regattaEntryPanel();
|
||||
|
||||
String sumPoints();
|
||||
|
||||
String regattaName();
|
||||
|
||||
String regattaRank();
|
||||
|
||||
String competitor();
|
||||
|
||||
String regattaInfoLeft();
|
||||
|
||||
String regattaInfoRight();
|
||||
|
||||
String showLeaderboardButton();
|
||||
|
||||
String regattaSplitter1px();
|
||||
|
||||
String detailsSectionPanel();
|
||||
|
||||
String competitorWithClubnameItemDescriptionId();
|
||||
|
||||
String competitorWithClubnameItemDescriptionClubname();
|
||||
|
||||
String eventTableHeader();
|
||||
|
||||
String overviewPanel();
|
||||
|
||||
String gotoEventButton();
|
||||
|
||||
String eventTableHeaderText();
|
||||
|
||||
String detailsEventsContainer();
|
||||
|
||||
String overviewTableFooterMobile();
|
||||
|
||||
String detailsCompetitorsContainer();
|
||||
|
||||
String inlineTitleUi();
|
||||
|
||||
String editButton();
|
||||
|
||||
String footerAddButton();
|
||||
|
||||
String statisticsHeaderLeft();
|
||||
|
||||
String statisticsHeaderRight();
|
||||
|
||||
String boatclassWithNameEntry();
|
||||
|
||||
String detailsBoatclassesSelectionPanel();
|
||||
|
||||
String detailsBoatclassesEmptyLabel();
|
||||
|
||||
String statisticTime();
|
||||
|
||||
String statisticValue();
|
||||
|
||||
String statisticCompetitor();
|
||||
|
||||
String statisticLabel();
|
||||
}
|
||||
}
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.DivElement;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.Style.Display;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.uibinder.client.UiHandler;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.domain.common.dto.BoatClassDTO;
|
||||
import com.sap.sailing.gwt.common.client.BoatClassImageResolver;
|
||||
import com.sap.sailing.gwt.common.client.SharedResources;
|
||||
import com.sap.sailing.gwt.home.communication.event.SimpleCompetitorWithIdDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.BadgeDTO;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailingProfileOverviewPresenter;
|
||||
import com.sap.sailing.gwt.home.mobile.partials.sectionHeader.SectionHeaderContent;
|
||||
import com.sap.sailing.gwt.home.shared.partials.dialog.ConfirmDialogFactory;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.gwt.client.dialog.DataEntryDialog.DialogCallback;
|
||||
|
||||
/** sailor profile overview entry with one sailor profile on mobile */
|
||||
public class SailorProfileOverviewEntry extends Composite {
|
||||
|
||||
private static SailorProfileOverviewEntryUiBinder uiBinder = GWT.create(SailorProfileOverviewEntryUiBinder.class);
|
||||
|
||||
interface SailorProfileOverviewEntryUiBinder extends UiBinder<Widget, SailorProfileOverviewEntry> {
|
||||
}
|
||||
|
||||
@UiField
|
||||
Button detailsButtonUi;
|
||||
|
||||
@UiField
|
||||
DivElement badgesDivUi;
|
||||
@UiField
|
||||
DivElement competitorsDivUi;
|
||||
@UiField
|
||||
DivElement boatclassesDivUi;
|
||||
@UiField
|
||||
SectionHeaderContent sectionTitleUi;
|
||||
@UiField
|
||||
HTMLPanel contentContainerCompetitorsUi;
|
||||
|
||||
@UiField
|
||||
DivElement badgesArea;
|
||||
|
||||
private final UUID uuidRef;
|
||||
|
||||
private final SailingProfileOverviewPresenter presenter;
|
||||
|
||||
public SailorProfileOverviewEntry(SailorProfileDTO entry, SailingProfileOverviewPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
SailorProfileMobileResources.INSTANCE.css().ensureInjected();
|
||||
this.sectionTitleUi.setSectionTitle(entry.getName());
|
||||
|
||||
badgesArea.getStyle().setDisplay(Display.NONE);
|
||||
|
||||
// add badges
|
||||
for (BadgeDTO badge : entry.getBadges()) {
|
||||
Element elem = DOM.createDiv();
|
||||
elem.setInnerText(badge.getName());
|
||||
badgesDivUi.appendChild(elem);
|
||||
}
|
||||
|
||||
// add competitors
|
||||
for (SimpleCompetitorWithIdDTO competitor : entry.getCompetitors()) {
|
||||
Element elem = DOM.createDiv();
|
||||
elem.setInnerText(competitor.getName());
|
||||
competitorsDivUi.appendChild(elem);
|
||||
}
|
||||
|
||||
// add boatclasses
|
||||
for (BoatClassDTO boatclass : entry.getBoatclasses()) {
|
||||
Element elem = DOM.createDiv();
|
||||
elem.setInnerSafeHtml(SharedSailorProfileResources.TEMPLATES.buildBoatclassIcon(
|
||||
BoatClassImageResolver.getBoatClassIconResource(boatclass.getName()).getSafeUri().asString()));
|
||||
elem.getStyle().setDisplay(Display.INLINE_BLOCK);
|
||||
boatclassesDivUi.appendChild(elem);
|
||||
}
|
||||
this.uuidRef = entry.getKey();
|
||||
sectionTitleUi.initCollapsibility(contentContainerCompetitorsUi.getElement(), false);
|
||||
|
||||
final Button removeButton = new Button("X");
|
||||
removeButton.addClickHandler(e -> {
|
||||
e.preventDefault();
|
||||
e.getNativeEvent().preventDefault();
|
||||
e.getNativeEvent().stopPropagation();
|
||||
ConfirmDialogFactory.showConfirmDialog(StringMessages.INSTANCE.sailorProfileRemoveMessage(),
|
||||
new DialogCallback<Void>() {
|
||||
|
||||
@Override
|
||||
public void ok(Void v) {
|
||||
presenter.removeSailorProfile(uuidRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
removeButton.addStyleName(SharedResources.INSTANCE.mainCss().buttonred());
|
||||
sectionTitleUi.appendHeaderElement(removeButton);
|
||||
}
|
||||
|
||||
@UiHandler("detailsButtonUi")
|
||||
void onClick(ClickEvent e) {
|
||||
presenter.getClientFactory().getPlaceController().goTo(new SailorProfilePlace(uuidRef));
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:p="urn:import:com.sap.sailing.gwt.home.mobile.partials"
|
||||
xmlns:ms="urn:import:com.sap.sailing.gwt.home.mobile.partials.section">
|
||||
<ui:with field="i18n" type="com.sap.sailing.gwt.ui.client.StringMessages" />
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<ui:with field="spmr"
|
||||
type="com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles.SailorProfileMobileResources" />
|
||||
<ui:with field="spr"
|
||||
type="com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources" />
|
||||
|
||||
<g:HTMLPanel>
|
||||
<ms:MobileSection>
|
||||
<ms:header>
|
||||
<p:sectionHeader.SectionHeaderContent ui:field="sectionTitleUi" />
|
||||
</ms:header>
|
||||
<ms:content>
|
||||
<g:HTMLPanel ui:field="contentContainerCompetitorsUi"
|
||||
addStyleNames="{spmr.css.overviewPanel} {res.mainCss.spacermarginbottomsmall}">
|
||||
<div ui:field="badgesArea">
|
||||
<h3>
|
||||
<ui:text from="{i18n.badges}" />
|
||||
</h3>
|
||||
<div ui:field="badgesDivUi" />
|
||||
</div>
|
||||
<h3>
|
||||
<ui:text from="{i18n.competitors}" />
|
||||
</h3>
|
||||
<div ui:field="competitorsDivUi" />
|
||||
<h3>
|
||||
<ui:text from="{i18n.boatClasses}" />
|
||||
</h3>
|
||||
<div ui:field="boatclassesDivUi" />
|
||||
<g:Button styleName="{spr.css.inverseButton}" ui:field="detailsButtonUi"
|
||||
text="{i18n.showDetails}" />
|
||||
</g:HTMLPanel>
|
||||
</ms:content>
|
||||
</ms:MobileSection>
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import com.google.gwt.core.shared.GWT;
|
||||
import com.google.gwt.event.shared.EventBus;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
import com.google.gwt.user.client.ui.AcceptsOneWidget;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfilesDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailingProfileOverviewPresenter;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailorProfileOverviewImplPresenter;
|
||||
import com.sap.sailing.gwt.home.mobile.app.MobileApplicationClientFactory;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.AbstractUserProfileActivity;
|
||||
import com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles.details.SailorProfilesDetailsViewImpl;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.ClientFactoryWithDispatchAndErrorAndUserService;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfilePresenter;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.EditSailorProfileDetailsView;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.HasLoginFormAndFactory;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileView;
|
||||
import com.sap.sailing.gwt.ui.client.FlagImageResolverImpl;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.security.ui.authentication.AuthenticationContextEvent;
|
||||
|
||||
/** main entry point for Sailor Profiles on mobile */
|
||||
public class SailorProfilesActivity extends AbstractUserProfileActivity
|
||||
implements SailorProfilesOverviewView.Presenter, HasLoginFormAndFactory {
|
||||
|
||||
private final MobileApplicationClientFactory clientFactory;
|
||||
private final SailorProfileView currentView;
|
||||
private final SailingProfileOverviewPresenter sailorProfileOverviewPresenter;
|
||||
|
||||
// redundant with sailorProfileOverviewPresenter.getSharedPresenter() --> TODO: remove
|
||||
private final EditSailorProfilePresenter editSailorProfilePresenter;
|
||||
|
||||
private final SailorProfilePlace place;
|
||||
|
||||
public SailorProfilesActivity(SailorProfilePlace place, MobileApplicationClientFactory clientFactory) {
|
||||
super(clientFactory);
|
||||
this.place = place;
|
||||
this.clientFactory = clientFactory;
|
||||
editSailorProfilePresenter = new EditSailorProfilePresenter(clientFactory);
|
||||
if (place.getSailorProfileUuid() == null) {
|
||||
if (place.isCreateNew()) {
|
||||
// no uuid & createNew -> go to details view to create new sailor profile
|
||||
this.currentView = new SailorProfilesDetailsViewImpl(this);
|
||||
} else {
|
||||
// no uuid & !createNew -> go to overview
|
||||
this.currentView = new SailorProfilesOverviewViewImpl(this);
|
||||
|
||||
}
|
||||
} else {
|
||||
// existing uuid -> go to details
|
||||
this.currentView = new SailorProfilesDetailsViewImpl(this);
|
||||
}
|
||||
sailorProfileOverviewPresenter = new SailorProfileOverviewImplPresenter(this.currentView, this,
|
||||
FlagImageResolverImpl.get(), editSailorProfilePresenter);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(final AcceptsOneWidget panel, final EventBus eventBus) {
|
||||
panel.setWidget(currentView);
|
||||
if (currentView instanceof SailorProfilesViewWithAuthenticationContext) {
|
||||
|
||||
SailorProfilesViewWithAuthenticationContext cView = (SailorProfilesViewWithAuthenticationContext) currentView;
|
||||
cView.setAuthenticationContext(clientFactory.getAuthenticationManager().getAuthenticationContext());
|
||||
eventBus.addHandler(AuthenticationContextEvent.TYPE, new AuthenticationContextEvent.Handler() {
|
||||
@Override
|
||||
public void onUserChangeEvent(AuthenticationContextEvent event) {
|
||||
cView.setAuthenticationContext(event.getCtx());
|
||||
}
|
||||
});
|
||||
|
||||
if (cView instanceof SailorProfilesOverviewView) {
|
||||
SailorProfilesOverviewView overview = (SailorProfilesOverviewView) cView;
|
||||
if (clientFactory.getAuthenticationManager().getAuthenticationContext().isLoggedIn()) {
|
||||
sailorProfileOverviewPresenter.getSharedSailorProfilePresenter().getDataProvider()
|
||||
.loadSailorProfiles(new AsyncCallback<SailorProfilesDTO>() {
|
||||
|
||||
@Override
|
||||
public void onSuccess(SailorProfilesDTO result) {
|
||||
overview.setProfileList(result.getEntries());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
GWT.log(caught.getMessage(), caught);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else if (cView instanceof EditSailorProfileDetailsView) {
|
||||
EditSailorProfileDetailsView detailsView = (EditSailorProfileDetailsView) cView;
|
||||
editSailorProfilePresenter.getDataProvider().setView(detailsView);
|
||||
if (place.isCreateNew()) {
|
||||
editSailorProfilePresenter.getDataProvider().createNewEntry(UUID.randomUUID(),
|
||||
StringMessages.INSTANCE.newSailorProfileName());
|
||||
} else {
|
||||
editSailorProfilePresenter.getDataProvider().loadSailorProfile(place.getSailorProfileUuid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EditSailorProfilePresenter getSailorProfilePresenter() {
|
||||
return editSailorProfilePresenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SailingProfileOverviewPresenter getSailorProfileOverviewPresenter() {
|
||||
return sailorProfileOverviewPresenter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientFactoryWithDispatchAndErrorAndUserService getClientFactory() {
|
||||
return editSailorProfilePresenter.getClientFactory();
|
||||
}
|
||||
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.sap.sailing.gwt.home.mobile.places.user.profile.sailorprofiles;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.uibinder.client.UiBinder;
|
||||
import com.google.gwt.uibinder.client.UiField;
|
||||
import com.google.gwt.user.client.ui.Button;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.sap.sailing.gwt.common.client.SharedResources;
|
||||
import com.sap.sailing.gwt.home.communication.user.profile.domain.SailorProfileDTO;
|
||||
import com.sap.sailing.gwt.home.desktop.places.user.profile.sailorprofiletab.SailingProfileOverviewPresenter;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SailorProfilePlace;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.SharedSailorProfileResources;
|
||||
import com.sap.sailing.gwt.home.shared.places.user.profile.sailorprofile.view.SailorProfileOverview;
|
||||
import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sse.security.ui.authentication.app.NeedsAuthenticationContext;
|
||||
|
||||
/**
|
||||
* Implementation of {@link SailorProfileOverview} where a user can see an overview over all his sailor profiles.
|
||||
*/
|
||||
public class SailorProfilesOverviewImpl extends Composite implements SailorProfileOverview {
|
||||
|
||||
private static MyUiBinder uiBinder = GWT.create(MyUiBinder.class);
|
||||
|
||||
interface MyUiBinder extends UiBinder<Widget, SailorProfilesOverviewImpl> {
|
||||
}
|
||||
|
||||
@UiField
|
||||
FlowPanel contentUi;
|
||||
|
||||
private SailingProfileOverviewPresenter presenter;
|
||||
|
||||
public SailorProfilesOverviewImpl() {
|
||||
initWidget(uiBinder.createAndBindUi(this));
|
||||
SailorProfileMobileResources.INSTANCE.css().ensureInjected();
|
||||
SharedSailorProfileResources.INSTANCE.css().ensureInjected();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPresenter(SailingProfileOverviewPresenter presenter) {
|
||||
this.presenter = presenter;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public NeedsAuthenticationContext authentificationContextConsumer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfileList(Collection<SailorProfileDTO> entries) {
|
||||
for (SailorProfileDTO entry : entries) {
|
||||
SailorProfileOverviewEntry entryOverview = new SailorProfileOverviewEntry(entry, presenter);
|
||||
contentUi.add(entryOverview);
|
||||
}
|
||||
createFooter();
|
||||
}
|
||||
|
||||
private void createFooter() {
|
||||
Button addButton = new Button("+ " + StringMessages.INSTANCE.addSailorProfileMessage());
|
||||
SimplePanel panel = new SimplePanel(addButton);
|
||||
panel.addStyleName(SailorProfileMobileResources.INSTANCE.css().overviewTableFooterMobile());
|
||||
addButton.addStyleName(SharedResources.INSTANCE.mainCss().buttonprimary());
|
||||
addButton.addStyleName(SharedResources.INSTANCE.mainCss().button());
|
||||
addButton.addStyleName(SailorProfileMobileResources.INSTANCE.css().footerAddButton());
|
||||
contentUi.add(panel);
|
||||
addButton.addClickHandler((event) -> {
|
||||
presenter.getClientFactory().getPlaceController().goTo(new SailorProfilePlace(true));
|
||||
});
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<!DOCTYPE ui:UiBinder SYSTEM "http://dl.google.com/gwt/DTD/xhtml.ent">
|
||||
<ui:UiBinder xmlns:ui="urn:ui:com.google.gwt.uibinder" xmlns:g="urn:import:com.google.gwt.user.client.ui">
|
||||
<ui:with field="res" type="com.sap.sailing.gwt.common.client.SharedResources" />
|
||||
<g:HTMLPanel addStyleNames="{res.mediaCss.grid}">
|
||||
<g:FlowPanel addStyleNames="{res.mediaCss.column} {res.mediaCss.small12}" ui:field="contentUi" />
|
||||
</g:HTMLPanel>
|
||||
</ui:UiBinder>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user