Merge branch 'master' into bug4942

This commit is contained in:
Steffen Schaefer committed 2019-07-01 10:23:59 +02:00
commit 46fae16241
39 files changed
+431 -245

No files matched your search

@@ -117,6 +117,7 @@ public enum DetailType implements Serializable {
RACE_TIME_TRAVELED_REACHING(0, ASCENDING),
CHART_DISTANCE_TO_START_LINE(0, ASCENDING, "DISTANCE_TO_START_LINE"),
CHART_BEAT_ANGLE(0, ASCENDING, "BEAT_ANGLE"),
CHART_ABS_TWA(0, ASCENDING),
CHART_COURSE_OVER_GROUND_TRUE_DEGREES(0, ASCENDING, "COURSE_OVER_GROUND_TRUE_DEGREES"),
OVERALL_TOTAL_SCORED_RACE_COUNT(0, ASCENDING, "TOTAL_SCORED_RACE_COUNT"),
EXPEDITION_RACE_AWA(2, ASCENDING),
@@ -261,6 +262,7 @@ public enum DetailType implements Serializable {
availableDetailsTypes.add(DetailType.REGATTA_RANK);
availableDetailsTypes.add(DetailType.CHART_DISTANCE_TO_START_LINE);
availableDetailsTypes.add(DetailType.CHART_BEAT_ANGLE);
availableDetailsTypes.add(DetailType.CHART_ABS_TWA);
availableDetailsTypes.add(DetailType.CHART_COURSE_OVER_GROUND_TRUE_DEGREES);
availableDetailsTypes.add(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
availableDetailsTypes.add(DetailType.BRAVO_RACE_HEEL_IN_DEGREES);
@@ -22,8 +22,6 @@ public class FinishedTimeFinder extends RaceLogAnalyzer<TimePoint> {
}
}
}
return null;
}
}
@@ -74,7 +74,8 @@ public class RaceStatusAnalyzer extends RaceLogAnalyzer<Pair<RaceLogRaceStatus,
// events; but dispatch all other events (particularly start-related events) to the dispatcher:
final boolean dispatch;
if (statusTypesToIgnoreIfEventNotValidYet.contains(event.getNextStatus())) {
if (event.getLogicalTimePoint().after(now)) { // event not valid yet
if (statusesToIgnore.contains(event.getNextStatus()) // event of this type already found but it's not valid (yet)
|| event.getLogicalTimePoint() == null || event.getLogicalTimePoint().after(now)) { // event not valid yet
statusesToIgnore.add(event.getNextStatus()); // but ignore events of same status with lesser relevance
dispatch = false;
} else {
@@ -805,7 +805,7 @@ public abstract class TrackedRaceImpl extends TrackedRaceWithWindEssentials impl
/**
* Monitor object to synchronize access to the {@link #updateStartAndEndOfTracking(boolean)} method. See bug 3922.
*/
private final Serializable updateStartAndEndOfTrackingMonitor = "updateStartAndEndOfTrackingMonitor";
private final Serializable updateStartAndEndOfTrackingMonitor = ""+new Random().nextDouble();
/**
* Updates the start and end of tracking in the following precedence order:
@@ -4,6 +4,12 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Analytics</h4>
<div class="innerContent">
<h5 class="articleSubheadline">June 2019</h5>
<ul class="bulletList">
<li>The combined wind arrow on the top left of the map now switches through three states:
wind visualization off, wind visualization on, wind visualization on with color.</li>
</ul>
<h5 class="articleSubheadline">May 2019</h5>
<ul class="bulletList">
<li>Improvements for handicap regattas: when finishing times have been entered, leading to finish line
@@ -53,7 +53,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
private VerticalPanel contentPanel;
private Button cloneButton;
private Button updateButton;
protected DeviceConfigurationDTO originalConfiguration;
protected DeviceConfigurationWithSecurityDTO originalConfiguration;
protected TextBox uuidBox;
protected TextBox identifierBox;
private StringListEditorComposite allowedCourseAreasList;
@@ -64,7 +64,8 @@ public class DeviceConfigurationDetailComposite extends Composite {
private final UserService userService;
public static interface DeviceConfigurationFactory {
void obtainAndSetNameForConfigurationAndAdd(final DeviceConfigurationDTO configurationToObtainAndSetNameForAndAdd);
void obtainAndSetNameForConfigurationAndAdd(final DeviceConfigurationWithSecurityDTO configurationToObtainAndSetNameForAndAdd);
void update(DeviceConfigurationWithSecurityDTO configurationToUpdate);
}
public DeviceConfigurationDetailComposite(SailingServiceAsync sailingService, UserService userService,
@@ -80,10 +81,10 @@ public class DeviceConfigurationDetailComposite extends Composite {
cloneButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
updateConfiguration();
updateConfiguration(callbackInterface);
// create a new, cloned configuration object and set a new UUID; then ask for a name,
// then send it to the server and add to the local list
final DeviceConfigurationDTO cloned = getResult();
final DeviceConfigurationWithSecurityDTO cloned = getResult();
cloned.id = UUID.randomUUID();
callbackInterface.obtainAndSetNameForConfigurationAndAdd(cloned);
}
@@ -92,7 +93,7 @@ public class DeviceConfigurationDetailComposite extends Composite {
updateButton.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
updateConfiguration();
updateConfiguration(callbackInterface);
}
});
verticalPanel.add(contentPanel);
@@ -249,8 +250,10 @@ public class DeviceConfigurationDetailComposite extends Composite {
}
}
private DeviceConfigurationDTO getResult() {
DeviceConfigurationDTO result = new DeviceConfigurationDTO();
private DeviceConfigurationWithSecurityDTO getResult() {
DeviceConfigurationWithSecurityDTO result = new DeviceConfigurationWithSecurityDTO(originalConfiguration.getIdentifier());
result.setOwnership(originalConfiguration.getOwnership());
result.setAccessControlList(originalConfiguration.getAccessControlList());
result.name = identifierBox.getValue();
result.id = UUID.fromString(uuidBox.getValue());
if (!allowedCourseAreasList.getValue().isEmpty()) {
@@ -268,16 +271,17 @@ public class DeviceConfigurationDetailComposite extends Composite {
return result;
}
private void updateConfiguration() {
private void updateConfiguration(DeviceConfigurationFactory callbackInterface) {
if (originalConfiguration == null) {
errorReporter.reportError(stringMessages.invalidState());
return;
}
DeviceConfigurationDTO dto = getResult();
DeviceConfigurationWithSecurityDTO dto = getResult();
sailingService.createOrUpdateDeviceConfiguration(dto, new MarkedAsyncCallback<>(new AsyncCallback<Void>() {
@Override
public void onSuccess(Void result) {
markAsDirty(false);
callbackInterface.update(dto);
}
@Override
@@ -71,17 +71,17 @@ public class DeviceConfigurationListComposite extends Composite {
configurationTable.setVisible(true);
refreshableConfigurationSelectionModel = new RefreshableMultiSelectionModel<>(
new EntityIdentityComparator<DeviceConfigurationWithSecurityDTO>() {
@Override
@Override
public boolean representSameEntity(DeviceConfigurationWithSecurityDTO dto1,
DeviceConfigurationWithSecurityDTO dto2) {
return Util.equalsWithNull(dto1.id, dto2.id);
}
return Util.equalsWithNull(dto1.id, dto2.id);
}
@Override
@Override
public int hashCode(DeviceConfigurationWithSecurityDTO t) {
return t.id == null ? 0 : t.id.hashCode();
}
}, configurationsDataProvider);
return t.id == null ? 0 : t.id.hashCode();
}
}, configurationsDataProvider);
configurationTable.setSelectionModel(refreshableConfigurationSelectionModel);
panel.add(configurationTable);
initWidget(mainPanel);
@@ -136,8 +136,6 @@ public class DeviceConfigurationListComposite extends Composite {
final TextColumn<DeviceConfigurationWithSecurityDTO> deviceConfigurationUUidColumn = new AbstractSortableTextColumn<DeviceConfigurationWithSecurityDTO>(
config -> config.id == null ? "<null>" : config.id.toString());
final HasPermissions type = SecuredSecurityTypes.USER_GROUP;
final AccessControlledActionsColumn<DeviceConfigurationWithSecurityDTO, DefaultActionsImagesBarCell> actionColumn = create(
new DefaultActionsImagesBarCell(stringMessages), userService);
@@ -156,23 +154,27 @@ public class DeviceConfigurationListComposite extends Composite {
});
}
});
final EditOwnershipDialog.DialogConfig<DeviceConfigurationWithSecurityDTO> configOwnership = EditOwnershipDialog
.create(userService.getUserManagementService(), type, user -> refreshTable(), stringMessages);
final EditACLDialog.DialogConfig<DeviceConfigurationWithSecurityDTO> configACL = EditACLDialog.create(
userService.getUserManagementService(), type, user -> user.getAccessControlList(), stringMessages);
actionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_OWNERSHIP, DefaultActions.CHANGE_OWNERSHIP,
configOwnership::openDialog);
actionColumn.addAction(DefaultActionsImagesBarCell.ACTION_CHANGE_ACL, DefaultActions.CHANGE_ACL,
u -> configACL.openDialog(u));
SecuredDTOOwnerColumn.configureOwnerColumns(table, columnSortHandler, stringMessages);
table.addColumn(deviceConfigurationUUidColumn, stringMessages.id());
table.addColumn(actionColumn, stringMessages.actions());
return table;
}
void update(DeviceConfigurationWithSecurityDTO configurationToUpdate) {
final List<DeviceConfigurationWithSecurityDTO> configList = configurationsDataProvider.getList();
for (int i=0; i<configList.size(); i++) {
if (configList.get(i).id.equals(configurationToUpdate.id)) {
configList.set(i, configurationToUpdate);
break;
}
}
}
}
@@ -121,7 +121,7 @@ public class DeviceConfigurationPanel extends SimplePanel implements DeviceConfi
}
private void createConfiguration() {
final DeviceConfigurationDTO newConfiguration = new DeviceConfigurationDTO();
final DeviceConfigurationWithSecurityDTO newConfiguration = new DeviceConfigurationWithSecurityDTO(null);
newConfiguration.id = UUID.randomUUID(); // the name will be obtained by the following call
obtainAndSetNameForConfigurationAndAdd(newConfiguration);
}
@@ -136,7 +136,7 @@ public class DeviceConfigurationPanel extends SimplePanel implements DeviceConfi
*/
@Override
public void obtainAndSetNameForConfigurationAndAdd(
final DeviceConfigurationDTO configurationToObtainAndSetNameForAndAdd) {
final DeviceConfigurationWithSecurityDTO configurationToObtainAndSetNameForAndAdd) {
sailingService.getDeviceConfigurations(
new MarkedAsyncCallback<>(new AsyncCallback<List<DeviceConfigurationWithSecurityDTO>>() {
@Override
@@ -172,6 +172,11 @@ public class DeviceConfigurationPanel extends SimplePanel implements DeviceConfi
}));
}
@Override
public void update(DeviceConfigurationWithSecurityDTO configurationToUpdate) {
listComposite.update(configurationToUpdate);
}
private void removeConfiguration() {
detailComposite.setConfiguration(null);
for (DeviceConfigurationDTO config : refreshableMultiSelectionModel.getSelectedSet()) {
@@ -87,15 +87,17 @@ public class SetFinishingAndFinishedTimeDialog extends SetTimeDialog<RaceLogSetF
@Override
public String getErrorMessage(RaceLogSetFinishingAndFinishTimeDTO dto) {
if (dto.authorName == null || dto.authorName.isEmpty() || dto.authorPriority == null
|| dto.finishTime == null || dto.finishingTime == null) {
return stringMessages.pleaseEnterAValue();
}
// both times are != null at this point
if (dto.finishTime.before(dto.finishingTime)) {
final String result;
if (dto.authorName == null || dto.authorName.isEmpty() || dto.authorPriority == null) {
result = stringMessages.pleaseEnterAValue();
} else if (dto.finishTime != null && dto.finishingTime == null) {
result = stringMessages.youHaveToEnterAFinishingTimeIfYouEnterAFinishedTime();
} else if (dto.finishTime != null && dto.finishTime.before(dto.finishingTime)) {
return stringMessages.finishTimeMustBeAtOrAfterFinishingTime();
} else {
result = null;
}
return null;
return result;
}
}
@@ -202,6 +202,8 @@ public class DetailTypeFormatter {
return stringMessages.distanceToLine();
case CHART_BEAT_ANGLE:
return stringMessages.TWA();
case CHART_ABS_TWA:
return stringMessages.absoluteTWA();
case CHART_COURSE_OVER_GROUND_TRUE_DEGREES:
return stringMessages.courseOverGroundTrueDegrees();
case OVERALL_TOTAL_SCORED_RACE_COUNT:
@@ -515,6 +517,7 @@ public class DetailTypeFormatter {
case RACE_DISPLAY_BOATS:
case LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED:
case CHART_BEAT_ANGLE:
case CHART_ABS_TWA:
case OVERALL_TIME_ON_TIME_FACTOR:
case OVERALL_TOTAL_SCORED_RACE_COUNT:
case EXPEDITION_RACE_AWA:
@@ -788,6 +791,8 @@ public class DetailTypeFormatter {
return stringMessages.raceTimeUpwindTooltip();
case CHART_BEAT_ANGLE:
return stringMessages.TWATooltip();
case CHART_ABS_TWA:
return stringMessages.absoluteTWATooltip();
case CHART_DISTANCE_TO_START_LINE:
return "";
case CHART_COURSE_OVER_GROUND_TRUE_DEGREES:
@@ -1033,6 +1033,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String finishTimeString();
String setFinishingAndFinishTime();
String finishTimeMustBeAtOrAfterFinishingTime();
String youHaveToEnterAFinishingTimeIfYouEnterAFinishedTime();
String currentPass();
String setStartTimeDescription();
String setFinishingAndFinishTimeDescription();
@@ -1072,6 +1073,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String timeSinceStart(String timeSince);
String distanceToLine();
String TWATooltip();
String absoluteTWATooltip();
String showBoatClassChartsLabel();
String showDiagram();
String rerunQueryAfterRefreshTooltip();
@@ -2021,6 +2023,7 @@ public interface StringMessages extends com.sap.sse.gwt.client.StringMessages,
String boatSpeed();
String knotsUnit();
String windSpeed();
String absoluteTWA();
String TWA();
String degreesShort();
String numberOfDataPoints();
@@ -1057,8 +1057,10 @@ resultFromIgtimiWindImport=The following number of fixes were imported for the l
timeToStart={0} to start
timeSinceStart={0} since start
distanceToLine=Distance to start line
TWATooltip=The angle between the competitors direction and the wind
TWATooltip=The angle between the competitors course over ground and the wind, signed, negative values meaning wind from port, positive values meaning wind from starboard
absoluteTWATooltip=The positive angle between the competitors course over ground and the wind, without +/- sign
TWA=True Wind Angle
absoluteTWA=Absolute True Wind Angle
showBoatClassChartsLabel=You can also view the overall diagram for the available boat classes.
showDiagram=Show Diagram
rerunQueryAfterRefreshTooltip=Reruns the query after the tables have been refreshed.
@@ -1933,6 +1935,7 @@ finishingTime=Finishing time
finishTimeString=Finish time
setFinishingAndFinishTime=Set finishing and finish time
finishTimeMustBeAtOrAfterFinishingTime=Finish time must be at or after finishing time
youHaveToEnterAFinishingTimeIfYouEnterAFinishedTime=You have to enter a finishing time if you enter a finish time
boatNameMustNotBeEmpty=Please provide a non-empty boat name
errorUpdatingExpeditionDeviceConfiguration=Error updating Expedition device configuration "{0}": {1}
doYouReallyWantToRemoveExpeditionDeviceConfiguration=Do you really want to remove Expedition device configuration "{0}"?
@@ -22,7 +22,7 @@ races=Wettfahrten
racesAndTracking=Wettfahrten/Tracking
tracked=getracked
time=Zeit
linkedRaces=Verknüfte Rennen
linkedRaces=Verknüpfte Rennen
timeTooltip=Zeit, die der Teilnehmer auf diesem Schenkel gesegelt ist. Beim ersten Schenkel zählt die Zeit ab Überquerung der Startlinie.
playSpeed=Abspielgeschwindigkeit
playSpeedHelp="1" für normale Abspielgeschwindigkeit, "2" für doppelte Geschwindigkeit usw.
@@ -1043,8 +1043,10 @@ resultFromIgtimiWindImport=Die folgenden Anzahlen von Windmessungen wurden für
timeToStart={0} bis zum Start
timeSinceStart={0} seit dem Start
distanceToLine=Abstand zur Startlinie
TWATooltip=Der Winkel zwischen wahrer Windrichtung und Fahrtrichtung des Teilnehmers
TWATooltip=Der Winkel zwischen wahrer Windrichtung und Fahrtrichtung des Teilnehmers, vorzeichenbehaftet; negative Werte bedeuten Wind von Backbord, positive Werte Wind von Steuerbord
absoluteTWATooltip=Der positive Winkel zwischen wahrer Windrichtung und Fahrtrichtung des Teilnehmers, ohne Vorzeichen
TWA=Winkel zum wahren Wind
absoluteTWA=Absoluter Winkel zum wahren Wind
showBoatClassChartsLabel=Im folgenden können außerdem auch die existierenden Diagramme für die vorhandenen Bootsklassen angezeigt werden.
showDiagram=Diagramm anzeigen
rerunQueryAfterRefreshTooltip=Wiederholt die Anfrage nachdem die Tabellen aktualisiert wurden.
@@ -1925,6 +1927,7 @@ finishingTime=Zieleinlaufzeit
finishTimeString=Endzeitpunkt
setFinishingAndFinishTime=Setzte Zieleinlaufzeit und Endzeitpunkt
finishTimeMustBeAtOrAfterFinishingTime=Der Endzeitpunkt muss nach der Zieleinlaufzeit liegen oder gleich sein
youHaveToEnterAFinishingTimeIfYouEnterAFinishedTime=Gib eine Zieleinlaufzeit ein, wenn Du auch bereits einen Endzeitpunkt eingibst
setFinishingAndFinishTimeDescription=Wähle neue Werte für Zieleinlaufzeit und Endzeitpunkt aus.
boatNameMustNotBeEmpty=Bitte einen nicht leeren Bootsnamen angeben
errorUpdatingExpeditionDeviceConfiguration=Fehler beim Speichern der Expedition Gerätekonfiguration "{0}": {1}
@@ -44,13 +44,16 @@ public class CombinedWindPanel extends FlowPanel {
@Override
public void onClick(ClickEvent event) {
RaceMapSettings oldRaceMapSettings = map.getSettings();
boolean newShowStreamletsOverlaySetting = !oldRaceMapSettings.isShowWindStreamletOverlay();
// when off, turn on; when on and no color, turn on color; when on with color, turn off
boolean newShowStreamletsOverlaySetting = oldRaceMapSettings.isShowWindStreamletOverlay() ?
oldRaceMapSettings.isShowWindStreamletColors() ? false : true : true;
boolean newShowWindStreamletColors = oldRaceMapSettings.isShowWindStreamletOverlay() ? !oldRaceMapSettings.isShowWindStreamletColors() :
false;
final RaceMapSettings newRaceMapSettings = new RaceMapSettings(oldRaceMapSettings.getZoomSettings(),
oldRaceMapSettings.getHelpLinesSettings(), oldRaceMapSettings.getTransparentHoverlines(),
oldRaceMapSettings.getHoverlineStrokeWeight(), oldRaceMapSettings.getTailLengthInMilliseconds(), oldRaceMapSettings.isWindUp(),
oldRaceMapSettings.getBuoyZoneRadius(), oldRaceMapSettings.isShowOnlySelectedCompetitors(),
oldRaceMapSettings.isShowSelectedCompetitorsInfo(), oldRaceMapSettings.isShowWindStreamletColors(),
oldRaceMapSettings.isShowSelectedCompetitorsInfo(), newShowWindStreamletColors,
newShowStreamletsOverlaySetting, oldRaceMapSettings.isShowSimulationOverlay(),
oldRaceMapSettings.isShowMapControls(), oldRaceMapSettings.getManeuverTypesToShow(),
oldRaceMapSettings.isShowDouglasPeuckerPoints(), oldRaceMapSettings.isShowEstimatedDuration(),
@@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthenticatedException;
import org.mp4parser.AbstractBoxParser;
import org.mp4parser.IsoFile;
import org.mp4parser.PropertyBoxParserImpl;
@@ -53,6 +54,7 @@ import com.sap.sse.common.impl.MillisecondsDurationImpl;
import com.sap.sse.security.Action;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.shared.HasPermissions.DefaultActions;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.ui.server.SecurityDTOUtil;
public class MediaServiceImpl extends RemoteServiceServlet implements MediaService {
@@ -112,17 +114,24 @@ public class MediaServiceImpl extends RemoteServiceServlet implements MediaServi
@Override
public MediaTrackWithSecurityDTO addMediaTrack(MediaTrack mediaTrack) {
SecurityUtils.getSubject().checkPermission(SecuredDomainType.MEDIA_TRACK.getStringPermission(DefaultActions.CREATE));
if (mediaTrack.dbId != null) {
throw new IllegalStateException("Property dbId must not be null for newly created media track.");
}
racingEventService().mediaTrackAdded(mediaTrack);
SecurityService securityService = racingEventService().getSecurityService();
securityService.setDefaultOwnershipIfNotSet(mediaTrack.getIdentifier());
MediaTrackWithSecurityDTO mediaTrackWithSecurity = new MediaTrackWithSecurityDTO(mediaTrack);
SecurityDTOUtil.addSecurityInformation(racingEventService().getSecurityService(), mediaTrackWithSecurity,
mediaTrackWithSecurity.getIdentifier());
return mediaTrackWithSecurity;
final SecurityService securityService = racingEventService().getSecurityService();
final QualifiedObjectIdentifier identifier = mediaTrack.getIdentifier();
securityService.setDefaultOwnershipIfNotSet(identifier);
if (!SecurityUtils.getSubject().isPermitted(identifier.getStringPermission(DefaultActions.CREATE))) {
// the user was not permitted to create the object; remove it again
racingEventService().mediaTrackDeleted(mediaTrack);
securityService.deleteOwnership(identifier);
throw new UnauthenticatedException("Not authorized to create media track object");
} else {
final MediaTrackWithSecurityDTO mediaTrackWithSecurity = new MediaTrackWithSecurityDTO(mediaTrack);
SecurityDTOUtil.addSecurityInformation(racingEventService().getSecurityService(), mediaTrackWithSecurity,
mediaTrackWithSecurity.getIdentifier());
return mediaTrackWithSecurity;
}
}
@Override
@@ -3522,8 +3522,12 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
}
break;
case CHART_BEAT_ANGLE:
case CHART_ABS_TWA:
Bearing twa = trackedRace.getTWA(competitor, timePoint, cache);
result = twa == null? null:twa.getDegrees();
result = twa == null ? null : twa.getDegrees();
if (result != null && dataType == DetailType.CHART_ABS_TWA) {
result = Math.abs(result);
}
break;
case BRAVO_RACE_HEEL_IN_DEGREES:
case BRAVO_LEG_CURRENT_HEEL_IN_DEGREES: {
@@ -6367,16 +6371,18 @@ public class SailingServiceImpl extends ResultCachingProxiedRemoteServiceServlet
public Pair<Boolean, Boolean> setFinishingAndEndTime(RaceLogSetFinishingAndFinishTimeDTO dto)
throws NotFoundException {
getSecurityService().checkCurrentUserUpdatePermission(getLeaderboardByName(dto.leaderboardName));
final MillisecondsTimePoint finishingTimePoint = dto.finishingTime==null?null:new MillisecondsTimePoint(dto.finishingTime);
TimePoint newFinsihingTime = getService().setFinishingTime(dto.leaderboardName, dto.raceColumnName,
dto.fleetName, dto.authorName, dto.authorPriority,
dto.passId, new MillisecondsTimePoint(dto.finishingTime));
dto.passId, finishingTimePoint);
final TimePoint finishTimePoint = dto.finishTime==null?null:new MillisecondsTimePoint(dto.finishTime);
TimePoint newEndTime = getService().setEndTime(dto.leaderboardName, dto.raceColumnName,
dto.fleetName, dto.authorName, dto.authorPriority,
dto.passId, new MillisecondsTimePoint(dto.finishTime));
dto.passId, finishTimePoint);
return new Pair<Boolean, Boolean>(new MillisecondsTimePoint(dto.finishingTime).equals(newFinsihingTime),
new MillisecondsTimePoint(dto.finishTime).equals(newEndTime));
return new Pair<Boolean, Boolean>(Util.equalsWithNull(finishingTimePoint, newFinsihingTime),
Util.equalsWithNull(finishTimePoint, newEndTime));
}
@Override
@@ -8,7 +8,7 @@ import com.sap.sse.security.shared.dto.OwnershipDTO;
import com.sap.sse.security.shared.dto.SecuredDTO;
import com.sap.sse.security.shared.dto.SecurityInformationDTO;
public class DeviceConfigurationWithSecurityDTO extends DeviceConfigurationDTO implements SecuredDTO{
public class DeviceConfigurationWithSecurityDTO extends DeviceConfigurationDTO implements SecuredDTO {
private static final long serialVersionUID = 7187283665921500148L;
@@ -20,6 +20,9 @@ securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
securityManager.subjectFactory=$webSubjectFactoryWithAnonymousPrincipalSupport
@@ -29,6 +29,12 @@
The new end points support resolving, creation and deletion of user groups, as well as adding
and removing users and roles to and from user groups.
</li>
<li>The Device Configurations table for the Race Manager App now updates its underlying data
properly when a configuration is edited locally.
</li>
<li>Blue flag up/down times can be cleared in the AdminConsole now</li>
<li>Users can now create media tracks if they have the permissions based on the ownership that
will result from the creation process.</li>
</ul>
<h2 class="articleSubheadline">May 2019</h2>
<ul class="bulletList">
@@ -22,6 +22,9 @@ securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
securityManager.subjectFactory=$webSubjectFactoryWithAnonymousPrincipalSupport
@@ -89,7 +89,6 @@ public class AccessControlStoreImpl implements AccessControlStore {
@Override
public void loadACLsAndOwnerships() {
LockUtil.executeWithWriteLock(lockForManagementMappings, new Runnable() {
@Override
public void run() {
if (domainObjectFactory != null) {
@@ -97,7 +96,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
internalAddACL(acl);
}
for (OwnershipAnnotation ownership : domainObjectFactory.loadAllOwnerships(userStore)) {
internalSetOwnershipAndmapUserAndUserGroupToOwnership(ownership);
internalSetOwnershipAndMapUserAndUserGroupToOwnership(ownership);
}
}
}
@@ -294,13 +293,12 @@ public class AccessControlStoreImpl implements AccessControlStore {
final OwnershipAnnotation ownership = new OwnershipAnnotation(new Ownership(userOwnerName, tenantOwner), id,
displayNameOfOwnedObject);
LockUtil.executeWithWriteLock(lockForManagementMappings, new Runnable() {
@Override
public void run() {
// first removing it, prevents the necessity to do a delta update
removeUserAndUserGroupToOwnershipMapping(ownership);
// and add it to the new ownership
internalSetOwnershipAndmapUserAndUserGroupToOwnership(ownership);
internalSetOwnershipAndMapUserAndUserGroupToOwnership(ownership);
}
});
// and that it is finally written
@@ -308,7 +306,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
return ownership;
}
private void internalSetOwnershipAndmapUserAndUserGroupToOwnership(final OwnershipAnnotation ownership) {
private void internalSetOwnershipAndMapUserAndUserGroupToOwnership(final OwnershipAnnotation ownership) {
ownerships.put(ownership.getIdOfAnnotatedObject(), ownership);
UserGroup tenantOwner = ownership.getAnnotation().getTenantOwner();
if (tenantOwner != null) {
@@ -413,7 +411,6 @@ public class AccessControlStoreImpl implements AccessControlStore {
@Override
public void replaceContentsFrom(final AccessControlStore newAccessControlStore) {
LockUtil.executeWithWriteLock(lockForManagementMappings, new Runnable() {
@Override
public void run() {
clear();
@@ -421,7 +418,7 @@ public class AccessControlStoreImpl implements AccessControlStore {
internalAddACL(acl);
}
for (OwnershipAnnotation ownership : newAccessControlStore.getOwnerships()) {
ownerships.put(ownership.getIdOfAnnotatedObject(), ownership);
internalSetOwnershipAndMapUserAndUserGroupToOwnership(ownership);
}
}
});
@@ -28,7 +28,6 @@ import com.sap.sse.security.jaxrs.api.SecurityResource;
*
*/
public class BearerTokenOrBasicOrFormAuthenticationFilter extends BasicHttpAuthenticationFilter {
private static final String BEARER = "Bearer";
/**
@@ -0,0 +1,25 @@
package com.sap.sse.security;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SubjectDAO;
import org.apache.shiro.subject.Subject;
/**
* A special {@link SubjectDAO} implementation that refuses to create/store a session for a subject that is not
* authenticated. In {@code shiro.ini} configure like this:
*
* <pre>
*
* subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
* securityManager.subjectDAO = $subjectDAO
* </pre>
*
* @author Axel Uhl (D043530)
*
*/
public class NoSessionStorageForUnauthenticatedSessionsSessionDAO extends DefaultSubjectDAO {
@Override
protected boolean isSessionStorageEnabled(Subject subject) {
return subject.isAuthenticated();
}
}
@@ -1182,7 +1182,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
store.removeAllQualifiedRolesForUser(userToDelete);
final String defaultTenantNameForUsername = getDefaultTenantNameForUsername(username);
UserGroup defaultTenantUserGroup = getUserGroupByName(defaultTenantNameForUsername);
final UserGroup defaultTenantUserGroup = getUserGroupByName(defaultTenantNameForUsername);
if (defaultTenantUserGroup != null) {
List<User> usersInGroupList = Util.asList(defaultTenantUserGroup.getUsers());
if (usersInGroupList.size() == 1 && usersInGroupList.contains(userToDelete)) {
@@ -1196,7 +1196,9 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
}
// also remove from all usergroups
for (UserGroup userGroup : userToDelete.getUserGroups()) {
internalRemoveUserFromUserGroup(userGroup.getId(), userToDelete.getName());
if (userGroup != defaultTenantUserGroup) { // the defaultTenantUserGroup has already been deleted above
internalRemoveUserFromUserGroup(userGroup.getId(), userToDelete.getName());
}
}
store.deleteUser(username);
}
@@ -2024,6 +2026,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
@Override
public void initiallyFillFromInternal(ObjectInputStream is) throws IOException, ClassNotFoundException,
InterruptedException {
logger.info("Reading cache manager...");
ReplicatingCacheManager newCacheManager = (ReplicatingCacheManager) is.readObject();
cacheManager.replaceContentsFrom(newCacheManager);
// overriding thread context class loader because the user store may be provided by a different bundle;
@@ -2032,6 +2035,7 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
if (store != null) {
Thread.currentThread().setContextClassLoader(store.getClass().getClassLoader());
}
logger.info("Reading user store...");
try {
UserStore newUserStore = (UserStore) is.readObject();
store.replaceContentsFrom(newUserStore);
@@ -2041,12 +2045,14 @@ public class SecurityServiceImpl implements ReplicableSecurityService, ClearStat
if (accessControlStore != null) {
Thread.currentThread().setContextClassLoader(accessControlStore.getClass().getClassLoader());
}
logger.info("Reading access control store...");
try {
AccessControlStore newAccessControlStore = (AccessControlStore) is.readObject();
accessControlStore.replaceContentsFrom(newAccessControlStore);
} finally {
Thread.currentThread().setContextClassLoader(oldCCL);
}
logger.info("Done filling SecurityService");
}
@Override
@@ -14,6 +14,7 @@ import com.tractrac.model.lib.impl.attachment.DefaultAttachmentManager;
import com.tractrac.model.lib.impl.data.DefaultPositionFactory;
import com.tractrac.model.lib.impl.event.EventFactory;
import com.tractrac.model.lib.impl.metadata.DefaultMetadataFactory;
import com.tractrac.model.lib.impl.route.PathRouteFactory;
import com.tractrac.subscription.lib.api.SubscriptionLocator;
import com.tractrac.subscription.lib.impl.SubscriberFactory;
import com.tractrac.util.lib.api.UtilLocator;
@@ -33,6 +34,7 @@ public class Activator implements BundleActivator {
DataflowProviderLocator.registerStoredDataProviderFactory(new MTBStoredDataProviderFactory());
ModelLocator.registerAttachmentManager(new DefaultAttachmentManager());
ModelLocator.registerEventFactory(new EventFactory());
ModelLocator.registerPathRouteFactory(new PathRouteFactory());
ModelLocator.registerPositionFactory(new DefaultPositionFactory());
ModelLocator.registerMetadataFactory(new DefaultMetadataFactory());
SubscriptionLocator.registerSubscriberFactory(new SubscriberFactory());
@@ -17,7 +17,7 @@
android:layout_weight="1"
android:completionThreshold="1"
android:hint="@string/enter_new_item"
android:inputType="textNoSuggestions|textVisiblePassword" />
android:inputType="textCapWords|textNoSuggestions" />
<Button
android:id="@+id/edit_set_preference_add"
@@ -1,9 +1,5 @@
package com.sap.sailing.android.shared.ui.adapters;
import java.util.List;
import com.sap.sailing.android.shared.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,6 +9,12 @@ import android.widget.ArrayAdapter;
import android.widget.ImageButton;
import android.widget.TextView;
import com.sap.sailing.android.shared.R;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class ArrayRemoveAdapter<T> extends ArrayAdapter<T> {
public interface NotifyDataSetChangedListener<T> {
@@ -54,6 +56,14 @@ public class ArrayRemoveAdapter<T> extends ArrayAdapter<T> {
}
}
public Set<T> getItems() {
Set<T> items = new LinkedHashSet<>(getCount());
for (int position = 0; position < getCount(); position++) {
items.add(getItem(position));
}
return items;
}
public NotifyDataSetChangedListener<T> getDataSetChangedListener() {
return listener;
}
@@ -1,14 +1,5 @@
package com.sap.sailing.android.shared.ui.fragments.preference;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.android.shared.R;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.ui.adapters.ArrayRemoveAdapter;
import com.sap.sailing.android.shared.ui.views.EditSetPreference;
import android.os.Bundle;
import android.support.v7.preference.DialogPreference;
import android.support.v7.preference.Preference;
@@ -21,11 +12,20 @@ import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.ListView;
import com.sap.sailing.android.shared.R;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.ui.adapters.ArrayRemoveAdapter;
import com.sap.sailing.android.shared.ui.views.EditSetPreference;
import java.util.ArrayList;
import java.util.Set;
public class EditSetPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat {
private static final String TAG = EditSetPreferenceDialogFragmentCompat.class.getName();
private Set<String> currentValue;
private ArrayRemoveAdapter<String> adapter;
private Set<String> currentValues;
private Set<String> exampleValues;
public static EditSetPreferenceDialogFragmentCompat newInstance(Preference preference) {
@@ -40,30 +40,29 @@ public class EditSetPreferenceDialogFragmentCompat extends PreferenceDialogFragm
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
final AutoCompleteTextView inputView = (AutoCompleteTextView) view.findViewById(R.id.edit_set_preference_input);
final Button addButton = (Button) view.findViewById(R.id.edit_set_preference_add);
final ListView listView = (ListView) view.findViewById(R.id.edit_set_preference_list);
final AutoCompleteTextView inputView = view.findViewById(R.id.edit_set_preference_input);
final Button addButton = view.findViewById(R.id.edit_set_preference_add);
final ListView listView = view.findViewById(R.id.edit_set_preference_list);
DialogPreference preference = getPreference();
if (preference instanceof EditSetPreference) {
currentValue = ((EditSetPreference) preference).getCurrentValue();
currentValues = ((EditSetPreference) preference).getCurrentValues();
exampleValues = ((EditSetPreference) preference).getExampleValues();
}
// setup list view
final ArrayRemoveAdapter<String> adapter = new ArrayRemoveAdapter<String>(view.getContext(),
new ArrayList<String>(currentValue));
adapter = new ArrayRemoveAdapter<>(view.getContext(), new ArrayList<>(currentValues));
listView.setEmptyView(view.findViewById(R.id.edit_set_preference_list_empty));
listView.setAdapter(adapter);
// setup inputView
ArrayAdapter<String> autoCompleteAdapter = new ArrayAdapter<String>(view.getContext(),
android.R.layout.simple_dropdown_item_1line, new ArrayList<String>(exampleValues));
ArrayAdapter<String> autoCompleteAdapter = new ArrayAdapter<>(view.getContext(),
android.R.layout.simple_dropdown_item_1line, new ArrayList<>(exampleValues));
inputView.setAdapter(autoCompleteAdapter);
inputView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
boolean invalid = s.length() == 0 || currentValue.contains(s.toString());
boolean invalid = s.length() == 0 || currentValues.contains(s.toString());
addButton.setEnabled(!invalid);
}
@@ -77,6 +76,7 @@ public class EditSetPreferenceDialogFragmentCompat extends PreferenceDialogFragm
});
// setup add button
addButton.setEnabled(false);
addButton.setOnClickListener(new View.OnClickListener() {
@Override
@@ -91,10 +91,11 @@ public class EditSetPreferenceDialogFragmentCompat extends PreferenceDialogFragm
@Override
public void onDialogClosed(boolean positiveResult) {
DialogPreference preference = getPreference();
Set<String> values = adapter.getItems();
if (positiveResult && (preference instanceof EditSetPreference)
&& preference.callChangeListener(new HashSet<String>(currentValue))) {
&& preference.callChangeListener(values)) {
ExLog.i(getContext(), TAG, "Storing result...");
preference.persistStringSet(currentValue);
preference.persistStringSet(values);
}
}
}
@@ -1,29 +1,29 @@
package com.sap.sailing.android.shared.ui.views;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.android.shared.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v7.preference.DialogPreference;
import android.util.AttributeSet;
import com.sap.sailing.android.shared.R;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class EditSetPreference extends DialogPreference {
private static final Set<String> defaultFallbackValue = new HashSet<String>();
private static final Set<String> defaultFallbackValue = new HashSet<>();
private static final int mDialogLayoutResId = R.layout.edit_set_preference;
private Set<String> currentValue;
private Set<String> currentValues;
private Set<String> exampleValues;
public EditSetPreference(Context context, AttributeSet attrs) {
super(context, attrs);
this.exampleValues = new HashSet<String>();
this.exampleValues = new HashSet<>();
}
public void setExampleValues(String[] values) {
@@ -34,8 +34,8 @@ public class EditSetPreference extends DialogPreference {
return exampleValues;
}
public Set<String> getCurrentValue() {
return currentValue;
public Set<String> getCurrentValues() {
return currentValues;
}
@Override
@@ -48,17 +48,17 @@ public class EditSetPreference extends DialogPreference {
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
if (restorePersistedValue) {
// Restore existing state
currentValue = getPersistedStringSet(defaultFallbackValue);
currentValues = getPersistedStringSet(defaultFallbackValue);
} else {
// Set default state from the XML attribute
currentValue = new HashSet<String>((Set<String>) defaultValue);
persistStringSet(currentValue);
currentValues = new HashSet<>((Set<String>) defaultValue);
persistStringSet(currentValues);
}
}
@Override
protected Object onGetDefaultValue(TypedArray a, int index) {
Set<String> defaultValue = new HashSet<String>();
Set<String> defaultValue = new HashSet<>();
for (CharSequence chars : a.getTextArray(index)) {
defaultValue.add(chars.toString());
}
@@ -71,10 +71,15 @@ public class EditSetPreference extends DialogPreference {
return defaultReturnValue;
}
Set<String> fallbackDefault = defaultReturnValue == null ? null : new HashSet<String>(defaultReturnValue);
Set<String> fallbackDefault = defaultReturnValue == null ? null : new HashSet<>(defaultReturnValue);
Set<String> value = getSharedPreferences().getStringSet(getKey(), fallbackDefault);
return value == null ? null : new HashSet<String>(value);
return value == null ? null : new HashSet<>(value);
}
@Override
public boolean persistStringSet(Set<String> values) {
currentValues = values;
return super.persistStringSet(values);
}
}
@@ -11,7 +11,6 @@ public class AppConstants {
public final static String INTENT_EXTRA_TIMEPOINT_MILLIS = PACKAGE_NAME + ".timePoint.millis";
public final static String INTENT_EXTRA_EVENTNAME = PACKAGE_NAME + ".eventName";
public final static String FLAG_KEY = PACKAGE_NAME + ".raceFlag";
public final static String EXTRA_FORCE_REFRESH = PACKAGE_NAME + ".forceRefresh";
public final static String AUTHOR_TYPE_OFFICER_VESSEL = "Race Officer on Vessel";
public final static String AUTHOR_TYPE_SHORE_CONTROL = "Shore Control";
@@ -1,36 +1,42 @@
package com.sap.sailing.racecommittee.app.domain.impl;
import java.io.Serializable;
import android.support.annotation.NonNull;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
import com.sap.sailing.domain.base.Boat;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.TimePoint;
import java.io.Serializable;
public class CompetitorResultWithIdImpl extends CompetitorResultImpl {
private static final long serialVersionUID = 4373611281142932067L;
private long mId;
private Boat mBoat;
public CompetitorResultWithIdImpl(long id, Boat boat, CompetitorResult result) {
this(id, boat, result.getCompetitorId(), result.getName(), result.getShortName(),
result.getOneBasedRank(), result.getMaxPointsReason(), result.getScore(), result.getFinishingTime(),
result.getComment(), result.getMergeState());
public CompetitorResultWithIdImpl(long id, CompetitorResult result) {
this(id, result.getCompetitorId(), result.getName(), result.getShortName(), result.getBoatName(),
result.getBoatSailId(),result.getOneBasedRank(), result.getMaxPointsReason(), result.getScore(),
result.getFinishingTime(), result.getComment(), result.getMergeState());
}
public CompetitorResultWithIdImpl(long id, Boat boat, Serializable competitorId, String competitorName,
String shortName, int oneBasedRank, MaxPointsReason maxPointsReason, Double score, TimePoint finishingTime,
String comment, MergeState mergeState) {
super(competitorId, competitorName, shortName,
boat == null ? null : boat.getName(), boat == null ? null : boat.getSailID(),
public CompetitorResultWithIdImpl(long id, Serializable competitorId, String competitorName, String shortName,
@NonNull Boat boat, int oneBasedRank, MaxPointsReason maxPointsReason,
Double score, TimePoint finishingTime, String comment, MergeState mergeState) {
this(id, competitorId, competitorName, shortName, boat.getName(), boat.getSailID(),
oneBasedRank, maxPointsReason, score, finishingTime, comment, mergeState);
mId = id;
mBoat = boat;
}
public CompetitorResultWithIdImpl(long id, Serializable competitorId, String competitorName, String shortName,
String boatName, String sailId, int oneBasedRank, MaxPointsReason maxPointsReason,
Double score, TimePoint finishingTime, String comment, MergeState mergeState) {
super(competitorId, competitorName, shortName, boatName, sailId, oneBasedRank, maxPointsReason, score,
finishingTime, comment, mergeState);
mId = id;
}
public long getId() {
return mId;
}
@@ -366,13 +366,6 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
public void onResume() {
super.onResume();
if (preferences.needConfigRefresh()) {
preferences.setNeedConfigRefresh(false);
Intent intent = new Intent(this, getClass());
startActivity(intent);
finish();
}
IntentFilter filter = new IntentFilter();
filter.addAction(AppConstants.INTENT_ACTION_RESET);
filter.addAction(AppConstants.INTENT_ACTION_VALID_DATA);
@@ -425,6 +418,8 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
@Override
public void onLoadSucceeded(DeviceConfiguration configuration, boolean isCached) {
getSupportLoaderManager().destroyLoader(0);
dismissProgressSpinner();
// this is our 'global' configuration, let's store it in app preferences
@@ -441,7 +436,6 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
getSupportLoaderManager().restartLoader(0, null, configurationLoader).forceLoad();
} else {
dismissProgressSpinner();
slideUpBackdropDelayed();
}
}
@@ -531,15 +525,16 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
/**
* Reset the data (reload from server)
*
* @param force
* Reload data, even if the backdrop is moved up
* @param force Reload data, even if the backdrop is moved up
*/
private void resetData(boolean force) {
if (!force && backdrop.getY() != 0) {
return;
if (force) {
setupDataManager();
}
setupDataManager();
if (backdrop.getY() == 0f) {
slideUpBackdropDelayed();
}
addEventListFragment();
@@ -554,11 +549,15 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (AppConstants.INTENT_ACTION_RESET.equals(action)) {
resetData(intent.getBooleanExtra(AppConstants.EXTRA_FORCE_REFRESH, false));
resetData(true);
} else if (AppConstants.INTENT_ACTION_VALID_DATA.equals(action)) {
resetData(false);
if (preferences.needConfigRefresh()) {
resetData(true);
preferences.setNeedConfigRefresh(false);
} else {
resetData(false);
}
}
}
}
@@ -208,7 +208,6 @@ public class LoginBackdrop extends Fragment implements BackPressListener {
private void refreshData() {
Intent intent = new Intent(AppConstants.INTENT_ACTION_RESET);
intent.putExtra(AppConstants.EXTRA_FORCE_REFRESH, true);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
}
@@ -352,10 +351,7 @@ public class LoginBackdrop extends Fragment implements BackPressListener {
if (resultCode == CommonStatusCodes.SUCCESS && data != null) {
Barcode barcode = data.getParcelableExtra(BarcodeCaptureActivity.BarcodeObject);
if (QRHelper.with(getActivity()).saveData(barcode.displayValue)) {
BroadcastManager.getInstance(getActivity())
.addIntent(new Intent(AppConstants.INTENT_ACTION_CHECK_LOGIN));
}
QRHelper.with(getActivity()).saveData(barcode.displayValue);
} else {
Toast.makeText(getActivity(), getString(R.string.error_scanning_qr, resultCode), Toast.LENGTH_LONG).show();
}
@@ -98,6 +98,8 @@ public class MainPreferenceFragment extends LoggableFragment {
@Override
public void onLoadSucceeded(DeviceConfiguration configuration,
boolean isCached) {
getLoaderManager().destroyLoader(0);
// this is our 'global' configuration, let's store it in app preferences
PreferencesDeviceConfigurationLoader
.wrap(configuration, AppPreferences.on(getActivity())).store();
@@ -42,6 +42,7 @@ public class PositionListFragment extends LoggableListFragment {
preferences = AppPreferences.on(getActivity());
values.clear();
values.add(new LoginTypeItem(1, getString(R.string.login_type_officer_on_vessel),
AppConstants.AUTHOR_TYPE_OFFICER_VESSEL, LoginType.OFFICER));
values.add(new LoginTypeItem(2, getString(R.string.login_type_shore_control),
@@ -1,7 +1,9 @@
package com.sap.sailing.racecommittee.app.ui.fragments.preference;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.EditTextPreference;
@@ -9,23 +11,34 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceChangeListener;
import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
import android.widget.Toast;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.vision.barcode.Barcode;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.ui.activities.BarcodeCaptureActivity;
import com.sap.sailing.android.shared.ui.fragments.preference.BasePreferenceFragment;
import com.sap.sailing.android.shared.ui.views.EditSetPreference;
import com.sap.sailing.domain.base.configuration.DeviceConfiguration;
import com.sap.sailing.racecommittee.app.AppPreferences;
import com.sap.sailing.racecommittee.app.BuildConfig;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
import com.sap.sailing.racecommittee.app.domain.configuration.impl.PreferencesDeviceConfigurationLoader;
import com.sap.sailing.racecommittee.app.utils.QRHelper;
import com.sap.sailing.racecommittee.app.utils.autoupdate.AutoUpdater;
import java.io.FileNotFoundException;
import java.util.Objects;
import java.util.UUID;
public class GeneralPreferenceFragment extends BasePreferenceFragment {
private static final String TAG = GeneralPreferenceFragment.class.getName();
private static int REQUEST_CODE_QR_CODE = 45392;
@Override
@@ -174,7 +187,6 @@ public class GeneralPreferenceFragment extends BasePreferenceFragment {
if (resultCode == CommonStatusCodes.SUCCESS && data != null) {
Barcode barcode = data.getParcelableExtra(BarcodeCaptureActivity.BarcodeObject);
QRHelper.with(getActivity()).saveData(barcode.displayValue);
final AppPreferences appPreferences = AppPreferences.on(getActivity());
appPreferences.setNeedConfigRefresh(true);
// update device identifier in ui
@@ -184,6 +196,71 @@ public class GeneralPreferenceFragment extends BasePreferenceFragment {
// update server url in ui
EditTextPreference serverUrlPreference = findPreference(R.string.preference_server_url_key);
serverUrlPreference.setText(appPreferences.getServerBaseURL());
//Update all the other preferences, e.g. course areas, mail recipient
final SharedPreferences.OnSharedPreferenceChangeListener listener =
new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
final Preference preference = findPreference(key);
if (preference == null) {
return;
}
final Object newValue = sharedPreferences.getAll().get(key);
final OnPreferenceChangeListener listener = preference.getOnPreferenceChangeListener();
if (listener != null) {
listener.onPreferenceChange(preference, newValue);
}
}
};
PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(getContext()))
.registerOnSharedPreferenceChangeListener(listener);
String deviceConfigurationName = AppPreferences.on(getActivity()).getDeviceConfigurationName();
UUID deviceConfigurationUuid = AppPreferences.on(getActivity()).getDeviceConfigurationUuid();
LoaderManager.LoaderCallbacks<?> configurationLoader = DataManager.create(getActivity())
.createConfigurationLoader(deviceConfigurationName, deviceConfigurationUuid, new LoadClient<DeviceConfiguration>() {
@Override
public void onLoadFailed(Exception reason) {
if (reason instanceof FileNotFoundException) {
Toast.makeText(getActivity(),
getString(R.string.loading_configuration_not_found),
Toast.LENGTH_LONG).show();
ExLog.w(getActivity(), TAG, String.format(
"There seems to be no configuration for this device: %s",
reason.toString()));
} else {
Toast.makeText(getActivity(),
getString(R.string.loading_configuration_failed),
Toast.LENGTH_LONG).show();
ExLog.ex(getActivity(), TAG, reason);
}
PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(getContext()))
.unregisterOnSharedPreferenceChangeListener(listener);
}
@Override
public void onLoadSucceeded(DeviceConfiguration configuration,
boolean isCached) {
getLoaderManager().destroyLoader(0);
// this is our 'global' configuration, let's store it in app preferences
PreferencesDeviceConfigurationLoader
.wrap(configuration, AppPreferences.on(getActivity())).store();
Toast.makeText(getActivity(),
getString(R.string.loading_configuration_succeded),
Toast.LENGTH_LONG).show();
PreferenceManager.getDefaultSharedPreferences(Objects.requireNonNull(getContext()))
.unregisterOnSharedPreferenceChangeListener(listener);
}
});
getLoaderManager().initLoader(0, null, configurationLoader).forceLoad();
} else {
Toast.makeText(getActivity(), getString(R.string.error_scanning_qr, resultCode), Toast.LENGTH_LONG).show();
}
@@ -679,7 +679,7 @@ public class PenaltyFragment extends BaseFragment
}
}
competitor.setMergeState(MergeState.OK);
CompetitorResultWithIdImpl item = new CompetitorResultWithIdImpl(0, getBoat(competitor.getCompetitorId()), competitor);
CompetitorResultWithIdImpl item = new CompetitorResultWithIdImpl(0, competitor);
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_AlertDialog);
builder.setTitle(CompetitorUtils.getDisplayName(item));
final CompetitorEditLayout layout = new CompetitorEditLayout(getActivity(), item,
@@ -162,12 +162,12 @@ public class TrackingListFragment extends BaseFragment
RaceFragment fragment = PenaltyFragment.newInstance();
int viewId = R.id.race_content;
switch (getRaceState().getStatus()) {
case FINISHED:
viewId = getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true);
break;
case FINISHED:
viewId = getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true);
break;
default:
break;
default:
break;
}
replaceFragment(fragment, viewId);
}
@@ -379,23 +379,23 @@ public class TrackingListFragment extends BaseFragment
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.by_short_name:
mComparator = mComparators.get(SORT_SHORT_NAME);
break;
case R.id.by_name:
mComparator = mComparators.get(SORT_NAME);
break;
case R.id.by_start:
mComparator = mComparators.get(SORT_START);
break;
case R.id.by_goal:
mComparator = mComparators.get(SORT_GOAL);
break;
case R.id.by_boat:
mComparator = mComparators.get(SORT_SAIL_NUMBER);
break;
default:
mComparator = mComparators.get(SORT_SAIL_NUMBER);
case R.id.by_short_name:
mComparator = mComparators.get(SORT_SHORT_NAME);
break;
case R.id.by_name:
mComparator = mComparators.get(SORT_NAME);
break;
case R.id.by_start:
mComparator = mComparators.get(SORT_START);
break;
case R.id.by_goal:
mComparator = mComparators.get(SORT_GOAL);
break;
case R.id.by_boat:
mComparator = mComparators.get(SORT_SAIL_NUMBER);
break;
default:
mComparator = mComparators.get(SORT_SAIL_NUMBER);
}
sortCompetitors();
@@ -562,8 +562,7 @@ public class TrackingListFragment extends BaseFragment
Collections.synchronizedList(new ArrayList<CompetitorResultWithIdImpl>()));
if (getRaceState() != null && getRaceState().getFinishPositioningList() != null) {
for (CompetitorResult result : getRaceState().getFinishPositioningList()) {
Boat boat = getBoat(result.getCompetitorId());
positioning.add(new CompetitorResultWithIdImpl(mId, boat, result));
positioning.add(new CompetitorResultWithIdImpl(mId, result));
mId++;
}
}
@@ -627,8 +626,9 @@ public class TrackingListFragment extends BaseFragment
@Override
public void onCancel(DialogInterface dialog) {
CompetitorResultWithIdImpl newItem = new CompetitorResultWithIdImpl(item.getId(),
getBoat(item.getCompetitorId()), item.getCompetitorId(), item.getName(), item.getShortName(),
item.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(), item.getFinishingTime(),
item.getCompetitorId(), item.getName(), item.getShortName(),
item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(),
item.getMaxPointsReason(), item.getScore(), item.getFinishingTime(),
item.getComment(), MergeState.OK);
updateItem(item, newItem);
}
@@ -653,9 +653,10 @@ public class TrackingListFragment extends BaseFragment
greatestOneBasedRankSoFar = result.getOneBasedRank();
}
}
CompetitorResultWithIdImpl theCompetitor = new CompetitorResultWithIdImpl(mId, getBoat(competitor.getId()), competitor.getId(),
competitor.getName(), competitor.getShortName(), greatestOneBasedRankSoFar + 1, MaxPointsReason.NONE,
/* score */ null, /* finishingTime */ null, /* comment */ null, MergeState.OK);
CompetitorResultWithIdImpl theCompetitor = new CompetitorResultWithIdImpl(mId, competitor.getId(),
competitor.getName(), competitor.getShortName(), getBoat(competitor.getId()),
greatestOneBasedRankSoFar + 1, MaxPointsReason.NONE, /* score */ null, /* finishingTime */ null,
/* comment */ null, MergeState.OK);
mFinishedData.add(pos, theCompetitor);
mId++;
setPublishButton();
@@ -694,11 +695,9 @@ public class TrackingListFragment extends BaseFragment
* position</li>
* </ol>
*
* @param fromPosition
* the position (zero-based index) where the item currently is in {@link #mFinishedData}
* @param toPosition
* the position (zero-based index <em>after</em> removal of the item from its {@code fromPosition}) where
* to {@link List#add(int, Object)} the item again in {@link #mFinishedData}
* @param fromPosition the position (zero-based index) where the item currently is in {@link #mFinishedData}
* @param toPosition the position (zero-based index <em>after</em> removal of the item from its {@code fromPosition}) where
* to {@link List#add(int, Object)} the item again in {@link #mFinishedData}
*/
public boolean onItemMove(int fromPosition, int toPosition) {
final int firstPositionChanged = Math.min(getFirstRankZeroPosition(), Math.min(fromPosition, toPosition));
@@ -726,10 +725,8 @@ public class TrackingListFragment extends BaseFragment
* in the list plus one; stop before reaching the entry at list index {@code toPosition} or the
* {@link #getFirstRankZeroPosition() first penalty position}.
*
* @param fromPosition
* inclusive start index into {@link #mFinishedData} where to start updating the ranks
* @param toPosition
* inclusive end index into {@link #mFinishedData} where to stop updating the ranks; must not be -1
* @param fromPosition inclusive start index into {@link #mFinishedData} where to start updating the ranks
* @param toPosition inclusive end index into {@link #mFinishedData} where to stop updating the ranks; must not be -1
*/
private void adjustRanks(int fromPosition, int toPosition) {
final int end = Math.min(toPosition, getFirstRankZeroPosition());
@@ -741,13 +738,11 @@ public class TrackingListFragment extends BaseFragment
}
}
private CompetitorResultWithIdImpl cloneCompetitorResultAndAdjustRank(CompetitorResultWithIdImpl competitorToReplaceWithAdjustedPosition,
final int newOneBasedRank) {
return new CompetitorResultWithIdImpl(competitorToReplaceWithAdjustedPosition.getId(), getBoat(competitorToReplaceWithAdjustedPosition
.getCompetitorId()), competitorToReplaceWithAdjustedPosition.getCompetitorId(), competitorToReplaceWithAdjustedPosition
.getName(), competitorToReplaceWithAdjustedPosition.getShortName(), newOneBasedRank, competitorToReplaceWithAdjustedPosition
.getMaxPointsReason(), competitorToReplaceWithAdjustedPosition.getScore(), competitorToReplaceWithAdjustedPosition
.getFinishingTime(), competitorToReplaceWithAdjustedPosition.getComment(), MergeState.OK);
private CompetitorResultWithIdImpl cloneCompetitorResultAndAdjustRank(CompetitorResultWithIdImpl competitor,
final int newOneBasedRank) {
return new CompetitorResultWithIdImpl(competitor.getId(), competitor.getCompetitorId(), competitor.getName(),
competitor.getShortName(), competitor.getBoatName(), competitor.getBoatSailId(), newOneBasedRank, competitor.getMaxPointsReason(),
competitor.getScore(), competitor.getFinishingTime(), competitor.getComment(), MergeState.OK);
}
public void onLongClick(final CompetitorResultWithIdImpl item) {
@@ -785,14 +780,14 @@ public class TrackingListFragment extends BaseFragment
}
if (index >= 0) {
mFinishedData.set(index, newItem); // update the item in the list already; then check where to move it and
// adjust other elements
// adjust other elements
}
if (item.getOneBasedRank() != 0 && newItem.getOneBasedRank() == 0
&& newItem.getMaxPointsReason() != MaxPointsReason.NONE) {
// move to the end of the area of "penalized" competitors; may also be an unpenalized competitor that hasn't
// been removed yet (e.g., in order to force a score correction reset on the server)
mFinishedAdapter.onItemMove(index, mFinishedData.size() - 1); // -1 because first the element is removed, so when inserting
// the list is one element shorter
// the list is one element shorter
} else if (item.getOneBasedRank() != newItem.getOneBasedRank() && newItem.getOneBasedRank() != 0) {
mFinishedAdapter.onItemMove(index, newItem.getOneBasedRank() - 1);
} else if (newItem.getOneBasedRank() == 0 && newItem.getMaxPointsReason() == MaxPointsReason.NONE) {
@@ -813,7 +808,7 @@ public class TrackingListFragment extends BaseFragment
protected void setMaxPointsReasonForItem(CompetitorResultWithIdImpl item, CharSequence maxPointsReasonName) {
MaxPointsReason maxPointsReason = MaxPointsReason.valueOf(maxPointsReasonName.toString());
CompetitorResultWithIdImpl newItem = new CompetitorResultWithIdImpl(item.getId(), getBoat(item.getCompetitorId()), item);
CompetitorResultWithIdImpl newItem = new CompetitorResultWithIdImpl(item.getId(), item);
updateItem(item, newItem);
getRaceState().setFinishPositioningListChanged(MillisecondsTimePoint.now(), getCompetitorResults());
}
@@ -868,23 +863,23 @@ public class TrackingListFragment extends BaseFragment
public void onClick(View v) {
if (v != null) {
switch (v.getId()) {
case R.id.nav_prev:
viewPanel(MOVE_DOWN);
break;
case R.id.nav_prev:
viewPanel(MOVE_DOWN);
break;
case R.id.nav_next:
viewPanel(MOVE_UP);
break;
case R.id.nav_next:
viewPanel(MOVE_UP);
break;
}
}
if (mHeader != null) {
switch (mActivePage) {
case 0:
mHeader.setHeaderText(R.string.tracking_list_01);
break;
case 0:
mHeader.setHeaderText(R.string.tracking_list_01);
break;
default:
mHeader.setHeaderText(R.string.tracking_list_02);
default:
mHeader.setHeaderText(R.string.tracking_list_02);
}
}
if (mTools != null) {
@@ -969,7 +964,6 @@ public class TrackingListFragment extends BaseFragment
}
}
if (item != null) { // result is in list
Boat boat = getBoat(item.getCompetitorId());
// check one based rank
if (item.getOneBasedRank() != result.getOneBasedRank()) {
if (draft != null) {
@@ -981,8 +975,8 @@ public class TrackingListFragment extends BaseFragment
} else {
state = MergeState.ERROR;
}
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), result.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(),
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), result.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(),
item.getFinishingTime(), item.getComment(), getMergeState(item, state));
item = updateChangedItem(changedCompetitor, item, newItem);
}
@@ -998,9 +992,9 @@ public class TrackingListFragment extends BaseFragment
} else {
state = MergeState.ERROR;
}
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), item.getOneBasedRank(), result.getMaxPointsReason(), item.getScore(),
item.getFinishingTime(), item.getComment(), getMergeState(item, state));
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), result.getMaxPointsReason(),
item.getScore(), item.getFinishingTime(), item.getComment(), getMergeState(item, state));
item = updateChangedItem(changedCompetitor, item, newItem);
}
@@ -1016,16 +1010,17 @@ public class TrackingListFragment extends BaseFragment
} else {
state = MergeState.ERROR;
}
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(),
item.getName(), item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(),
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
result.getScore(), item.getFinishingTime(), item.getComment(),
getMergeState(item, state));
item = updateChangedItem(changedCompetitor, item, newItem);
}
} else if (result.getScore() != null) {
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(), result.getScore(),
item.getFinishingTime(), item.getComment(), getMergeState(item, MergeState.ERROR));
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
result.getScore(), item.getFinishingTime(), item.getComment(),
getMergeState(item, MergeState.ERROR));
item = updateChangedItem(changedCompetitor, item, newItem);
}
@@ -1041,16 +1036,17 @@ public class TrackingListFragment extends BaseFragment
} else {
state = MergeState.ERROR;
}
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(),
item.getName(), item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(),
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
item.getScore(), result.getFinishingTime(), item.getComment(),
getMergeState(item, state));
item = updateChangedItem(changedCompetitor, item, newItem);
}
} else if (result.getFinishingTime() != null) {
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(),
result.getFinishingTime(), item.getComment(), getMergeState(item, MergeState.ERROR));
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
item.getScore(), result.getFinishingTime(), item.getComment(),
getMergeState(item, MergeState.ERROR));
item = updateChangedItem(changedCompetitor, item, newItem);
}
@@ -1066,24 +1062,26 @@ public class TrackingListFragment extends BaseFragment
} else {
state = MergeState.ERROR;
}
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(),
item.getName(), item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(),
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
item.getScore(), item.getFinishingTime(),
item.getComment() + " ## " + result.getComment(), getMergeState(item, state));
item = updateChangedItem(changedCompetitor, item, newItem);
}
} else if (result.getComment() != null) {
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(),
item.getFinishingTime(), result.getComment(), getMergeState(item, MergeState.ERROR));
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
item.getScore(), item.getFinishingTime(), result.getComment(),
getMergeState(item, MergeState.ERROR));
item = updateChangedItem(changedCompetitor, item, newItem);
}
// check merge state
if (!item.getMergeState().equals(result.getMergeState())) {
newItem = new CompetitorResultWithIdImpl(item.getId(), boat, item.getCompetitorId(), item.getName(),
item.getShortName(), item.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(),
item.getFinishingTime(), item.getComment(), getMergeState(item, result.getMergeState()));
newItem = new CompetitorResultWithIdImpl(item.getId(), item.getCompetitorId(), item.getName(),
item.getShortName(), item.getBoatName(), item.getBoatSailId(), item.getOneBasedRank(), item.getMaxPointsReason(),
item.getScore(), item.getFinishingTime(), item.getComment(),
getMergeState(item, result.getMergeState()));
item = updateChangedItem(changedCompetitor, item, newItem);
}
} else { // unknown result, so it will be added
@@ -1094,8 +1092,7 @@ public class TrackingListFragment extends BaseFragment
break;
}
}
mFinishedData.add(new CompetitorResultWithIdImpl(mFinishedData.size(),
getBoat(result.getCompetitorId()), result));
mFinishedData.add(new CompetitorResultWithIdImpl(mFinishedData.size(), result));
Collections.sort(mFinishedData,
new DefaultCompetitorResultComparator(/* lowPoint TODO where to get this from? */ true));
}
@@ -1121,7 +1118,7 @@ public class TrackingListFragment extends BaseFragment
@NonNull
private CompetitorResultWithIdImpl updateChangedItem(Map<Serializable, String> changedCompetitor,
CompetitorResultWithIdImpl item, CompetitorResultWithIdImpl newItem) {
CompetitorResultWithIdImpl item, CompetitorResultWithIdImpl newItem) {
updateItem(item, newItem);
changedCompetitor.put(newItem.getCompetitorId(), CompetitorUtils.getDisplayName(newItem));
return newItem;
@@ -1130,23 +1127,23 @@ public class TrackingListFragment extends BaseFragment
private MergeState getMergeState(CompetitorResultWithIdImpl item, MergeState newState) {
MergeState state = item.getMergeState();
switch (item.getMergeState()) {
case ERROR:
if (newState != MergeState.ERROR) {
case ERROR:
if (newState != MergeState.ERROR) {
break;
}
state = newState;
break;
}
state = newState;
break;
case WARNING:
if (newState != MergeState.WARNING && newState != MergeState.ERROR) {
case WARNING:
if (newState != MergeState.WARNING && newState != MergeState.ERROR) {
break;
}
state = newState;
break;
}
state = newState;
break;
case OK:
state = newState;
break;
case OK:
state = newState;
break;
}
return state;
}
@@ -267,7 +267,7 @@ public class CompetitorEditLayout extends ScrollView
CompetitorResult result = new CompetitorResultImpl(mCompetitor.getCompetitorId(), mCompetitor.getName(),
mCompetitor.getShortName(), mCompetitor.getBoatName(), mCompetitor.getBoatSailId(), oneBaseRank,
maxPointsReason, score, finishingTime, comment, MergeState.OK);
return new CompetitorResultWithIdImpl(mCompetitor.getId(), mCompetitor.getBoat(), result);
return new CompetitorResultWithIdImpl(mCompetitor.getId(), result);
}
@Override