mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-14 06:18:12 +00:00
Merge branch 'master' into bug4942
This commit is contained in:
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);
|
||||
|
||||
-2
@@ -22,8 +22,6 @@ public class FinishedTimeFinder extends RaceLogAnalyzer<TimePoint> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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:
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
+13
-9
@@ -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
|
||||
|
||||
+16
-14
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-2
@@ -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()) {
|
||||
|
||||
+9
-7
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -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:
|
||||
|
||||
+3
@@ -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();
|
||||
|
||||
+4
-1
@@ -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}"?
|
||||
|
||||
+5
-2
@@ -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}
|
||||
|
||||
+6
-3
@@ -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(),
|
||||
|
||||
+16
-7
@@ -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
|
||||
|
||||
+11
-5
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+4
-7
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
-1
@@ -28,7 +28,6 @@ import com.sap.sse.security.jaxrs.api.SecurityResource;
|
||||
*
|
||||
*/
|
||||
public class BearerTokenOrBasicOrFormAuthenticationFilter extends BasicHttpAuthenticationFilter {
|
||||
|
||||
private static final String BEARER = "Bearer";
|
||||
|
||||
/**
|
||||
|
||||
+25
@@ -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"
|
||||
|
||||
+14
-4
@@ -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;
|
||||
}
|
||||
|
||||
+22
-21
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-17
@@ -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);
|
||||
}
|
||||
}
|
||||
-1
@@ -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";
|
||||
|
||||
+19
-13
@@ -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;
|
||||
}
|
||||
|
||||
+15
-16
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -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();
|
||||
}
|
||||
|
||||
+2
@@ -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();
|
||||
|
||||
+1
@@ -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),
|
||||
|
||||
+78
-1
@@ -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();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
+96
-99
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
Reference in new issue
Block a user