mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-10-17 09:41:00 +00:00
Merge remote-tracking branch 'origin/master' into leaderboardView2
This commit is contained in:
commit
daee1914a3
111 files changed
+2469
-1241
No files matched your search
+21
-10
@@ -142,7 +142,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
}
|
||||
|
||||
private TimePoint loadTimePoint(DBObject object, FieldNames field) {
|
||||
return new MillisecondsTimePoint((Long) object.get(field.name()));
|
||||
return new MillisecondsTimePoint(((Number) object.get(field.name())).longValue());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1006,14 +1006,15 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
RaceLog result = new RaceLogImpl(RaceLogImpl.class.getSimpleName(), identifier.getIdentifier());
|
||||
try {
|
||||
BasicDBObject query = new BasicDBObject();
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(identifier.getIdentifier().toString()));
|
||||
DBCollection raceLog = database.getCollection(CollectionNames.RACE_LOGS.name());
|
||||
for (DBObject o : raceLog.find(query)) {
|
||||
RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name()));
|
||||
|
||||
if (raceLogEvent != null)
|
||||
result.add(raceLogEvent);
|
||||
}
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(identifier.getIdentifier()));
|
||||
loadRaceLogEvents(result, query);
|
||||
|
||||
// query for obsolete events
|
||||
query.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(String.format("%s.%s.%s",
|
||||
identifier.getTemplate().getParentObjectName(),
|
||||
identifier.getRaceColumnName(),
|
||||
identifier.getFleetName())));
|
||||
loadRaceLogEvents(result, query);
|
||||
} catch (Throwable t) {
|
||||
// something went wrong during DB access; report, then use empty new race log
|
||||
logger.log(Level.SEVERE, "Error connecting to MongoDB, unable to load recorded race log data. Check MongoDB settings.");
|
||||
@@ -1022,6 +1023,16 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
return result;
|
||||
}
|
||||
|
||||
private void loadRaceLogEvents(RaceLog result, BasicDBObject query) {
|
||||
DBCollection raceLog = database.getCollection(CollectionNames.RACE_LOGS.name());
|
||||
for (DBObject o : raceLog.find(query)) {
|
||||
RaceLogEvent raceLogEvent = loadRaceLogEvent((DBObject) o.get(FieldNames.RACE_LOG_EVENT.name()));
|
||||
if (raceLogEvent != null) {
|
||||
result.add(raceLogEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public RaceLogEvent loadRaceLogEvent(DBObject dbObject) {
|
||||
TimePoint timePoint = loadTimePoint(dbObject);
|
||||
TimePoint createdAt = loadTimePoint(dbObject, FieldNames.RACE_LOG_EVENT_CREATED_AT);
|
||||
@@ -1190,7 +1201,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
|
||||
|
||||
private CourseBase loadCourseData(BasicDBList dbCourseList, String courseName) {
|
||||
if (courseName == null) {
|
||||
courseName = "Course template";
|
||||
courseName = "Course";
|
||||
}
|
||||
CourseBase courseData = new CourseDataImpl(courseName);
|
||||
int i = 0;
|
||||
|
||||
+14
-14
@@ -1,5 +1,5 @@
|
||||
package com.sap.sailing.domain.persistence.impl;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@@ -536,7 +536,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFlagEvent flagEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFlagEvent(flagEvent));
|
||||
return result;
|
||||
@@ -544,7 +544,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartTimeEvent startTimeEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartTimeEvent(startTimeEvent));
|
||||
return result;
|
||||
@@ -552,7 +552,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPassChangeEvent passChangeEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPassChangeEvent(passChangeEvent));
|
||||
return result;
|
||||
@@ -560,7 +560,7 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogRaceStatusEvent raceStatusEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogRaceStatusEvent(raceStatusEvent));
|
||||
return result;
|
||||
@@ -568,63 +568,63 @@ public class MongoObjectFactoryImpl implements MongoObjectFactory {
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseAreaChangedEvent courseAreaChangedEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseAreaChangedEvent(courseAreaChangedEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogCourseDesignChangedEvent courseDesignChangedEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogCourseDesignChangedEvent(courseDesignChangedEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningListChangedEvent finishPositioningListChangedEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningListChangedEvent(finishPositioningListChangedEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogFinishPositioningConfirmedEvent finishPositioningConfirmedEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogFinishPositioningConfirmedEvent(finishPositioningConfirmedEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogPathfinderEvent pathfinderEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogPathfinderEvent(pathfinderEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogGateLineOpeningTimeEvent gateLineOpeningTimeEvent) {
|
||||
BasicDBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogGateLineOpeningTimeEvent(gateLineOpeningTimeEvent));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogStartProcedureChangedEvent event) {
|
||||
DBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogStartProcedureChangedEvent(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogProtestStartTimeEvent event) {
|
||||
DBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogProtestStartTimeEvent(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
public DBObject storeRaceLogEntry(RaceLogIdentifier raceLogIdentifier, RaceLogWindFixEvent event) {
|
||||
DBObject result = new BasicDBObject();
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), MongoUtils.escapeDollarAndDot(raceLogIdentifier.getIdentifier().toString()));
|
||||
result.put(FieldNames.RACE_LOG_IDENTIFIER.name(), TripleSerializer.serialize(raceLogIdentifier.getIdentifier()));
|
||||
result.put(FieldNames.RACE_LOG_EVENT.name(), storeRaceLogWindFix(event));
|
||||
return result;
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package com.sap.sailing.domain.persistence.impl;
|
||||
|
||||
import com.mongodb.BasicDBObject;
|
||||
import com.mongodb.DBObject;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
|
||||
public class TripleSerializer {
|
||||
public static DBObject serialize(Triple<String, String, String> value) {
|
||||
DBObject container = new BasicDBObject();
|
||||
container.put("a", value.getA());
|
||||
container.put("b", value.getB());
|
||||
container.put("c", value.getC());
|
||||
return container;
|
||||
}
|
||||
}
|
||||
+6
@@ -831,4 +831,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTimeReceived() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+6
@@ -539,4 +539,10 @@ public class MockedTrackedRaceWithStartTimeAndRanks implements TrackedRace {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTimeReceived() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
+1
@@ -11,5 +11,6 @@ public interface TracTracConnectionConstants {
|
||||
final int PORT_STORED = PORT_LIVE + 1; //For official usage use 4401;
|
||||
|
||||
final String HIDDEN_STATUS = "HIDDEN";
|
||||
final Object REPLAY_STATUS = "REPLAY";
|
||||
|
||||
}
|
||||
+1
@@ -41,6 +41,7 @@ public class TracTracCourseDesignUpdateHandler extends UpdateHandler implements
|
||||
@Override
|
||||
public void courseDesignChanged(CourseBase newCourseDesign) throws MalformedURLException, IOException {
|
||||
if (!isActive()) {
|
||||
logger.info("Not sending course update to TracTrac because no URL has been provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+21
-6
@@ -582,12 +582,27 @@ public class TracTracRaceTrackerImpl extends AbstractRaceTrackerImpl implements
|
||||
updateStatusOfTrackedRaces();
|
||||
} else {
|
||||
// ask RacingEventService to cleanly stop and unregister this tracker
|
||||
for (RaceDefinition race : getRaces()) {
|
||||
try {
|
||||
trackedRegattaRegistry.stopTracking(getRegatta(), race);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to stop tracker for race "+race.getName()+
|
||||
" in regatta "+getRegatta().getName(), e);
|
||||
// if the race has all data loaded. Doing this asynchronously because
|
||||
// stopping can take longer and if you're loading many races in parallel
|
||||
// this can slow down loading extremely
|
||||
for (final RaceDefinition race : getRaces()) {
|
||||
DynamicTrackedRace trackedRace = getTrackedRegatta().getExistingTrackedRace(race);
|
||||
final Regatta regatta = getRegatta();
|
||||
if (trackedRace.getStatus().getLoadingProgress() == 1.0) {
|
||||
Thread raceStopper = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
trackedRegattaRegistry.stopTracking(regatta, race);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Error trying to stop tracker for race "+race.getName()+
|
||||
" in regatta "+getRegatta().getName(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
raceStopper.start();
|
||||
} else {
|
||||
logger.log(Level.SEVERE, "Not stopping race "+race.getName()+" because it has not all data loaded! Progress: " + trackedRace.getStatus().getLoadingProgress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -2,13 +2,15 @@ package com.sap.sailing.domain.racelog;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
|
||||
public interface RaceLogIdentifier extends Serializable {
|
||||
|
||||
String getRaceColumnName();
|
||||
|
||||
String getFleetName();
|
||||
|
||||
Serializable getIdentifier();
|
||||
Triple<String, String, String> getIdentifier();
|
||||
|
||||
RaceLogIdentifierTemplate getTemplate();
|
||||
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
package com.sap.sailing.domain.racelog.impl;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifierTemplate;
|
||||
|
||||
@@ -21,8 +21,8 @@ public class RaceLogIdentifierImpl implements RaceLogIdentifier {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getIdentifier() {
|
||||
return String.format("%s.%s.%s", template.getParentObjectName(), raceColumnName, fleetName);
|
||||
public Triple<String, String, String> getIdentifier() {
|
||||
return new Util.Triple<String, String, String>(template.getParentObjectName(), raceColumnName, fleetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -575,4 +575,9 @@ public interface TrackedRace extends Serializable {
|
||||
* If the competitor hasn't started yet, <code>null</code> is returned.
|
||||
*/
|
||||
Distance getDistanceFromStarboardSideOfStartLineWhenPassingStart(Competitor competitor);
|
||||
|
||||
/**
|
||||
* Start time received by the tracking infrastructure. To determine real start time use {@link #getStartOfRace()}.
|
||||
*/
|
||||
TimePoint getStartTimeReceived();
|
||||
}
|
||||
+26
-6
@@ -1,6 +1,9 @@
|
||||
package com.sap.sailing.domain.tracking.impl;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
import com.sap.sailing.domain.common.WindSourceType;
|
||||
import com.sap.sailing.domain.common.impl.WindSourceImpl;
|
||||
@@ -21,19 +24,22 @@ import com.sap.sailing.domain.racelog.RaceLogStartTimeEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogWindFixEvent;
|
||||
import com.sap.sailing.domain.racelog.analyzing.impl.LastPublishedCourseDesignFinder;
|
||||
import com.sap.sailing.domain.racelog.analyzing.impl.RaceStatusAnalyzer;
|
||||
import com.sap.sailing.domain.racelog.analyzing.impl.StartTimeFinder;
|
||||
import com.sap.sailing.domain.racelog.analyzing.impl.WindFixesFinder;
|
||||
import com.sap.sailing.domain.tracking.DynamicTrackedRace;
|
||||
import com.sap.sailing.domain.tracking.Wind;
|
||||
|
||||
public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
|
||||
|
||||
public static final Logger log = Logger.getLogger(DynamicTrackedRaceLogListener.class.getName());
|
||||
|
||||
private DynamicTrackedRace trackedRace;
|
||||
|
||||
private final WindSource raceCommitteeWindSource;
|
||||
|
||||
private RaceStatusAnalyzer statusAnalyzer;
|
||||
|
||||
private LastPublishedCourseDesignFinder courseDesignFinder;
|
||||
private StartTimeFinder startTimeFinder;
|
||||
|
||||
public DynamicTrackedRaceLogListener(DynamicTrackedRace trackedRace) {
|
||||
this.trackedRace = trackedRace;
|
||||
@@ -105,20 +111,34 @@ public class DynamicTrackedRaceLogListener implements RaceLogEventVisitor {
|
||||
// Because this code can be triggered by an obsolete (delayed) event...
|
||||
// ... onCourseDesignChangedByRaceCommittee() might be called more than once.
|
||||
trackedRace.onCourseDesignChangedByRaceCommittee(courseDesign);
|
||||
} else {
|
||||
log.info("Could not find any course design update on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void analyzeStartTime() {
|
||||
/* start time will be set by StartTimeAnalyzer in TrackedRace.getStartTime() */
|
||||
trackedRace.invalidateStartTime();
|
||||
|
||||
TimePoint startTime = startTimeFinder.analyze();
|
||||
if (startTime != null) {
|
||||
/* invoke listeners with received start time, this will also trigger tractrac update */
|
||||
trackedRace.onStartTimeChangedByRaceCommittee(startTime);
|
||||
} else {
|
||||
log.info("Could not find any valid start time on race log of " + trackedRace.getRace().getName() + "! Not sending out any events.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogPassChangeEvent event) {
|
||||
trackedRace.invalidateStartTime();
|
||||
/* this will send tractrac the original start time */
|
||||
trackedRace.onStartTimeChangedByRaceCommittee(trackedRace.getStartTimeReceived());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(RaceLogStartTimeEvent event) {
|
||||
/* start time will be set by StartTimeAnalyzer in TrackedRace.getStartTime() */
|
||||
trackedRace.invalidateStartTime();
|
||||
/* invoke listeners with received start time, this will also trigger tractrac update */
|
||||
trackedRace.onStartTimeChangedByRaceCommittee(event.getStartTime());
|
||||
analyzeStartTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-2
@@ -495,7 +495,7 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
}
|
||||
}
|
||||
if (startTime == null) {
|
||||
startTime = startTimeReceived;
|
||||
startTime = getStartTimeReceived();
|
||||
// If not null, check if the first mark passing for the start line is too much after the
|
||||
// startTimeReceived; if so, return an adjusted, later start time.
|
||||
// If no official start time was received, try to estimate the start time using the mark passings for
|
||||
@@ -1356,7 +1356,8 @@ public abstract class TrackedRaceImpl implements TrackedRace, CourseListener {
|
||||
}
|
||||
}
|
||||
|
||||
protected TimePoint getStartTimeReceived() {
|
||||
@Override
|
||||
public TimePoint getStartTimeReceived() {
|
||||
return startTimeReceived;
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -833,4 +833,10 @@ public class MockedTrackedRace implements DynamicTrackedRace {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTimeReceived() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -706,3 +706,8 @@ video {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.pointeredLink {
|
||||
cursor: pointer;
|
||||
cursor: hand;
|
||||
}
|
||||
+98
-22
@@ -1,6 +1,8 @@
|
||||
package com.sap.sailing.gwt.ui.masterdataimport;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
@@ -8,6 +10,8 @@ import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.dom.client.KeyCodes;
|
||||
import com.google.gwt.event.dom.client.KeyDownEvent;
|
||||
import com.google.gwt.event.dom.client.KeyDownHandler;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
import com.google.gwt.http.client.Request;
|
||||
import com.google.gwt.http.client.RequestBuilder;
|
||||
import com.google.gwt.http.client.RequestCallback;
|
||||
@@ -15,7 +19,6 @@ import com.google.gwt.http.client.RequestException;
|
||||
import com.google.gwt.http.client.Response;
|
||||
import com.google.gwt.json.client.JSONArray;
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
import com.google.gwt.json.client.JSONString;
|
||||
import com.google.gwt.regexp.shared.RegExp;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.rpc.AsyncCallback;
|
||||
@@ -39,7 +42,9 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
private ListBox leaderboardgroupListBox;
|
||||
private TextBox hostBox;
|
||||
private Button importLeaderboardGroupsButton;
|
||||
private Button fetchIdsButton;
|
||||
private Button fetchIdsButton;
|
||||
|
||||
private List<String> allLeaderboardGroupNames;
|
||||
|
||||
private RegExp urlValidator;
|
||||
private RegExp urlPlusTldValidator;
|
||||
@@ -113,7 +118,7 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
protected void importLeaderboardGroups() {
|
||||
String[] groupNames = createLeaderBoardGroupNamesFromListBox();
|
||||
if (groupNames.length >= 1) {
|
||||
changeAllButtonState(false);
|
||||
disableAllButtons();
|
||||
boolean override = overrideSwitch.getValue();
|
||||
sailingService.importMasterData(currentHost, groupNames, override,
|
||||
new AsyncCallback<MasterDataImportObjectCreationCount>() {
|
||||
@@ -135,13 +140,13 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
}
|
||||
showSuccessAlert(leaderboardsCreated, leaderboardGroupsCreated, eventsCreated,
|
||||
regattasCreated);
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable caught) {
|
||||
showErrorAlert(caught.getLocalizedMessage());
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -150,11 +155,33 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
}
|
||||
|
||||
|
||||
private void changeAllButtonState(boolean enabled) {
|
||||
private void disableAllButtons() {
|
||||
boolean enabled = false;
|
||||
importLeaderboardGroupsButton.setEnabled(enabled);
|
||||
overrideSwitch.setEnabled(enabled);
|
||||
fetchIdsButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
private void changeButtonStateAccordingToApplicationState() {
|
||||
if (leaderboardgroupListBox.getItemCount() > 0 && countSelectedItems() > 0) {
|
||||
importLeaderboardGroupsButton.setEnabled(true);
|
||||
} else {
|
||||
importLeaderboardGroupsButton.setEnabled(false);
|
||||
}
|
||||
overrideSwitch.setEnabled(true);
|
||||
fetchIdsButton.setEnabled(true);
|
||||
}
|
||||
|
||||
|
||||
private int countSelectedItems() {
|
||||
int count = 0;
|
||||
for (int i = 0; i < leaderboardgroupListBox.getItemCount(); i++) {
|
||||
if (leaderboardgroupListBox.isItemSelected(i)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
protected void showSuccessAlert(int leaderboardsCreated, int leaderboardGroupsCreated, int eventsCreated,
|
||||
int regattasCreated) {
|
||||
@@ -187,7 +214,7 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
showErrorAlert(stringMessages.importUrlInvalid(getLgsUrl));
|
||||
return;
|
||||
}
|
||||
changeAllButtonState(false);
|
||||
disableAllButtons();
|
||||
RequestBuilder getLgsRequestBuilder = new RequestBuilder(RequestBuilder.GET, getLgsUrl);
|
||||
getLgsRequestBuilder.setCallback(new RequestCallback() {
|
||||
|
||||
@@ -196,41 +223,38 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
if (response.getStatusCode() != 200) {
|
||||
showErrorAlert(stringMessages.importGetLeaderboardsFailed(response.getStatusCode(), getLgsUrl));
|
||||
}
|
||||
int itemCount = leaderboardgroupListBox.getItemCount();
|
||||
for (int i = itemCount - 1; i >= 0; i--) {
|
||||
leaderboardgroupListBox.removeItem(i);
|
||||
}
|
||||
clearListBox();
|
||||
String body = response.getText();
|
||||
if (body == null || body.isEmpty()) {
|
||||
showErrorAlert(stringMessages.importNoDataReturned());
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
return;
|
||||
}
|
||||
JSONArray leaderboardGroups = JSONParser.parseStrict(body).isArray();
|
||||
leaderboardgroupListBox.setVisibleItemCount(leaderboardGroups.size());
|
||||
List<String> toSort = new ArrayList<String>();
|
||||
for (int i = 0; i < leaderboardGroups.size(); i++) {
|
||||
JSONString leaderboardGroupName = leaderboardGroups.get(i).isString();
|
||||
leaderboardgroupListBox.addItem(leaderboardGroupName.stringValue());
|
||||
toSort.add(leaderboardGroups.get(i).isString().stringValue());
|
||||
}
|
||||
if (leaderboardGroups.size() > 1) {
|
||||
importLeaderboardGroupsButton.setEnabled(true);
|
||||
} else {
|
||||
importLeaderboardGroupsButton.setEnabled(false);
|
||||
Collections.sort(toSort);
|
||||
allLeaderboardGroupNames = toSort;
|
||||
leaderboardgroupListBox.setVisibleItemCount(leaderboardGroups.size());
|
||||
for (String lgName : toSort) {
|
||||
leaderboardgroupListBox.addItem(lgName);
|
||||
}
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Request request, Throwable exception) {
|
||||
showErrorAlert(stringMessages.importServerError());
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
});
|
||||
try {
|
||||
getLgsRequestBuilder.send();
|
||||
} catch (RequestException e) {
|
||||
showErrorAlert(stringMessages.importServerError());
|
||||
changeAllButtonState(true);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,8 +290,16 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
|
||||
private void addContentToLeftPanel(VerticalPanel contentPanel) {
|
||||
contentPanel.add(new Label(stringMessages.importLeaderboardGroups()));
|
||||
|
||||
HorizontalPanel filterPanel = new HorizontalPanel();
|
||||
filterPanel.add(new Label(stringMessages.filterName() + ":"));
|
||||
TextBox filterBox = new TextBox();
|
||||
setFilterHandler(filterBox);
|
||||
filterPanel.add(filterBox);
|
||||
contentPanel.add(filterPanel);
|
||||
|
||||
leaderboardgroupListBox = new ListBox(true);
|
||||
addSelectionChangedListener();
|
||||
contentPanel.add(leaderboardgroupListBox);
|
||||
|
||||
overrideSwitch = new CheckBox(stringMessages.importOverrideSwitchLabel());
|
||||
@@ -279,4 +311,48 @@ public class MasterDataImportPanel extends VerticalPanel {
|
||||
contentPanel.add(importLeaderboardGroupsButton);
|
||||
}
|
||||
|
||||
private void addSelectionChangedListener() {
|
||||
leaderboardgroupListBox.addClickHandler(new ClickHandler() {
|
||||
|
||||
@Override
|
||||
public void onClick(ClickEvent event) {
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setFilterHandler(final TextBox filterBox) {
|
||||
filterBox.addKeyUpHandler(new KeyUpHandler() {
|
||||
|
||||
@Override
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
clearListBox();
|
||||
int visibleNameCount = 0;
|
||||
List<String> filterTexts = Arrays.asList(filterBox.getText().split(" "));
|
||||
for(String name : allLeaderboardGroupNames) {
|
||||
boolean containsAllFilterTexts = true;
|
||||
for (String filterText : filterTexts) {
|
||||
if (!name.toUpperCase().contains(filterText.toUpperCase())) {
|
||||
containsAllFilterTexts = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (containsAllFilterTexts) {
|
||||
leaderboardgroupListBox.addItem(name);
|
||||
visibleNameCount++;
|
||||
}
|
||||
}
|
||||
leaderboardgroupListBox.setVisibleItemCount(visibleNameCount);
|
||||
changeButtonStateAccordingToApplicationState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void clearListBox() {
|
||||
int itemCount = leaderboardgroupListBox.getItemCount();
|
||||
for (int i = itemCount - 1; i >= 0; i--) {
|
||||
leaderboardgroupListBox.removeItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+28
-25
@@ -9,11 +9,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gwt.cell.client.ClickableTextCell;
|
||||
import com.google.gwt.cell.client.FieldUpdater;
|
||||
import com.google.gwt.cell.client.SafeHtmlCell;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.BrowserEvents;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
@@ -38,8 +36,6 @@ import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
import com.google.gwt.view.client.CellPreviewEvent;
|
||||
import com.google.gwt.view.client.CellPreviewEvent.Handler;
|
||||
import com.google.gwt.view.client.ListDataProvider;
|
||||
import com.sap.sailing.domain.common.LeaderboardNameConstants;
|
||||
import com.sap.sailing.domain.common.NauticalSide;
|
||||
@@ -57,6 +53,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
|
||||
import com.sap.sailing.gwt.ui.client.Timer;
|
||||
import com.sap.sailing.gwt.ui.client.shared.components.Component;
|
||||
import com.sap.sailing.gwt.ui.client.shared.components.SettingsDialogComponent;
|
||||
import com.sap.sailing.gwt.ui.shared.ClickableSafeHtmlCell;
|
||||
import com.sap.sailing.gwt.ui.shared.CourseAreaDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.EventDTO;
|
||||
import com.sap.sailing.gwt.ui.shared.RaceGroupDTO;
|
||||
@@ -145,14 +142,6 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
|
||||
|
||||
regattaOverviewDataProvider = new ListDataProvider<RegattaOverviewEntryDTO>();
|
||||
regattaOverviewTable = createRegattaTable();
|
||||
regattaOverviewTable.addCellPreviewHandler(new Handler<RegattaOverviewEntryDTO>() {
|
||||
@Override
|
||||
public void onCellPreview(CellPreviewEvent<RegattaOverviewEntryDTO> event) {
|
||||
if (BrowserEvents.CLICK.equals(event.getNativeEvent().getType()) && entryClickedHandler != null){
|
||||
entryClickedHandler.onEntryClicked(event.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mainPanel.add(regattaOverviewTable);
|
||||
setWidget(mainPanel);
|
||||
@@ -379,13 +368,24 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
|
||||
|
||||
});
|
||||
|
||||
TextColumn<RegattaOverviewEntryDTO> raceStatusColumn = new TextColumn<RegattaOverviewEntryDTO>() {
|
||||
Column<RegattaOverviewEntryDTO, SafeHtml> raceStatusColumn = new Column<RegattaOverviewEntryDTO, SafeHtml>(new ClickableSafeHtmlCell()) {
|
||||
@Override
|
||||
public String getValue(RegattaOverviewEntryDTO entryDTO) {
|
||||
return flagInterpreter.getMeaningOfRaceStateAndFlags(entryDTO.raceInfo.lastStatus, entryDTO.raceInfo.lastUpperFlag,
|
||||
public SafeHtml getValue(final RegattaOverviewEntryDTO entryDTO) {
|
||||
String status = flagInterpreter.getMeaningOfRaceStateAndFlags(entryDTO.raceInfo.lastStatus, entryDTO.raceInfo.lastUpperFlag,
|
||||
entryDTO.raceInfo.lastLowerFlag, entryDTO.raceInfo.isLastFlagDisplayed);
|
||||
SafeHtmlBuilder sb = new SafeHtmlBuilder();
|
||||
sb.appendHtmlConstant("<a class=\"pointeredLink\">");
|
||||
sb.appendEscaped(status);
|
||||
sb.appendHtmlConstant("</a>");
|
||||
return sb.toSafeHtml();
|
||||
}
|
||||
};
|
||||
raceStatusColumn.setFieldUpdater(new FieldUpdater<RegattaOverviewEntryDTO, SafeHtml>() {
|
||||
@Override
|
||||
public void update(int index, RegattaOverviewEntryDTO object, SafeHtml value) {
|
||||
entryClickedHandler.onEntryClicked(object);
|
||||
}
|
||||
});
|
||||
raceStatusColumn.setSortable(true);
|
||||
regattaOverviewListHandler.setComparator(raceStatusColumn, new Comparator<RegattaOverviewEntryDTO>() {
|
||||
|
||||
@@ -397,29 +397,32 @@ public class RegattaRaceStatesComponent extends SimplePanel implements Component
|
||||
});
|
||||
raceStatusColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
|
||||
Column<RegattaOverviewEntryDTO, String> raceCourseColumn = new Column<RegattaOverviewEntryDTO, String>(new ClickableTextCell()) {
|
||||
Column<RegattaOverviewEntryDTO, SafeHtml> raceCourseColumn = new Column<RegattaOverviewEntryDTO, SafeHtml>(new ClickableSafeHtmlCell()) {
|
||||
@Override
|
||||
public String getValue(RegattaOverviewEntryDTO entryDTO) {
|
||||
String courseName = "-";
|
||||
public SafeHtml getValue(final RegattaOverviewEntryDTO entryDTO) {
|
||||
SafeHtmlBuilder sb = new SafeHtmlBuilder();
|
||||
if (entryDTO.raceInfo.lastCourseName != null) {
|
||||
courseName = entryDTO.raceInfo.lastCourseName;
|
||||
String courseName = entryDTO.raceInfo.lastCourseName;
|
||||
sb.appendHtmlConstant("<a class=\"pointeredLink\">");
|
||||
sb.appendEscaped(courseName);
|
||||
sb.appendHtmlConstant("</a>");
|
||||
return sb.toSafeHtml();
|
||||
} else {
|
||||
return sb.toSafeHtml();
|
||||
}
|
||||
return courseName;
|
||||
}
|
||||
};
|
||||
raceCourseColumn.setFieldUpdater(new FieldUpdater<RegattaOverviewEntryDTO, String>() {
|
||||
|
||||
raceCourseColumn.setFieldUpdater(new FieldUpdater<RegattaOverviewEntryDTO, SafeHtml>() {
|
||||
@Override
|
||||
public void update(int index, RegattaOverviewEntryDTO object, String value) {
|
||||
public void update(int index, RegattaOverviewEntryDTO object, SafeHtml value) {
|
||||
if (object.raceInfo.lastCourseDesign.waypoints.size() > 0) {
|
||||
DialogBox courseViewDialogBox = createCourseViewDialogBox(object.raceInfo);
|
||||
courseViewDialogBox.center();
|
||||
courseViewDialogBox.setGlassEnabled(true);
|
||||
courseViewDialogBox.setAnimationEnabled(true);
|
||||
courseViewDialogBox.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
raceCourseColumn.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
|
||||
|
||||
|
||||
+8
-4
@@ -94,12 +94,12 @@ import com.sap.sailing.domain.common.RegattaIdentifier;
|
||||
import com.sap.sailing.domain.common.RegattaName;
|
||||
import com.sap.sailing.domain.common.RegattaNameAndRaceName;
|
||||
import com.sap.sailing.domain.common.RegattaScoreCorrections;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.RegattaScoreCorrections.ScoreCorrectionForCompetitorInRace;
|
||||
import com.sap.sailing.domain.common.RegattaScoreCorrections.ScoreCorrectionsForRace;
|
||||
import com.sap.sailing.domain.common.ScoreCorrectionProvider;
|
||||
import com.sap.sailing.domain.common.ScoringSchemeType;
|
||||
import com.sap.sailing.domain.common.Speed;
|
||||
import com.sap.sailing.domain.common.SpeedWithBearing;
|
||||
import com.sap.sailing.domain.common.Tack;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.WindSource;
|
||||
@@ -811,10 +811,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
|
||||
logger.info("Loaded race " + record.getName() + " in " + record.getEventName() + " start:" + record.getRaceStartTime() + " trackingStart:" + record.getTrackingStartTime() + " trackingEnd:" + record.getTrackingEndTime());
|
||||
// note that the live URI may be null for races that were put into replay mode
|
||||
final String effectiveLiveURI;
|
||||
if (liveURI == null || liveURI.trim().length() == 0) {
|
||||
effectiveLiveURI = record.getLiveURI() == null ? null : record.getLiveURI().toString();
|
||||
if (!record.getRaceStatus().equals(TracTracConnectionConstants.REPLAY_STATUS)) {
|
||||
if (liveURI == null || liveURI.trim().length() == 0) {
|
||||
effectiveLiveURI = record.getLiveURI() == null ? null : record.getLiveURI().toString();
|
||||
} else {
|
||||
effectiveLiveURI = liveURI;
|
||||
}
|
||||
} else {
|
||||
effectiveLiveURI = liveURI;
|
||||
effectiveLiveURI = null;
|
||||
}
|
||||
final String effectiveStoredURI;
|
||||
if (storedURI == null || storedURI.trim().length() == 0) {
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.sap.sailing.gwt.ui.shared;
|
||||
|
||||
import com.google.gwt.cell.client.AbstractCell;
|
||||
import com.google.gwt.cell.client.ValueUpdater;
|
||||
import com.google.gwt.dom.client.Element;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.safehtml.shared.SafeHtml;
|
||||
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
|
||||
|
||||
/**
|
||||
* Cell that is clickable and renders its contents as HTML.
|
||||
* Especially useful if you want to render a ClickableTextCell
|
||||
* in a CellTable as an anchor.
|
||||
*
|
||||
* Use it like this:
|
||||
* <pre>
|
||||
* Column<RegattaOverviewEntryDTO, SafeHtml> raceStatusColumn = new Column<RegattaOverviewEntryDTO, SafeHtml>(new ClickableSafeHtmlCell()) {
|
||||
* @Override
|
||||
* public SafeHtml getValue(final RegattaOverviewEntryDTO entryDTO) {
|
||||
* String status = "my string";
|
||||
* SafeHtmlBuilder sb = new SafeHtmlBuilder();
|
||||
* sb.appendHtmlConstant("<a>");
|
||||
* sb.appendEscaped(status);
|
||||
* sb.appendHtmlConstant("</a>");
|
||||
* return sb.toSafeHtml();
|
||||
* }
|
||||
* };
|
||||
* </pre>
|
||||
*
|
||||
* @author Simon Pamies
|
||||
*/
|
||||
public class ClickableSafeHtmlCell extends AbstractCell<SafeHtml> {
|
||||
|
||||
public ClickableSafeHtmlCell() {
|
||||
super("click", "keydown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Context context, Element parent, SafeHtml value, NativeEvent event,
|
||||
ValueUpdater<SafeHtml> valueUpdater) {
|
||||
super.onBrowserEvent(context, parent, value, event, valueUpdater);
|
||||
if ("click".equals(event.getType())) {
|
||||
onEnterKeyDown(context, parent, value, event, valueUpdater);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onEnterKeyDown(Context context, Element parent, SafeHtml value,
|
||||
NativeEvent event, ValueUpdater<SafeHtml> valueUpdater) {
|
||||
if (valueUpdater != null) {
|
||||
valueUpdater.update(value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(Context context, SafeHtml value, SafeHtmlBuilder sb) {
|
||||
if (value != null) {
|
||||
sb.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-1
@@ -21,6 +21,7 @@ import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
@@ -58,7 +59,7 @@ public class StoreAndLoadRaceLogEventsTest extends AbstractMongoDBTest {
|
||||
@Before
|
||||
public void setUp() {
|
||||
logIdentifier = mock(RaceLogIdentifier.class);
|
||||
when(logIdentifier.getIdentifier()).thenReturn(UUID.randomUUID());
|
||||
when(logIdentifier.getIdentifier()).thenReturn(new Triple<String, String, String>("a", "b", UUID.randomUUID().toString()));
|
||||
}
|
||||
|
||||
public void assertBaseFields(RaceLogEvent expectedEvent, RaceLogEvent actualEvent) {
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
package com.sap.sailing.mongodb.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.mongodb.DBObject;
|
||||
import com.mongodb.MongoException;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.Fleet;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.racelog.Flags;
|
||||
import com.sap.sailing.domain.persistence.MongoFactory;
|
||||
import com.sap.sailing.domain.persistence.impl.DomainObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.persistence.impl.MongoObjectFactoryImpl;
|
||||
import com.sap.sailing.domain.racelog.RaceLog;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
|
||||
import com.sap.sailing.domain.racelog.RaceLogFlagEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifier;
|
||||
import com.sap.sailing.domain.racelog.RaceLogIdentifierTemplate;
|
||||
import com.sap.sailing.domain.racelog.impl.RaceLogIdentifierImpl;
|
||||
|
||||
public class StoreAndLoadRaceLogsTest extends AbstractMongoDBTest {
|
||||
|
||||
protected MongoObjectFactoryImpl mongoFactory = (MongoObjectFactoryImpl) MongoFactory.INSTANCE
|
||||
.getMongoObjectFactory(getMongoService());
|
||||
protected DomainObjectFactoryImpl domainFactory = (DomainObjectFactoryImpl) MongoFactory.INSTANCE
|
||||
.getDomainObjectFactory(getMongoService());
|
||||
protected RaceLogEventFactory eventFactory = RaceLogEventFactory.INSTANCE;
|
||||
|
||||
public StoreAndLoadRaceLogsTest() throws UnknownHostException, MongoException {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreAndLoadSingleRaceLog() {
|
||||
RaceLogIdentifier identifier = createIdentifier("A.A", "B.B", "C.C");
|
||||
|
||||
RaceLogFlagEvent event1 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
RaceLogFlagEvent event2 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
DBObject dbEvent1 = mongoFactory.storeRaceLogEntry(identifier, event1);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent1);
|
||||
DBObject dbEvent2 = mongoFactory.storeRaceLogEntry(identifier, event2);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent2);
|
||||
|
||||
RaceLog raceLog = domainFactory.loadRaceLog(identifier);
|
||||
try {
|
||||
raceLog.lockForRead();
|
||||
assertEquals(2, Util.size(raceLog.getRawFixes()));
|
||||
} finally {
|
||||
raceLog.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreAndLoadCollidingRaceLogs() {
|
||||
// RaceLog A.A B.B C.C
|
||||
RaceLogIdentifier identifier = createIdentifier("A.A", "B.B", "C.C");
|
||||
|
||||
RaceLogFlagEvent event1 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
RaceLogFlagEvent event2 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
DBObject dbEvent1 = mongoFactory.storeRaceLogEntry(identifier, event1);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent1);
|
||||
DBObject dbEvent2 = mongoFactory.storeRaceLogEntry(identifier, event2);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent2);
|
||||
|
||||
// RaceLog A.A.B B.C C
|
||||
RaceLogIdentifier collidingIdentifier = createIdentifier("A.A.B", "B.C", "C");
|
||||
|
||||
RaceLogFlagEvent event3 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
DBObject dbEvent3 = mongoFactory.storeRaceLogEntry(collidingIdentifier, event3);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent3);
|
||||
|
||||
RaceLog raceLog = domainFactory.loadRaceLog(identifier);
|
||||
try {
|
||||
raceLog.lockForRead();
|
||||
assertEquals(2, Util.size(raceLog.getRawFixes()));
|
||||
} finally {
|
||||
raceLog.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testdLoadObsoleteIdentifier() {
|
||||
// Identifier is A.A B.B C.C
|
||||
|
||||
DBObject dbEvent1 = (DBObject) com.mongodb.util.JSON.parse(createOldFormatRaceLogEventJson(UUID.randomUUID()));
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent1);
|
||||
DBObject dbEvent2 = (DBObject) com.mongodb.util.JSON.parse(createOldFormatRaceLogEventJson(UUID.randomUUID()));
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent2);
|
||||
|
||||
RaceLog raceLog = domainFactory.loadRaceLog(createIdentifier("A.A", "B.B", "C.C"));
|
||||
try {
|
||||
raceLog.lockForRead();
|
||||
assertEquals(2, Util.size(raceLog.getRawFixes()));
|
||||
} finally {
|
||||
raceLog.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testdLoadObsoleteAndNewIdentifier() {
|
||||
// event1 stored with obsolete identifier
|
||||
DBObject dbEvent1 = (DBObject) com.mongodb.util.JSON.parse(createOldFormatRaceLogEventJson(UUID.randomUUID()));
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent1);
|
||||
|
||||
// event2 stored with new identifier
|
||||
RaceLogIdentifier identifier = createIdentifier("A.A", "B.B", "C.C");
|
||||
RaceLogFlagEvent event2 = createRaceLogFlagEvent(UUID.randomUUID());
|
||||
DBObject dbEvent2 = mongoFactory.storeRaceLogEntry(identifier, event2);
|
||||
mongoFactory.getRaceLogCollection().insert(dbEvent2);
|
||||
|
||||
RaceLog raceLog = domainFactory.loadRaceLog(identifier);
|
||||
try {
|
||||
raceLog.lockForRead();
|
||||
assertEquals(2, Util.size(raceLog.getRawFixes()));
|
||||
} finally {
|
||||
raceLog.unlockAfterRead();
|
||||
}
|
||||
}
|
||||
|
||||
private String createOldFormatRaceLogEventJson(Serializable id) {
|
||||
return "{ \"_id\" : { \"$oid\" : \""+ new ObjectId().toStringMongod() + "\"} , \"RACE_LOG_IDENTIFIER\" : \"A%2EA%2EB%2EB%2EC%2EC\" , \"RACE_LOG_EVENT\" : "
|
||||
+ "{ \"TIME_AS_MILLIS\" : 42 , \"RACE_LOG_EVENT_CREATED_AT\" : 1376058090051 , \"RACE_LOG_EVENT_ID\" : { \"$uuid\" : \"" + id.toString() + "\"} , "
|
||||
+ "\"RACE_LOG_EVENT_PASS_ID\" : 42 , \"RACE_LOG_EVENT_INVOLVED_BOATS\" : [ ] , \"RACE_LOG_EVENT_CLASS\" : \"RaceLogFlagEvent\" , \"RACE_LOG_EVENT_FLAG_UPPER\" : \"ALPHA\" , "
|
||||
+ "\"RACE_LOG_EVENT_FLAG_LOWER\" : \"BRAVO\" , \"RACE_LOG_EVENT_FLAG_DISPLAYED\" : \"true\"}}";
|
||||
}
|
||||
|
||||
private RaceLogIdentifier createIdentifier(String groupName, String raceColumnName, String fleetName) {
|
||||
RaceLogIdentifierTemplate template = mock(RaceLogIdentifierTemplate.class);
|
||||
when(template.getParentObjectName()).thenReturn(groupName);
|
||||
when(template.getRaceColumnName()).thenReturn(raceColumnName);
|
||||
Fleet fleet = mock(Fleet.class);
|
||||
when(fleet.getName()).thenReturn(fleetName);
|
||||
return new RaceLogIdentifierImpl(template, raceColumnName, fleet);
|
||||
}
|
||||
|
||||
private RaceLogFlagEvent createRaceLogFlagEvent(Serializable id) {
|
||||
return eventFactory.createFlagEvent(new MillisecondsTimePoint(42), id, Collections.<Competitor> emptyList(),
|
||||
42, Flags.ALPHA, Flags.BRAVO, true);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -28,7 +28,7 @@ import com.sap.sailing.domain.racelog.RaceLogCourseDesignChangedEvent;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEventFactory;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.ControlPointDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseDataDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.GateDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.MarkDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.WaypointDeserializer;
|
||||
@@ -61,7 +61,7 @@ public class RaceLogCourseDesignChangedEventSerializerTest {
|
||||
new CourseBaseJsonSerializer(new WaypointJsonSerializer(new ControlPointJsonSerializer(
|
||||
new MarkJsonSerializer(), new GateJsonSerializer(new MarkJsonSerializer())))));
|
||||
deserializer = new RaceLogCourseDesignChangedEventDeserializer(new CompetitorDeserializer(factory),
|
||||
new CourseDataDeserializer(new WaypointDeserializer(new ControlPointDeserializer(new MarkDeserializer(
|
||||
new CourseBaseDeserializer(new WaypointDeserializer(new ControlPointDeserializer(new MarkDeserializer(
|
||||
factory), new GateDeserializer(factory, new MarkDeserializer(factory))))));
|
||||
now = MillisecondsTimePoint.now();
|
||||
|
||||
|
||||
+46
-46
@@ -1,47 +1,47 @@
|
||||
package com.sap.sailing.server.gateway.deserialization.coursedata.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
|
||||
|
||||
/**
|
||||
* Deserializer for CourseData.
|
||||
*/
|
||||
public class CourseDataDeserializer implements JsonDeserializer<CourseBase> {
|
||||
|
||||
private final WaypointDeserializer waypointDeserializer;
|
||||
|
||||
public CourseDataDeserializer(WaypointDeserializer waypointDeserializer) {
|
||||
this.waypointDeserializer = waypointDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseBase deserialize(JSONObject object) throws JsonDeserializationException {
|
||||
String courseName = (String) object.get(CourseBaseJsonSerializer.FIELD_NAME);
|
||||
JSONArray jsonWaypoints = (JSONArray) object.get(CourseBaseJsonSerializer.FIELD_WAYPOINTS);
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
|
||||
for (Object waypointObject : jsonWaypoints) {
|
||||
JSONObject jsonWaypoint = (JSONObject) waypointObject;
|
||||
Waypoint waypoint = waypointDeserializer.deserialize(jsonWaypoint);
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
|
||||
CourseBase courseBase = new CourseDataImpl(courseName);
|
||||
for (int i = 0; i < waypoints.size(); i++) {
|
||||
courseBase.addWaypoint(i, waypoints.get(i));
|
||||
}
|
||||
|
||||
return courseBase;
|
||||
}
|
||||
|
||||
package com.sap.sailing.server.gateway.deserialization.coursedata.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.base.Waypoint;
|
||||
import com.sap.sailing.domain.base.impl.CourseDataImpl;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.coursedata.impl.CourseBaseJsonSerializer;
|
||||
|
||||
/**
|
||||
* Deserializer for CourseData.
|
||||
*/
|
||||
public class CourseBaseDeserializer implements JsonDeserializer<CourseBase> {
|
||||
|
||||
private final WaypointDeserializer waypointDeserializer;
|
||||
|
||||
public CourseBaseDeserializer(WaypointDeserializer waypointDeserializer) {
|
||||
this.waypointDeserializer = waypointDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseBase deserialize(JSONObject object) throws JsonDeserializationException {
|
||||
String courseName = (String) object.get(CourseBaseJsonSerializer.FIELD_NAME);
|
||||
JSONArray jsonWaypoints = (JSONArray) object.get(CourseBaseJsonSerializer.FIELD_WAYPOINTS);
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
|
||||
for (Object waypointObject : jsonWaypoints) {
|
||||
JSONObject jsonWaypoint = (JSONObject) waypointObject;
|
||||
Waypoint waypoint = waypointDeserializer.deserialize(jsonWaypoint);
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
|
||||
CourseBase courseBase = new CourseDataImpl(courseName);
|
||||
for (int i = 0; i < waypoints.size(); i++) {
|
||||
courseBase.addWaypoint(i, waypoints.get(i));
|
||||
}
|
||||
|
||||
return courseBase;
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -17,8 +17,8 @@ public class Helpers {
|
||||
if (object instanceof JSONArray) {
|
||||
return (JSONArray) object;
|
||||
}
|
||||
throw new JsonDeserializationException(String.format("Expected a JSONArray, got %s.", object.getClass()
|
||||
.getName()));
|
||||
throw new JsonDeserializationException(String.format("Expected a JSONArray, got %s.", object != null ? object.getClass()
|
||||
.getName() : ""));
|
||||
}
|
||||
|
||||
public static JSONObject toJSONObjectSafe(Object object) throws JsonDeserializationException {
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ public class WindJsonDeserializer implements JsonDeserializer<Wind> {
|
||||
direction = (Number) object.get("bearing");
|
||||
}
|
||||
Number speedInKnots = (Number) object.get(WindJsonSerializer.FIELD_SPEED_IN_KNOTS);
|
||||
Bearing degreeBearing = new DegreeBearingImpl(direction.doubleValue());
|
||||
Bearing degreeBearing = new DegreeBearingImpl(direction.doubleValue());
|
||||
SpeedWithBearing speedBearing = new KnotSpeedWithBearingImpl(speedInKnots.doubleValue(), degreeBearing);
|
||||
Wind wind = new WindImpl(position, new MillisecondsTimePoint(timeStamp.longValue()), speedBearing);
|
||||
return wind;
|
||||
|
||||
+3
-3
@@ -11,14 +11,14 @@ import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseDataDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer;
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogCourseDesignChangedEventSerializer;
|
||||
|
||||
public class RaceLogCourseDesignChangedEventDeserializer extends BaseRaceLogEventDeserializer {
|
||||
|
||||
private final CourseDataDeserializer courseDataDeserializer;
|
||||
private final CourseBaseDeserializer courseDataDeserializer;
|
||||
|
||||
public RaceLogCourseDesignChangedEventDeserializer(JsonDeserializer<Competitor> competitorDeserializer, CourseDataDeserializer courseDataDeserializer) {
|
||||
public RaceLogCourseDesignChangedEventDeserializer(JsonDeserializer<Competitor> competitorDeserializer, CourseBaseDeserializer courseDataDeserializer) {
|
||||
super(competitorDeserializer);
|
||||
this.courseDataDeserializer = courseDataDeserializer;
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ import com.sap.sailing.domain.racelog.RaceLogEvent;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializationException;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.ControlPointDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseDataDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.GateDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.MarkDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.WaypointDeserializer;
|
||||
@@ -40,7 +40,7 @@ public class RaceLogEventDeserializer implements JsonDeserializer<RaceLogEvent>
|
||||
new RaceLogRaceStatusEventDeserializer(competitorDeserializer),
|
||||
new RaceLogCourseAreaChangedEventDeserializer(competitorDeserializer),
|
||||
new RaceLogCourseDesignChangedEventDeserializer(competitorDeserializer,
|
||||
new CourseDataDeserializer(
|
||||
new CourseBaseDeserializer(
|
||||
new WaypointDeserializer(
|
||||
new ControlPointDeserializer(
|
||||
new MarkDeserializer(domainFactory), new GateDeserializer(domainFactory, new MarkDeserializer(domainFactory)))))),
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ public class RaceLogSerializer implements JsonSerializer<RaceLog> {
|
||||
events.add(itemSerializer.serialize(event));
|
||||
}
|
||||
result.put(FIELD_EVENTS, events);
|
||||
result.put(FIELD_RACELOG_IDENTIFIER, object.getId());
|
||||
result.put(FIELD_RACELOG_IDENTIFIER, object.getId().toString());
|
||||
} finally {
|
||||
object.unlockAfterRead();
|
||||
}
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ import com.sap.sailing.server.RacingEventService;
|
||||
|
||||
public abstract class AbstractSeriesOperation<ResultType> extends AbstractRacingEventServiceOperation<ResultType> {
|
||||
private static final long serialVersionUID = -7786133902346491275L;
|
||||
private Logger logger = Logger.getLogger(AbstractSeriesOperation.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(AbstractSeriesOperation.class.getName());
|
||||
private final RegattaIdentifier regattaIdentifier;
|
||||
private final String seriesName;
|
||||
|
||||
|
||||
+6
@@ -500,4 +500,10 @@ public class DummyTrackedRace implements TrackedRace {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TimePoint getStartTimeReceived() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -19,25 +19,12 @@
|
||||
<div id='mainContent'>
|
||||
<h1 id='pageHeadline'>Extreme Sailing Series 2013</h1>
|
||||
<h2>Next Event</h2>
|
||||
<p>
|
||||
Act 5 - Porto, Portugal
|
||||
</p>
|
||||
<p>
|
||||
July 25th - 28th
|
||||
</p>
|
||||
<!--<p>
|
||||
Act 6 - Cardiff, England
|
||||
</p>
|
||||
<p>
|
||||
August 22th - 25th
|
||||
</p>
|
||||
<p>
|
||||
Act 7 - Nice, France
|
||||
</p>
|
||||
<p>
|
||||
October 3th - 6th
|
||||
September 2th - 6th
|
||||
</p>
|
||||
-->
|
||||
</div>
|
||||
<div id='navigation'>
|
||||
<a class='navButton overall' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=Extreme%20Sailing%20Series%202013%20Overall&showRaceDetails=false&refreshIntervalMillis=10000&displayName=Overall%20Standings&leaderboardGroupName=Extreme%20Sailing%20Series%202013&root=leaderboardGroupPanel'>
|
||||
@@ -48,10 +35,10 @@
|
||||
</a>
|
||||
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Nice%20%28Extreme40%29&displayName=Nice&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
|
||||
Nice
|
||||
</a>
|
||||
</a>-->
|
||||
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Cardiff%20%28Extreme40%29&displayName=Cardiff&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
|
||||
Cardiff
|
||||
</a>-->
|
||||
</a>
|
||||
<a class='navButton event' href='http://ess40-2013.sapsailing.com/gwt/Leaderboard.html?name=ESS%202013%20Porto%20%28Extreme40%29&displayName=Porto&delayToLiveMillis=3000&refreshIntervalMillis=10000&legDetail=AVERAGE_SPEED_OVER_GROUND_IN_KNOTS&legDetail=DISTANCE_TRAVELED&legDetail=RANK_GAIN&raceDetail=DISPLAY_LEGS&maneuverDetail=TACK&maneuverDetail=JIBE&maneuverDetail=PENALTY_CIRCLE&lastN=3'>
|
||||
Porto
|
||||
</a>
|
||||
|
||||
@@ -33,22 +33,64 @@
|
||||
|
||||
<div class='innerContent'>
|
||||
<!-- Uncomment the following in case there are events in live state and add the timeBar plus raceSection -->
|
||||
<!--
|
||||
<h2 class='articleSubheadline'>Live</h2>
|
||||
|
||||
<!--<h2 class='articleSubheadline'>Live</h2>
|
||||
<br/>
|
||||
-->
|
||||
<div class="timeBar">
|
||||
</div>-->
|
||||
|
||||
|
||||
<!-- Uncomment the following in case there are upcoming and add the timeBar plus raceSection -->
|
||||
<!--
|
||||
<h2 class='articleSubheadline'>Upcoming</h2>
|
||||
<div class="timeBar">
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
Sep 2 - 7
|
||||
</h5>
|
||||
<div class='raceTimepoint'></div>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
|
||||
<ul class='racePanel'>
|
||||
<li class='raceName'>
|
||||
Extreme Sailing Series 2013
|
||||
</li>
|
||||
<li class='raceLocation'>
|
||||
Nice, France
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
<div class='raceDescription'>
|
||||
<p>Extreme Sailing Series 2013</p>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
|
||||
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
-->
|
||||
|
||||
<h2 class='articleSubheadline'>2013</h2>
|
||||
<div class="timeBar">
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
Aug 23 - 26
|
||||
</h5>
|
||||
<div class='raceTimepoint'></div>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
|
||||
<ul class='racePanel'>
|
||||
<li class='raceName'>
|
||||
Extreme Sailing Series 2013
|
||||
</li>
|
||||
<li class='raceLocation'>
|
||||
Cardiff, Wales
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
<div class='raceDescription'>
|
||||
<p>Extreme Sailing Series 2013</p>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
|
||||
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
July 19 - 28
|
||||
@@ -111,28 +153,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
July 25 - 28
|
||||
</h5>
|
||||
<div class='raceTimepoint'></div>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>
|
||||
<ul class='racePanel'>
|
||||
<li class='raceName'>
|
||||
Extreme Sailing Series 2013
|
||||
</li>
|
||||
<li class='raceLocation'>
|
||||
Porto, Portugal
|
||||
</li>
|
||||
</ul>
|
||||
</a>
|
||||
<div class='raceDescription'>
|
||||
<p>Extreme Sailing Series 2013</p>
|
||||
<a href='http://ess40-2013.sapsailing.com' target='_blank'>SAP Sailing Analytics</a><br/>
|
||||
<a href='http://www.extremesailingseries.com' target='_blank'>Official website</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='raceSection'>
|
||||
<h5 class='date'>
|
||||
May 1 - 5
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
monitor.interval = 30000
|
||||
|
||||
# time the monitoring server waits before polling, in milliseconds
|
||||
monitor.gracetime = 10000
|
||||
monitor.gracetime = 60000
|
||||
|
||||
# time between interval checks, in milliseconds
|
||||
monitor.pause = 1000
|
||||
|
||||
@@ -45,7 +45,8 @@
|
||||
<activity
|
||||
android:name=".ui.activities.LoginActivity"
|
||||
android:screenOrientation="landscape"
|
||||
android:launchMode="singleTop" >
|
||||
android:launchMode="standard"
|
||||
android:finishOnTaskLaunch="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
Regular → Executable
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
Regular → Executable
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
@@ -2,10 +2,15 @@
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<PreferenceCategory android:title="@string/settings_category_general" >
|
||||
|
||||
<Preference
|
||||
android:key="languagePref"
|
||||
android:title="@string/settings_general_language_header"
|
||||
android:summary="@string/settings_general_language_description"/>
|
||||
<EditTextPreference
|
||||
android:key="courseAreasPref"
|
||||
android:name="@string/settings_general_manageareas_header"
|
||||
android:defaultValue="@string/settings_general_manageareas_default"
|
||||
android:key="courseAreasPref"
|
||||
android:summary="@string/settings_general_manageareas_description"
|
||||
android:title="@string/settings_general_manageareas_header" />
|
||||
</PreferenceCategory>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<TextView android:id="@+id/Welter.Cell.OneRowNoImage.txtTitle"
|
||||
android:padding="5dp"
|
||||
android:textColor="@drawable/text_selector"
|
||||
android:textSize="10pt"
|
||||
android:textSize="@dimen/Welter.BigTitleTextSize"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true">
|
||||
</TextView>
|
||||
|
||||
+2
-2
@@ -15,14 +15,14 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:textSize="10pt" android:alpha="1" >
|
||||
android:textSize="@dimen/Welter.RegularTextSize" android:alpha="1" >
|
||||
</TextView>
|
||||
|
||||
<ImageButton android:id="@+id/Welter.Cell.OneRowNoImageLabel.btnJury"
|
||||
android:src="@drawable/bravo_mini"
|
||||
android:padding="5dp"
|
||||
android:textColor="@color/welter_red"
|
||||
android:textSize="10pt"
|
||||
android:textSize="@dimen/Welter.RegularTextSize"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/flag_jury"
|
||||
android:layout_centerVertical="true" android:layout_alignParentRight="true" />
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Title of the first line"
|
||||
android:text="@string/empty"
|
||||
android:textColor="@drawable/text_selector"
|
||||
android:textSize="9pt" >
|
||||
android:textSize="@dimen/Welter.RegularTextSize" >
|
||||
</TextView>
|
||||
|
||||
<TextView
|
||||
@@ -30,8 +30,8 @@
|
||||
android:paddingLeft="6pt"
|
||||
android:layout_below="@+id/Welter.Cell.TwoRowNoImage.lineOne"
|
||||
android:layout_centerVertical="true"
|
||||
android:text="Title of the second line"
|
||||
android:textSize="8pt" >
|
||||
android:text="@string/empty"
|
||||
android:textSize="@dimen/Welter.ProgressTextSize" >
|
||||
</TextView>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -2,139 +2,117 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/background"
|
||||
android:descendantFocusability="beforeDescendants"
|
||||
android:focusableInTouchMode="true"
|
||||
android:background="@drawable/background" >
|
||||
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="18dp"
|
||||
android:background="@color/welter_extralight_gray_transparent">
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="18dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_wind_direction"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<com.sap.sailing.racecommittee.app.ui.views.CompassView
|
||||
android:id="@+id/compassView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
</com.sap.sailing.racecommittee.app.ui.views.CompassView>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_wind_speed"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekbar_wind_speed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:progress="100"
|
||||
android:max="250"
|
||||
android:padding="18dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="2dp"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_margin="18dp"
|
||||
android:background="@color/welter_deep_gray">
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="18dp"
|
||||
android:layout_marginRight="26dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="9dp"
|
||||
android:text="@string/check_all_data"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/wind_direction_degrees" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextWindDirection"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal"
|
||||
android:hint="@string/in_degrees"
|
||||
android:minWidth="200dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/wind_speed_knots" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextWindSpeed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:inputType="numberDecimal"
|
||||
android:hint="@string/in_knots"
|
||||
android:minWidth="200dp">
|
||||
</EditText>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/your_position" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_position_lat"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/latitude"
|
||||
android:minWidth="200dp"
|
||||
android:clickable="false"
|
||||
android:cursorVisible="false"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false">
|
||||
</EditText>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_position_lon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/longitude"
|
||||
android:minWidth="200dp"
|
||||
android:clickable="false"
|
||||
android:cursorVisible="false"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false">
|
||||
</EditText>
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_wind_send"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/store_wind"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
android:background="@color/welter_extralight_gray_transparent"
|
||||
android:orientation="horizontal" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="18dp"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_wind_direction"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/wind_direction_degrees" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextWindDirection"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/in_degrees"
|
||||
android:inputType="numberDecimal"
|
||||
android:minWidth="200dp"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<com.sap.sailing.racecommittee.app.ui.views.CompassView
|
||||
android:id="@+id/compassView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" >
|
||||
</com.sap.sailing.racecommittee.app.ui.views.CompassView>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="2dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="18dp"
|
||||
android:background="@color/welter_deep_gray"
|
||||
android:orientation="vertical" >
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="18dp"
|
||||
android:layout_marginRight="26dp"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/enter_wind_speed"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/wind_speed_knots" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/editTextWindSpeed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/in_knots"
|
||||
android:inputType="numberDecimal"
|
||||
android:minWidth="200dp"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/seekbar_wind_speed"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:max="500"
|
||||
android:padding="10dp"
|
||||
android:progress="100" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="9dp"
|
||||
android:text="@string/check_all_data"
|
||||
android:textAppearance="@style/TextAppearance.Welter.BigTitleLabel" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textWaitingForGPS"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/waiting_for_gps"
|
||||
android:textAppearance="@style/TextAppearance.Welter.TitleLabel"
|
||||
android:textColor="@color/welter_red"
|
||||
android:textSize="24sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_wind_send"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:text="@string/store_wind" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -6,7 +6,9 @@
|
||||
<string name="course_design_number_waypoints">Kurs hat %s Wegpunkte</string>
|
||||
<string name="choose_running_course">Wähle Kurs aus</string>
|
||||
<string name="service_info">SAP Race Committee Service</string>
|
||||
<string name="service_title">Verwaltet alle Rennen auf gewählter Rennbahn.</string>
|
||||
<string name="service_text_no_races">Warte auf Rennen…</string>
|
||||
<string name="service_text_num_races">Aktuell %d Rennen verwaltet.</string>
|
||||
|
||||
<string name="app_name">SAP Race Committee Cockpit</string>
|
||||
<string name="set_time">Start</string>
|
||||
<string name="reset_time">Startzeit ändern</string>
|
||||
@@ -179,6 +181,7 @@
|
||||
<string name="wind_speed_direction_not_a_valid_number">Die Windgeschwindigkeit oder -richtung ist keine valide Zahl. Bitte korrigieren Sie den Wert.</string>
|
||||
<string name="wind_location_or_fields_not_valid">Die eingegebene Position, Windgeschwindigkeit oder -richtung ist leer. Bitte korrigieren Sie die Werte.</string>
|
||||
<string name="your_position">Aktuelle Position</string>
|
||||
<string name="waiting_for_gps">Warte auf GPS Signal…</string>
|
||||
<string name="store_wind_entry">4. Windeingaben speichern</string>
|
||||
<string name="store_wind">Windeingaben speichern</string>
|
||||
|
||||
@@ -186,6 +189,8 @@
|
||||
<string name="settings_category_general">Allgemeine Einstellungen</string>
|
||||
<string name="settings_general_manageareas_header">Verwaltete Rennbahnen</string>
|
||||
<string name="settings_general_manageareas_description">Verwaltete Rennbahnen einstellen (Komma-getrennt)</string>
|
||||
<string name="settings_general_language_header">Sprache auswählen</string>
|
||||
<string name="settings_general_language_description">Sprache auswählen. Eventuell muss die App neugestartet werden.</string>
|
||||
|
||||
<string name="settings_category_race">Renneinstellungen</string>
|
||||
<string name="override_default_start_procedure_type_header">Standard Startprozedur überschreiben</string>
|
||||
@@ -196,7 +201,7 @@
|
||||
<string name="settings_time_frame_description">Zeit in Minuten einstellen, welches Zeitlimit angibt</string>
|
||||
|
||||
<string name="settings_category_advanced">Erweiterte Einstellungen</string>
|
||||
<string name="settings_advanced_service_header">Wählen sie die Server URL aus.</string>
|
||||
<string name="settings_advanced_service_header">Wählen sie die Server URL aus. Nach Änderung muss die Option \'Neuladen\' gewählt werden.</string>
|
||||
<string name="settings_advanced_service_description">Webservice URL einstellen.</string>
|
||||
<string name="settings_advanced_mail_description">Empfänger für Bilder der Ergebnislisten.</string>
|
||||
<string name="settings_advanced_mail_header">Empfänger Ergebnislisten</string>
|
||||
@@ -233,4 +238,8 @@
|
||||
<string name="number">Nummer</string>
|
||||
<string name="snap">Fotos schießen</string>
|
||||
|
||||
<string name="logout_dialog_title">Möchten Sie sich abmelden?</string>
|
||||
<string name="logout_dialog_message">Wenn Sie sich abmelden wird kein Rennen mehr verwaltet.</string>
|
||||
<string name="logout">Abmelden</string>
|
||||
|
||||
</resources>
|
||||
@@ -6,7 +6,9 @@
|
||||
<string name="course_design_number_waypoints">Course has %s waypoints</string>
|
||||
<string name="choose_running_course">Choose running course</string>
|
||||
<string name="service_info">SAP Race Committee Service</string>
|
||||
<string name="service_title">Monitoring all races on selected event course.</string>
|
||||
<string name="service_text_no_races">Waiting for races to monitor…</string>
|
||||
<string name="service_text_num_races">Currently monitoring %d races.</string>
|
||||
|
||||
<string name="app_name">SAP Race Committee Cockpit</string>
|
||||
<string name="set_time">Start</string>
|
||||
<string name="reset_time">Restart</string>
|
||||
@@ -167,7 +169,7 @@
|
||||
|
||||
<string name="results_mail_subject">[Race Committee] %s</string>
|
||||
<string name="results_mail_body">Results for race %s are attached.</string>
|
||||
<string name="wind_direction_degrees">Wind direction (degrees)</string>
|
||||
<string name="wind_direction_degrees">Wind direction from (degrees)</string>
|
||||
<string name="wind_speed_knots">Wind speed (knots)</string>
|
||||
<string name="enter_wind_direction">1. Enter the wind direction</string>
|
||||
<string name="enter_wind_speed">2. Enter the wind speed</string>
|
||||
@@ -178,7 +180,7 @@
|
||||
<string name="longitude">Longitude</string>
|
||||
<string name="wind_speed_direction_not_a_valid_number">The wind speed or direction is not a valid number. Please correct the value.</string>
|
||||
<string name="wind_location_or_fields_not_valid">The entered location, wind speed or direction is empty. Please correct the values.</string>
|
||||
<string name="your_position">Your position</string>
|
||||
<string name="waiting_for_gps">Waiting for GPS Signal…</string>
|
||||
<string name="store_wind_entry">4. Store wind entry</string>
|
||||
<string name="store_wind">Store wind</string>
|
||||
|
||||
@@ -186,6 +188,8 @@
|
||||
<string name="settings_category_general">General Settings</string>
|
||||
<string name="settings_general_manageareas_header">Managed Course Areas</string>
|
||||
<string name="settings_general_manageareas_description">Enter course area names managed by you (comma-separated)</string>
|
||||
<string name="settings_general_language_header">Select Language</string>
|
||||
<string name="settings_general_language_description">Select the language. You might need to restart the app to have changes applied.</string>
|
||||
|
||||
<string name="settings_category_race">Race Settings</string>
|
||||
<string name="override_default_start_procedure_type_header">Override default start procedure type</string>
|
||||
@@ -262,4 +266,8 @@
|
||||
<string name="confirm_positionings">Confirm positionings</string>
|
||||
<string name="snap">Snap</string>
|
||||
|
||||
<string name="logout_dialog_title">Are you sure want to logout?</string>
|
||||
<string name="logout_dialog_message">Logging out stops automatic monitoring for all races.</string>
|
||||
<string name="logout">Logout</string>
|
||||
|
||||
</resources>
|
||||
+1
@@ -6,6 +6,7 @@ import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.SetStartTimeRaceF
|
||||
public class AppConstants {
|
||||
|
||||
public static final boolean IS_DATA_OFFLINE = false;
|
||||
public static final boolean ENABLE_LIFECYCLE_LOGGING = false;
|
||||
|
||||
// Intent extra fields
|
||||
public final static String COURSE_AREA_UUID_KEY = "courseUuid";
|
||||
|
||||
+2
-2
@@ -109,13 +109,13 @@ public class AppPreferences {
|
||||
return Arrays.asList(managedCourseAreas);
|
||||
}
|
||||
|
||||
public static double getWindBearing(Context context) {
|
||||
public static double getWindBearingFromDirection(Context context) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
long windBearingAsLong = sp.getLong(PREFERENCE_WIND_BEARING, 0);
|
||||
return Double.longBitsToDouble(windBearingAsLong);
|
||||
}
|
||||
|
||||
public static void setWindBearing(Context context, double enteredWindBearing) {
|
||||
public static void setWindBearingFromDirection(Context context, double enteredWindBearing) {
|
||||
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
long windBearingAsLong = Double.doubleToLongBits(enteredWindBearing);
|
||||
sp.edit().putLong(PREFERENCE_WIND_BEARING, windBearingAsLong).apply();
|
||||
|
||||
+6
-5
@@ -4,13 +4,14 @@ import java.lang.Thread.UncaughtExceptionHandler;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Date;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.logging.FileLoggingTask;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.logging.FileLoggingTask;
|
||||
import com.sap.sailing.racecommittee.app.logging.LifecycleLogger;
|
||||
|
||||
/**
|
||||
* Register a additional exception handler for uncaught exception to have some crash logging.
|
||||
*/
|
||||
@@ -27,12 +28,12 @@ public class RaceApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
ExLog.i(TAG, "Application is starting");
|
||||
|
||||
|
||||
Thread.setDefaultUncaughtExceptionHandler(new LoggingExceptionHandler(Thread
|
||||
.getDefaultUncaughtExceptionHandler()));
|
||||
|
||||
LifecycleLogger.enableLifecycleLogging(AppConstants.ENABLE_LIFECYCLE_LOGGING);
|
||||
stringContext = new StringContext(new WeakReference<Context>(getApplicationContext()));
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -1,21 +1,21 @@
|
||||
package com.sap.sailing.racecommittee.app.data;
|
||||
|
||||
public class DataLoadingException extends Exception {
|
||||
private static final long serialVersionUID = 4787160523984332591L;
|
||||
private static final long serialVersionUID = 4787160523984332591L;
|
||||
|
||||
public DataLoadingException() {
|
||||
}
|
||||
public DataLoadingException() {
|
||||
}
|
||||
|
||||
public DataLoadingException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
public DataLoadingException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
public DataLoadingException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
public DataLoadingException(Throwable throwable) {
|
||||
super(throwable);
|
||||
}
|
||||
|
||||
public DataLoadingException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
}
|
||||
public DataLoadingException(String detailMessage, Throwable throwable) {
|
||||
super(detailMessage, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-2
@@ -4,18 +4,23 @@ import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* Base class for all data managers. Use {@link DataManager#create(Context)} for creating your {@link DataManager}.
|
||||
*/
|
||||
public abstract class DataManager implements ReadonlyDataManager {
|
||||
|
||||
public static ReadonlyDataManager create(Context context) {
|
||||
if (AppConstants.IS_DATA_OFFLINE) {
|
||||
return new OfflineDataManager(InMemoryDataStore.INSTANCE);
|
||||
return new OfflineDataManager(context, InMemoryDataStore.INSTANCE);
|
||||
}
|
||||
return new OnlineDataManager(context, InMemoryDataStore.INSTANCE);
|
||||
}
|
||||
|
||||
protected Context context;
|
||||
protected DataStore dataStore;
|
||||
|
||||
public DataManager(DataStore dataStore) {
|
||||
public DataManager(Context context, DataStore dataStore) {
|
||||
this.context = context;
|
||||
this.dataStore = dataStore;
|
||||
}
|
||||
|
||||
@@ -23,4 +28,8 @@ public abstract class DataManager implements ReadonlyDataManager {
|
||||
return dataStore;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
+94
-76
@@ -7,6 +7,10 @@ import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Context;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
@@ -31,6 +35,8 @@ import com.sap.sailing.domain.racelog.RaceLogEventFactory;
|
||||
import com.sap.sailing.domain.racelog.impl.RaceLogEventFactoryImpl;
|
||||
import com.sap.sailing.domain.racelog.impl.RaceLogImpl;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderResult;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.ImmediateDataLoaderCallbacks;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.ManagedRaceIdentifierImpl;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.ManagedRaceImpl;
|
||||
@@ -39,8 +45,8 @@ public class OfflineDataManager extends DataManager {
|
||||
|
||||
private static boolean isInitialized = false;
|
||||
|
||||
public OfflineDataManager(DataStore dataStore) {
|
||||
super(dataStore);
|
||||
public OfflineDataManager(Context context, DataStore dataStore) {
|
||||
super(context, dataStore);
|
||||
|
||||
if (!isInitialized) {
|
||||
isInitialized = true;
|
||||
@@ -49,7 +55,8 @@ public class OfflineDataManager extends DataManager {
|
||||
}
|
||||
|
||||
private void fillDataStore(DataStore dataStore) {
|
||||
dataStore.addEvent(new EventBaseImpl("Extreme Sailing Series 2012 (Cardiff)", "Cardiff", "", true, "DUMBUUIDA"));
|
||||
dataStore
|
||||
.addEvent(new EventBaseImpl("Extreme Sailing Series 2012 (Cardiff)", "Cardiff", "", true, "DUMBUUIDA"));
|
||||
dataStore.addEvent(new EventBaseImpl("Extreme Sailing Series 2012 (Nice)", "Nice", "", true, "DUMBUUIDB"));
|
||||
dataStore.addEvent(new EventBaseImpl("Extreme Sailing Series 2012 (Rio)", "Rio", "", true, "DUMBUUIDC"));
|
||||
EventBase newEvent = new EventBaseImpl("Extreme Sailing Series 2013 (Muscat)", "Muscat", "", true, "FIXUUID");
|
||||
@@ -59,12 +66,9 @@ public class OfflineDataManager extends DataManager {
|
||||
|
||||
SeriesWithRows qualifying = new SeriesWithRowsImpl("Qualifying", false, null);
|
||||
SeriesWithRows medal = new SeriesWithRowsImpl("Medal", true, null);
|
||||
RaceGroup raceGroup = new RaceGroupImpl(
|
||||
"ESS",
|
||||
new BoatClassImpl("X40", false),
|
||||
null,
|
||||
Arrays.asList(qualifying, medal));
|
||||
|
||||
RaceGroup raceGroup = new RaceGroupImpl("ESS", new BoatClassImpl("X40", false), null, Arrays.asList(qualifying,
|
||||
medal));
|
||||
|
||||
List<Competitor> competitors = new ArrayList<Competitor>();
|
||||
competitors.add(new CompetitorImpl(UUID.randomUUID(), "SAP Extreme Sailing Team", null, null));
|
||||
competitors.add(new CompetitorImpl(UUID.randomUUID(), "The Wave Muscat", null, null));
|
||||
@@ -74,103 +78,117 @@ public class OfflineDataManager extends DataManager {
|
||||
|
||||
RaceLogEventFactory factory = new RaceLogEventFactoryImpl();
|
||||
RaceLog log = new RaceLogImpl(UUID.randomUUID());
|
||||
log.add(factory.createStartTimeEvent(
|
||||
new MillisecondsTimePoint(new Date().getTime() - 2000),
|
||||
1,
|
||||
log.add(factory.createStartTimeEvent(new MillisecondsTimePoint(new Date().getTime() - 2000), 1,
|
||||
new MillisecondsTimePoint(new Date().getTime() - 1000)));
|
||||
|
||||
log.add(factory.createRaceStatusEvent(
|
||||
new MillisecondsTimePoint(new Date().getTime()),
|
||||
1,
|
||||
log.add(factory.createRaceStatusEvent(new MillisecondsTimePoint(new Date().getTime()), 1,
|
||||
RaceLogRaceStatus.FINISHING));
|
||||
|
||||
ManagedRace q1 = new ManagedRaceImpl(
|
||||
new ManagedRaceIdentifierImpl(
|
||||
"Q1",
|
||||
new FleetImpl("Default"),
|
||||
qualifying,
|
||||
raceGroup),
|
||||
StartProcedureType.ESS,
|
||||
log);
|
||||
ManagedRace q1 = new ManagedRaceImpl(new ManagedRaceIdentifierImpl("A.B", new FleetImpl("A"), qualifying,
|
||||
raceGroup), StartProcedureType.ESS, log);
|
||||
|
||||
log = new RaceLogImpl(UUID.randomUUID());
|
||||
/*log.add(factory.createStartTimeEvent(
|
||||
new MillisecondsTimePoint(new Date()),
|
||||
1,
|
||||
RaceLogRaceStatus.SCHEDULED,
|
||||
new MillisecondsTimePoint(new Date().getTime() + 100000)));
|
||||
/*
|
||||
* log.add(factory.createStartTimeEvent( new MillisecondsTimePoint(new Date()), 1, RaceLogRaceStatus.SCHEDULED,
|
||||
* new MillisecondsTimePoint(new Date().getTime() + 100000)));
|
||||
*/
|
||||
|
||||
ManagedRace q2 = new ManagedRaceImpl(
|
||||
new ManagedRaceIdentifierImpl(
|
||||
"Q2",
|
||||
new FleetImpl("Default"),
|
||||
qualifying,
|
||||
raceGroup),
|
||||
StartProcedureType.ESS,
|
||||
log);
|
||||
ManagedRace q2 = new ManagedRaceImpl(new ManagedRaceIdentifierImpl("B", new FleetImpl("A.A"), qualifying,
|
||||
raceGroup), StartProcedureType.ESS, log);
|
||||
|
||||
log = new RaceLogImpl(UUID.randomUUID());
|
||||
/*log.add(factory.createRaceStatusEvent(
|
||||
new MillisecondsTimePoint(new Date()),
|
||||
5,
|
||||
RaceLogRaceStatus.FINISHED));*/
|
||||
ManagedRace q3 = new ManagedRaceImpl(
|
||||
new ManagedRaceIdentifierImpl(
|
||||
"Q3",
|
||||
new FleetImpl("Default"),
|
||||
qualifying,
|
||||
raceGroup),
|
||||
StartProcedureType.ESS,
|
||||
log);
|
||||
/*ManagedRace m1 = new ManagedRaceImpl(
|
||||
new ManagedRaceIdentifierImpl(
|
||||
"M1",
|
||||
new FleetImpl("Default"),
|
||||
medal,
|
||||
raceGroup),
|
||||
null);*/
|
||||
/*
|
||||
* log.add(factory.createRaceStatusEvent( new MillisecondsTimePoint(new Date()), 5,
|
||||
* RaceLogRaceStatus.FINISHED));
|
||||
*/
|
||||
ManagedRace q3 = new ManagedRaceImpl(new ManagedRaceIdentifierImpl("Q3", new FleetImpl("Default"), qualifying,
|
||||
raceGroup), StartProcedureType.ESS, log);
|
||||
/*
|
||||
* ManagedRace m1 = new ManagedRaceImpl( new ManagedRaceIdentifierImpl( "M1", new FleetImpl("Default"), medal,
|
||||
* raceGroup), null);
|
||||
*/
|
||||
dataStore.addRace(q1);
|
||||
dataStore.addRace(q2);
|
||||
dataStore.addRace(q3);
|
||||
//dataStore.addRace(m1);
|
||||
|
||||
// dataStore.addRace(m1);
|
||||
|
||||
Mark m1 = new MarkImpl("Red");
|
||||
Mark m2 = new MarkImpl("Green");
|
||||
Mark m3 = new MarkImpl("White");
|
||||
|
||||
|
||||
dataStore.addMark(m1);
|
||||
dataStore.addMark(m2);
|
||||
dataStore.addMark(m3);
|
||||
}
|
||||
|
||||
public void loadEvents(LoadClient<Collection<EventBase>> client) {
|
||||
client.onLoadSucceded(dataStore.getEvents());
|
||||
}
|
||||
|
||||
public void loadCourseAreas(Serializable parentEventId,
|
||||
LoadClient<Collection<CourseArea>> client) {
|
||||
client.onLoadSucceded(dataStore.getCourseAreas(dataStore.getEvent(parentEventId)));
|
||||
}
|
||||
|
||||
public void loadRaces(Serializable courseAreaId,
|
||||
LoadClient<Collection<ManagedRace>> client) {
|
||||
client.onLoadSucceded(dataStore.getRaces());
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<EventBase>>> createEventsLoader(
|
||||
LoadClient<Collection<EventBase>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<EventBase>>(context, callback,
|
||||
new Callable<Collection<EventBase>>() {
|
||||
@Override
|
||||
public Collection<EventBase> call() throws Exception {
|
||||
return dataStore.getEvents();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadMarks(ManagedRace managedRace, LoadClient<Collection<Mark>> client) {
|
||||
client.onLoadSucceded(dataStore.getMarks());
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<CourseArea>>> createCourseAreasLoader(
|
||||
final Serializable parentEventId, LoadClient<Collection<CourseArea>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<CourseArea>>(context, callback,
|
||||
new Callable<Collection<CourseArea>>() {
|
||||
@Override
|
||||
public Collection<CourseArea> call() throws Exception {
|
||||
return dataStore.getCourseAreas(dataStore.getEvent(parentEventId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCourse(ManagedRace managedRace, LoadClient<CourseBase> client) {
|
||||
client.onLoadSucceded(managedRace.getCourseOnServer());
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<ManagedRace>>> createRacesLoader(Serializable courseAreaId,
|
||||
LoadClient<Collection<ManagedRace>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<ManagedRace>>(context, callback,
|
||||
new Callable<Collection<ManagedRace>>() {
|
||||
@Override
|
||||
public Collection<ManagedRace> call() throws Exception {
|
||||
return dataStore.getRaces();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCompetitors(ManagedRace managedRace, LoadClient<Collection<Competitor>> client) {
|
||||
client.onLoadSucceded((Collection<Competitor>) managedRace.getCompetitors());
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Mark>>> createMarksLoader(ManagedRace managedRace,
|
||||
LoadClient<Collection<Mark>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<Mark>>(context, callback, new Callable<Collection<Mark>>() {
|
||||
@Override
|
||||
public Collection<Mark> call() throws Exception {
|
||||
return dataStore.getMarks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<CourseBase>> createCourseLoader(final ManagedRace managedRace,
|
||||
LoadClient<CourseBase> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<CourseBase>(context, callback, new Callable<CourseBase>() {
|
||||
@Override
|
||||
public CourseBase call() throws Exception {
|
||||
return managedRace.getCourseOnServer();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Competitor>>> createCompetitorsLoader(
|
||||
final ManagedRace managedRace, LoadClient<Collection<Competitor>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<Competitor>>(context, callback,
|
||||
new Callable<Collection<Competitor>>() {
|
||||
@Override
|
||||
public Collection<Competitor> call() throws Exception {
|
||||
return managedRace.getCompetitors();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+149
-162
@@ -1,13 +1,15 @@
|
||||
package com.sap.sailing.racecommittee.app.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.domain.base.BoatClass;
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
@@ -19,14 +21,18 @@ import com.sap.sailing.domain.base.SharedDomainFactory;
|
||||
import com.sap.sailing.racecommittee.app.AppPreferences;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.CompetitorsDataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.CourseDataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.CourseBaseHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.DataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.EventsDataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.ManagedRacesDataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.MarksDataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoader;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderCallbacks;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderCallbacks.LoaderCreator;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderResult;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.ImmediateDataLoaderCallbacks;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.OnlineDataLoader;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.CompetitorsDataParser;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.CourseDataParser;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.CourseBaseParser;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.DataParser;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.EventsDataParser;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.ManagedRacesDataParser;
|
||||
@@ -34,9 +40,10 @@ import com.sap.sailing.racecommittee.app.data.parsers.MarksDataParser;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRaceIdentifier;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.ControlPointDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseDataDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.CourseBaseDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.GateDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.MarkDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.coursedata.impl.WaypointDeserializer;
|
||||
@@ -58,25 +65,10 @@ import com.sap.sailing.server.gateway.deserialization.racelog.impl.RaceLogEventD
|
||||
* Enables accessing of data.
|
||||
*/
|
||||
public class OnlineDataManager extends DataManager {
|
||||
// private static final String TAG = OnlineDataManager.class.getName();
|
||||
|
||||
private Context context;
|
||||
private static final String TAG = OnlineDataManager.class.getName();
|
||||
|
||||
OnlineDataManager(Context context, DataStore dataStore) {
|
||||
super(dataStore);
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public void loadEvents(LoadClient<Collection<EventBase>> client) {
|
||||
if (dataStore.getEvents().isEmpty()) {
|
||||
reloadEvents(client);
|
||||
} else {
|
||||
client.onLoadSucceded(dataStore.getEvents());
|
||||
}
|
||||
super(context, dataStore);
|
||||
}
|
||||
|
||||
public void addEvents(Collection<EventBase> events) {
|
||||
@@ -85,160 +77,155 @@ public class OnlineDataManager extends DataManager {
|
||||
}
|
||||
}
|
||||
|
||||
protected void reloadEvents(LoadClient<Collection<EventBase>> client) {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
DataParser<Collection<EventBase>> parser = new EventsDataParser(new EventBaseJsonDeserializer(
|
||||
new VenueJsonDeserializer(new CourseAreaJsonDeserializer(domainFactory))));
|
||||
DataHandler<Collection<EventBase>> handler = new EventsDataHandler(this, client);
|
||||
|
||||
try {
|
||||
new DataLoader<Collection<EventBase>>(context, URI.create(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/events"), parser, handler).forceLoad();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void loadCourseAreas(final Serializable parentEventId, final LoadClient<Collection<CourseArea>> client) {
|
||||
|
||||
if (dataStore.hasEvent(parentEventId)) {
|
||||
EventBase event = dataStore.getEvent(parentEventId);
|
||||
client.onLoadSucceded(dataStore.getCourseAreas(event));
|
||||
} else {
|
||||
reloadEvents(new LoadClient<Collection<EventBase>>() {
|
||||
public void onLoadSucceded(Collection<EventBase> data) {
|
||||
if (dataStore.hasEvent(parentEventId)) {
|
||||
EventBase event = dataStore.getEvent(parentEventId);
|
||||
client.onLoadSucceded(dataStore.getCourseAreas(event));
|
||||
} else {
|
||||
client.onLoadFailed(new DataLoadingException(String.format(
|
||||
"There was no event object found for id %s.", parentEventId)));
|
||||
}
|
||||
}
|
||||
|
||||
public void onLoadFailed(Exception reason) {
|
||||
client.onLoadFailed(new DataLoadingException(
|
||||
String.format(
|
||||
"There was no event object found for id %s. While reloading the events an error occured: %s",
|
||||
parentEventId, reason), reason));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void addRaces(Collection<ManagedRace> data) {
|
||||
for (ManagedRace race : data) {
|
||||
dataStore.addRace(race);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadRaces(Serializable courseAreaId, LoadClient<Collection<ManagedRace>> client) {
|
||||
if (!dataStore.hasCourseArea(courseAreaId)) {
|
||||
client.onLoadFailed(new DataLoadingException(String.format("No course area found with id %s", courseAreaId)));
|
||||
return;
|
||||
}
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<BoatClass> boatClassDeserializer = new BoatClassJsonDeserializer(domainFactory);
|
||||
DataParser<Collection<ManagedRace>> parser = new ManagedRacesDataParser(context, new RaceGroupDeserializer(
|
||||
boatClassDeserializer, new SeriesWithRowsDeserializer(new RaceRowDeserializer(new FleetDeserializer(
|
||||
new ColorDeserializer()), new RaceCellDeserializer(
|
||||
new RaceLogDeserializer(RaceLogEventDeserializer.create(domainFactory)))))));
|
||||
DataHandler<Collection<ManagedRace>> handler = new ManagedRacesDataHandler(this, client);
|
||||
try {
|
||||
new DataLoader<Collection<ManagedRace>>(context, URI.create(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/racegroups?courseArea=" + courseAreaId.toString()), parser, handler)
|
||||
.forceLoad();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void addMarks(Collection<Mark> marks) {
|
||||
for (Mark mark : marks) {
|
||||
dataStore.addMark(mark);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadMarks(ManagedRace managedRace, LoadClient<Collection<Mark>> client) {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<Mark> markDeserializer = new MarkDeserializer(domainFactory);
|
||||
DataParser<Collection<Mark>> parser = new MarksDataParser(markDeserializer);
|
||||
DataHandler<Collection<Mark>> handler = new MarksDataHandler(this, client);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
try {
|
||||
new DataLoader<Collection<Mark>>(context, URI.create(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/marks?leaderboard=" + raceGroupName + "&raceColumn=" + raceColumnName
|
||||
+ "&fleet=" + fleetName), parser, handler)
|
||||
.forceLoad();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<EventBase>>> createEventsLoader(
|
||||
LoadClient<Collection<EventBase>> callback) {
|
||||
return new DataLoaderCallbacks<Collection<EventBase>>(callback, new LoaderCreator<Collection<EventBase>>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<Collection<EventBase>>> create(int id, Bundle args) throws Exception {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
DataParser<Collection<EventBase>> parser = new EventsDataParser(new EventBaseJsonDeserializer(
|
||||
new VenueJsonDeserializer(new CourseAreaJsonDeserializer(domainFactory))));
|
||||
DataHandler<Collection<EventBase>> handler = new EventsDataHandler(OnlineDataManager.this);
|
||||
|
||||
ExLog.i(TAG, "getEventsLoader created new loader...");
|
||||
|
||||
return new OnlineDataLoader<Collection<EventBase>>(context, new URL(AppPreferences
|
||||
.getServerBaseURL(context) + "/sailingserver/events"), parser, handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCourse(ManagedRace managedRace, LoadClient<CourseBase> client) {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<CourseBase> courseBaseDeserializer = new CourseDataDeserializer(
|
||||
new WaypointDeserializer(
|
||||
new ControlPointDeserializer(
|
||||
new MarkDeserializer(domainFactory),
|
||||
new GateDeserializer(domainFactory,
|
||||
new MarkDeserializer(domainFactory)))));
|
||||
DataParser<CourseBase> parser = new CourseDataParser(courseBaseDeserializer);
|
||||
DataHandler<CourseBase> handler = new CourseDataHandler(this, client, managedRace);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
try {
|
||||
new DataLoader<CourseBase>(context, URI.create(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/currentcourse?leaderboard=" + raceGroupName + "&raceColumn=" + raceColumnName
|
||||
+ "&fleet=" + fleetName), parser, handler)
|
||||
.forceLoad();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<CourseArea>>> createCourseAreasLoader(
|
||||
final Serializable parentEventId, LoadClient<Collection<CourseArea>> callback) {
|
||||
return new ImmediateDataLoaderCallbacks<Collection<CourseArea>>(context, callback,
|
||||
new Callable<Collection<CourseArea>>() {
|
||||
@Override
|
||||
public Collection<CourseArea> call() throws Exception {
|
||||
if (dataStore.hasEvent(parentEventId)) {
|
||||
EventBase event = dataStore.getEvent(parentEventId);
|
||||
return dataStore.getCourseAreas(event);
|
||||
} else {
|
||||
throw new DataLoadingException(String.format(
|
||||
"Unable to load course areas for unknown event %s.", parentEventId));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadCompetitors(ManagedRace managedRace, LoadClient<Collection<Competitor>> client) {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<Competitor> competitorDeserializer = new CompetitorDeserializer(domainFactory);
|
||||
DataParser<Collection<Competitor>> parser = new CompetitorsDataParser(competitorDeserializer);
|
||||
DataHandler<Collection<Competitor>> handler = new CompetitorsDataHandler(this, client, managedRace);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
try {
|
||||
new DataLoader<Collection<Competitor>>(context, URI.create(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/competitors?leaderboard=" + raceGroupName + "&raceColumn=" + raceColumnName
|
||||
+ "&fleet=" + fleetName), parser, handler)
|
||||
.forceLoad();
|
||||
} catch (MalformedURLException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<ManagedRace>>> createRacesLoader(final Serializable courseAreaId,
|
||||
LoadClient<Collection<ManagedRace>> callback) {
|
||||
return new DataLoaderCallbacks<Collection<ManagedRace>>(callback, new LoaderCreator<Collection<ManagedRace>>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<Collection<ManagedRace>>> create(int id, Bundle args) throws Exception {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<BoatClass> boatClassDeserializer = new BoatClassJsonDeserializer(domainFactory);
|
||||
DataParser<Collection<ManagedRace>> parser = new ManagedRacesDataParser(context,
|
||||
new RaceGroupDeserializer(boatClassDeserializer, new SeriesWithRowsDeserializer(
|
||||
new RaceRowDeserializer(new FleetDeserializer(new ColorDeserializer()),
|
||||
new RaceCellDeserializer(new RaceLogDeserializer(
|
||||
RaceLogEventDeserializer.create(domainFactory)))))));
|
||||
DataHandler<Collection<ManagedRace>> handler = new ManagedRacesDataHandler(OnlineDataManager.this);
|
||||
|
||||
return new OnlineDataLoader<Collection<ManagedRace>>(context, new URL(AppPreferences
|
||||
.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/racegroups?courseArea="
|
||||
+ courseAreaId.toString()), parser, handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Mark>>> createMarksLoader(final ManagedRace managedRace,
|
||||
LoadClient<Collection<Mark>> callback) {
|
||||
return new DataLoaderCallbacks<Collection<Mark>>(callback, new LoaderCreator<Collection<Mark>>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<Collection<Mark>>> create(int id, Bundle args) throws Exception {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<Mark> markDeserializer = new MarkDeserializer(domainFactory);
|
||||
DataParser<Collection<Mark>> parser = new MarksDataParser(markDeserializer);
|
||||
DataHandler<Collection<Mark>> handler = new MarksDataHandler(OnlineDataManager.this);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
return new OnlineDataLoader<Collection<Mark>>(context, new URL(AppPreferences
|
||||
.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/marks?leaderboard="
|
||||
+ raceGroupName
|
||||
+ "&raceColumn=" + raceColumnName + "&fleet=" + fleetName), parser, handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<CourseBase>> createCourseLoader(final ManagedRace managedRace,
|
||||
LoadClient<CourseBase> callback) {
|
||||
return new DataLoaderCallbacks<CourseBase>(callback, new LoaderCreator<CourseBase>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<CourseBase>> create(int id, Bundle args) throws Exception {
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<CourseBase> courseBaseDeserializer = new CourseBaseDeserializer(
|
||||
new WaypointDeserializer(new ControlPointDeserializer(new MarkDeserializer(domainFactory),
|
||||
new GateDeserializer(domainFactory, new MarkDeserializer(domainFactory)))));
|
||||
DataParser<CourseBase> parser = new CourseBaseParser(courseBaseDeserializer);
|
||||
DataHandler<CourseBase> handler = new CourseBaseHandler(OnlineDataManager.this, managedRace);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
return new OnlineDataLoader<CourseBase>(context, new URL(AppPreferences.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/currentcourse?leaderboard=" + raceGroupName + "&raceColumn="
|
||||
+ raceColumnName + "&fleet=" + fleetName), parser, handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Competitor>>> createCompetitorsLoader(
|
||||
final ManagedRace managedRace, LoadClient<Collection<Competitor>> callback) {
|
||||
return new DataLoaderCallbacks<Collection<Competitor>>(callback, new LoaderCreator<Collection<Competitor>>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<Collection<Competitor>>> create(int id, Bundle args) throws Exception {
|
||||
ExLog.i(TAG, String.format("Creating Competitor-OnlineDataLoader %d", id));
|
||||
SharedDomainFactory domainFactory = DomainFactoryImpl.INSTANCE;
|
||||
JsonDeserializer<Competitor> competitorDeserializer = new CompetitorDeserializer(domainFactory);
|
||||
DataParser<Collection<Competitor>> parser = new CompetitorsDataParser(competitorDeserializer);
|
||||
DataHandler<Collection<Competitor>> handler = new CompetitorsDataHandler(OnlineDataManager.this,
|
||||
managedRace);
|
||||
|
||||
ManagedRaceIdentifier identifier = managedRace.getIdentifier();
|
||||
|
||||
String raceGroupName = URLEncoder.encode(identifier.getRaceGroup().getName());
|
||||
String raceColumnName = URLEncoder.encode(identifier.getRaceName());
|
||||
String fleetName = URLEncoder.encode(identifier.getFleet().getName());
|
||||
|
||||
return new OnlineDataLoader<Collection<Competitor>>(context, new URL(AppPreferences
|
||||
.getServerBaseURL(context)
|
||||
+ "/sailingserver/rc/competitors?leaderboard="
|
||||
+ raceGroupName
|
||||
+ "&raceColumn=" + raceColumnName + "&fleet=" + fleetName), parser, handler);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+99
-8
@@ -3,27 +3,118 @@ package com.sap.sailing.racecommittee.app.data;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
import android.app.LoaderManager;
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.domain.base.CourseArea;
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.data.loaders.DataLoaderResult;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Interface for everything read related when working with data.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The result values of this interface's methods are meant to be used in conjunction with the Android's
|
||||
* {@link LoaderManager} facility. Everything that is loaded by this interface is stored and cached in the underlying
|
||||
* {@link DataStore}.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If there are cached results your {@link LoadClient}'s callback methods might be called twice (first cached results;
|
||||
* afterwards remote results). See {@link LoadClient} for restrictions that apply to your data handling code.
|
||||
* </p>
|
||||
*/
|
||||
public interface ReadonlyDataManager {
|
||||
|
||||
/**
|
||||
* Gets the underlying data store.
|
||||
*
|
||||
* @return the {@link DataStore}.
|
||||
*/
|
||||
public DataStore getDataStore();
|
||||
|
||||
public void loadEvents(LoadClient<Collection<EventBase>> client);
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading {@link EventBase}s.
|
||||
*
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<EventBase>>> createEventsLoader(
|
||||
LoadClient<Collection<EventBase>> callback);
|
||||
|
||||
public void loadCourseAreas(Serializable parentEventId, LoadClient<Collection<CourseArea>> client);
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading {@link CourseArea}s.
|
||||
*
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<CourseArea>>> createCourseAreasLoader(
|
||||
Serializable parentEventId, LoadClient<Collection<CourseArea>> callback);
|
||||
|
||||
public void loadRaces(Serializable courseAreaId, LoadClient<Collection<ManagedRace>> client);
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading {@link ManagedRace}s of a specific {@link CourseArea}.
|
||||
*
|
||||
* @param courseAreaId
|
||||
* the {@link CourseArea}'s Identifier.
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<ManagedRace>>> createRacesLoader(Serializable courseAreaId,
|
||||
LoadClient<Collection<ManagedRace>> callback);
|
||||
|
||||
public void loadMarks(ManagedRace managedRace, LoadClient<Collection<Mark>> client);
|
||||
|
||||
public void loadCourse(ManagedRace managedRace, LoadClient<CourseBase> client);
|
||||
|
||||
public void loadCompetitors(ManagedRace managedRace, LoadClient<Collection<Competitor>> client);
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading a race's {@link Mark}s.
|
||||
*
|
||||
* @param managedRace
|
||||
* the {@link ManagedRace}.
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Mark>>> createMarksLoader(ManagedRace managedRace,
|
||||
LoadClient<Collection<Mark>> callback);
|
||||
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading a race's {@link CourseBase}.
|
||||
*
|
||||
* @param managedRace
|
||||
* the {@link ManagedRace}.
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<CourseBase>> createCourseLoader(ManagedRace managedRace,
|
||||
LoadClient<CourseBase> callback);
|
||||
|
||||
/**
|
||||
* Creates a new {@link LoaderCallbacks} object for loading {@link Competitor}s.
|
||||
*
|
||||
* @param callback
|
||||
* {@link LoadClient} implementing your data handling code.
|
||||
* @return {@link LoaderCallbacks} to be used in
|
||||
* {@link LoaderManager#initLoader(int, android.os.Bundle, LoaderCallbacks)} or
|
||||
* {@link LoaderManager#restartLoader(int, android.os.Bundle, LoaderCallbacks)}.
|
||||
*/
|
||||
public LoaderCallbacks<DataLoaderResult<Collection<Competitor>>> createCompetitorsLoader(ManagedRace managedRace,
|
||||
LoadClient<Collection<Competitor>> callback);
|
||||
}
|
||||
+29
-2
@@ -1,6 +1,33 @@
|
||||
package com.sap.sailing.racecommittee.app.data.clients;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Loader;
|
||||
|
||||
/**
|
||||
* Interface to hide complexity of {@link LoaderCallbacks#onLoadFinished(Loader, Object)}. Keep in mind that all
|
||||
* restrictions that apply on the LoaderCallback's method also apply to all methods of this interface.
|
||||
*
|
||||
* @param <T>
|
||||
* loaded data type.
|
||||
*/
|
||||
public interface LoadClient<T> {
|
||||
public void onLoadFailed(Exception reason);
|
||||
public void onLoadSucceded(T data);
|
||||
|
||||
/**
|
||||
* Called when a {@link Loader} returned a failure to its {@link LoaderCallbacks#onLoadFinished(Loader, Object)}.
|
||||
*
|
||||
* @param reason
|
||||
* the loading has failed.
|
||||
*/
|
||||
public void onLoadFailed(Exception reason);
|
||||
|
||||
/**
|
||||
* Called when a {@link Loader} returned successfully to its {@link LoaderCallbacks#onLoadFinished(Loader, Object)}.
|
||||
*
|
||||
* @param data
|
||||
* that was loaded.
|
||||
* @param isCached
|
||||
* <code>true</code> if returned data is cached data.
|
||||
*/
|
||||
public void onLoadSucceded(T data, boolean isCached);
|
||||
|
||||
}
|
||||
+13
-5
@@ -4,21 +4,29 @@ import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.base.Competitor;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
|
||||
public class CompetitorsDataHandler extends DataHandler<Collection<Competitor>> {
|
||||
|
||||
private ManagedRace race;
|
||||
|
||||
public CompetitorsDataHandler(OnlineDataManager manager, LoadClient<Collection<Competitor>> client, ManagedRace managedRace) {
|
||||
super(manager, client);
|
||||
public CompetitorsDataHandler(OnlineDataManager manager, ManagedRace managedRace) {
|
||||
super(manager);
|
||||
race = managedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCachedResults() {
|
||||
return race.getCompetitors() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Competitor> getCachedResults() {
|
||||
return race.getCompetitors();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaded(Collection<Competitor> data) {
|
||||
super.onLoaded(data);
|
||||
public void onResult(Collection<Competitor> data) {
|
||||
race.setCompetitors(data);
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.sap.sailing.racecommittee.app.data.handlers;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
|
||||
public class CourseBaseHandler extends DataHandler<CourseBase> {
|
||||
|
||||
private ManagedRace race;
|
||||
|
||||
public CourseBaseHandler(OnlineDataManager manager, ManagedRace managedRace) {
|
||||
super(manager);
|
||||
race = managedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCachedResults() {
|
||||
return race.getCourseOnServer() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CourseBase getCachedResults() {
|
||||
return race.getCourseOnServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResult(CourseBase data) {
|
||||
race.setCourseOnServer(data);
|
||||
}
|
||||
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
package com.sap.sailing.racecommittee.app.data.handlers;
|
||||
|
||||
import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
|
||||
public class CourseDataHandler extends DataHandler<CourseBase> {
|
||||
|
||||
private ManagedRace race;
|
||||
|
||||
public CourseDataHandler(OnlineDataManager manager, LoadClient<CourseBase> client, ManagedRace managedRace) {
|
||||
super(manager, client);
|
||||
race = managedRace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaded(CourseBase data) {
|
||||
super.onLoaded(data);
|
||||
race.setCourseOnServer(data);
|
||||
}
|
||||
|
||||
}
|
||||
+8
-9
@@ -1,22 +1,21 @@
|
||||
package com.sap.sailing.racecommittee.app.data.handlers;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
|
||||
public abstract class DataHandler<T> {
|
||||
protected OnlineDataManager manager;
|
||||
protected LoadClient<T> client;
|
||||
|
||||
public DataHandler(OnlineDataManager manager, LoadClient<T> client) {
|
||||
public DataHandler(OnlineDataManager manager) {
|
||||
this.manager = manager;
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
public void onLoaded(T data) {
|
||||
client.onLoadSucceded(data);
|
||||
public abstract void onResult(T data);
|
||||
|
||||
public boolean hasCachedResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void onFailed(Exception reason) {
|
||||
client.onLoadFailed(reason);
|
||||
|
||||
public T getCachedResults() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+13
-5
@@ -4,18 +4,26 @@ import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.base.EventBase;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
|
||||
public class EventsDataHandler extends DataHandler<Collection<EventBase>> {
|
||||
|
||||
public EventsDataHandler(OnlineDataManager manager, LoadClient<Collection<EventBase>> client) {
|
||||
super(manager, client);
|
||||
public EventsDataHandler(OnlineDataManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaded(Collection<EventBase> data) {
|
||||
super.onLoaded(data);
|
||||
public void onResult(Collection<EventBase> data) {
|
||||
manager.addEvents(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCachedResults() {
|
||||
return !manager.getDataStore().getEvents().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<EventBase> getCachedResults() {
|
||||
return manager.getDataStore().getEvents();
|
||||
}
|
||||
|
||||
}
|
||||
+13
-5
@@ -3,18 +3,26 @@ package com.sap.sailing.racecommittee.app.data.handlers;
|
||||
import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
|
||||
public class ManagedRacesDataHandler extends DataHandler<Collection<ManagedRace>> {
|
||||
|
||||
public ManagedRacesDataHandler(OnlineDataManager manager, LoadClient<Collection<ManagedRace>> client) {
|
||||
super(manager, client);
|
||||
public ManagedRacesDataHandler(OnlineDataManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCachedResults() {
|
||||
return !manager.getDataStore().getRaces().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ManagedRace> getCachedResults() {
|
||||
return manager.getDataStore().getRaces();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaded(Collection<ManagedRace> data) {
|
||||
super.onLoaded(data);
|
||||
public void onResult(Collection<ManagedRace> data) {
|
||||
manager.addRaces(data);
|
||||
}
|
||||
|
||||
|
||||
+13
-5
@@ -4,17 +4,25 @@ import java.util.Collection;
|
||||
|
||||
import com.sap.sailing.domain.base.Mark;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
|
||||
public class MarksDataHandler extends DataHandler<Collection<Mark>> {
|
||||
|
||||
public MarksDataHandler(OnlineDataManager manager, LoadClient<Collection<Mark>> client) {
|
||||
super(manager, client);
|
||||
public MarksDataHandler(OnlineDataManager manager) {
|
||||
super(manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCachedResults() {
|
||||
return !manager.getDataStore().getMarks().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Mark> getCachedResults() {
|
||||
return manager.getDataStore().getMarks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaded(Collection<Mark> data) {
|
||||
super.onLoaded(data);
|
||||
public void onResult(Collection<Mark> data) {
|
||||
manager.addMarks(data);
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -4,17 +4,17 @@ import java.io.BufferedInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
public class HttpGetRequest extends HttpRequest {
|
||||
|
||||
public HttpGetRequest(URI requestUri) throws MalformedURLException, IOException {
|
||||
super(requestUri.toURL());
|
||||
public HttpGetRequest(URL requestUrl) {
|
||||
super(requestUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream execute(HttpURLConnection connection) throws IOException {
|
||||
return new BufferedInputStream(connection.getInputStream());
|
||||
protected BufferedInputStream execute(HttpURLConnection connection) throws IOException {
|
||||
InputStream stream = connection.getInputStream();
|
||||
return new BufferedInputStream(stream);
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -3,11 +3,9 @@ package com.sap.sailing.racecommittee.app.data.http;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class HttpJsonPostRequest extends HttpRequest {
|
||||
@@ -15,14 +13,13 @@ public class HttpJsonPostRequest extends HttpRequest {
|
||||
|
||||
private String requestBody;
|
||||
|
||||
public HttpJsonPostRequest(URI requestUri, String body) throws MalformedURLException, IOException {
|
||||
super(requestUri.toURL());
|
||||
public HttpJsonPostRequest(URL requestUrl, String body) {
|
||||
super(requestUrl);
|
||||
this.requestBody = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InputStream execute(HttpURLConnection connection) throws IOException {
|
||||
// connection.setDoInput(true);
|
||||
protected BufferedInputStream execute(HttpURLConnection connection) throws IOException {
|
||||
connection.setDoOutput(true);
|
||||
connection.setChunkedStreamingMode(0);
|
||||
|
||||
|
||||
+25
-14
@@ -1,5 +1,8 @@
|
||||
package com.sap.sailing.racecommittee.app.data.http;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -28,25 +31,24 @@ public abstract class HttpRequest {
|
||||
throw new IOException(String.format("Request response had no valid status."));
|
||||
}
|
||||
|
||||
private HttpURLConnection connection;
|
||||
private URL url;
|
||||
|
||||
public HttpRequest(URL url) throws IOException {
|
||||
this((HttpURLConnection) url.openConnection());
|
||||
public HttpRequest(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public HttpRequest(HttpURLConnection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
protected abstract InputStream execute(HttpURLConnection connection) throws IOException;
|
||||
|
||||
protected abstract BufferedInputStream execute(HttpURLConnection connection) throws IOException;
|
||||
|
||||
public InputStream execute() throws Exception {
|
||||
ExLog.i(TAG, String.format("(Request %d) Executing HTTP request on %s.", this.hashCode(), connection.getURL()));
|
||||
ExLog.i(TAG, String.format("(Request %d) Executing HTTP request on %s.", this.hashCode(), url));
|
||||
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
|
||||
connection.setConnectTimeout(5000);
|
||||
connection.setReadTimeout(15000);
|
||||
connection.setRequestProperty("connection", "close");
|
||||
|
||||
InputStream stream = null;
|
||||
BufferedInputStream stream = null;
|
||||
try {
|
||||
stream = execute(connection);
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
@@ -55,12 +57,21 @@ public abstract class HttpRequest {
|
||||
}
|
||||
|
||||
validateHttpResponse(connection);
|
||||
byte[] streamData = copyStream(stream);
|
||||
connection.disconnect();
|
||||
|
||||
ExLog.i(TAG, String.format("(Request %d) HTTP request executed.", this.hashCode()));
|
||||
return stream;
|
||||
return new ByteArrayInputStream(streamData);
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
connection.disconnect();
|
||||
private byte[] copyStream(BufferedInputStream stream) throws IOException {
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
int len;
|
||||
byte[] buffer = new byte[4096];
|
||||
while ((len = stream.read(buffer)) != -1) {
|
||||
bos.write(buffer, 0, len);
|
||||
}
|
||||
return bos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Context;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.DataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpGetRequest;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpRequest;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.DataParser;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public class DataLoader<T> extends AsyncTaskLoader<T> {
|
||||
private static final String TAG = DataLoader.class.getName();
|
||||
|
||||
protected DataParser<T> dataParser;
|
||||
protected DataHandler<T> dataHandler;
|
||||
protected HttpRequest httpRequest;
|
||||
protected volatile Exception lastException;
|
||||
|
||||
public DataLoader(Context context, URI httpGetUri, DataParser<T> dataParser, DataHandler<T> dataHandler)
|
||||
throws MalformedURLException, IOException {
|
||||
this(context, new HttpGetRequest(httpGetUri), dataParser, dataHandler);
|
||||
}
|
||||
|
||||
public DataLoader(Context context, HttpRequest request, DataParser<T> dataParser, DataHandler<T> dataHandler) {
|
||||
super(context);
|
||||
this.httpRequest = request;
|
||||
this.dataParser = dataParser;
|
||||
this.dataHandler = dataHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T loadInBackground() {
|
||||
lastException = null;
|
||||
try {
|
||||
return loadDataInBackground();
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
ExLog.e(TAG, String.format("Exception while loading data:\n%s", e.toString()));
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter stream = new PrintWriter(stringWriter);
|
||||
e.printStackTrace(stream);
|
||||
ExLog.e(TAG, stringWriter.toString());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private T loadDataInBackground() throws Exception {
|
||||
Reader reader = null;
|
||||
try {
|
||||
InputStream inputStream = httpRequest.execute();
|
||||
reader = new InputStreamReader(inputStream);
|
||||
return dataParser.parse(reader);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
httpRequest.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(T data) {
|
||||
if (data == null) {
|
||||
dataHandler.onFailed(lastException);
|
||||
} else {
|
||||
dataHandler.onLoaded(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
import android.app.LoaderManager.LoaderCallbacks;
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link LoaderCallbacks} wrapper to be used with {@link LoadClient}s.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* On result {@link DataLoaderResult#isSuccessful()} is checked. If true
|
||||
* {@link LoadClient#onLoadSucceded(Object, boolean)} is called; other {@link LoadClient#onLoadFailed(Exception)} is
|
||||
* called.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* There is currently no handling of a {@link Loader}'s reset.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* result type.
|
||||
*/
|
||||
public class DataLoaderCallbacks<T> implements LoaderCallbacks<DataLoaderResult<T>> {
|
||||
private static String TAG = DataLoaderCallbacks.class.getName();
|
||||
|
||||
public interface LoaderCreator<T> {
|
||||
Loader<DataLoaderResult<T>> create(int id, Bundle args) throws Exception;
|
||||
}
|
||||
|
||||
private LoadClient<T> clientCallback;
|
||||
private LoaderCreator<T> loaderCreator;
|
||||
|
||||
public DataLoaderCallbacks(LoadClient<T> clientCallback, LoaderCreator<T> loaderCreator) {
|
||||
this.clientCallback = clientCallback;
|
||||
this.loaderCreator = loaderCreator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Loader<DataLoaderResult<T>> onCreateLoader(int id, Bundle args) {
|
||||
try {
|
||||
return loaderCreator.create(id, args);
|
||||
} catch (Exception e) {
|
||||
ExLog.ex(TAG, e);
|
||||
}
|
||||
throw new IllegalStateException("Exception while creating a loader.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFinished(Loader<DataLoaderResult<T>> loader, DataLoaderResult<T> result) {
|
||||
if (result.isSuccessful()) {
|
||||
clientCallback.onLoadSucceded(result.getResult(), result.isResultCached());
|
||||
} else {
|
||||
clientCallback.onLoadFailed(result.getException());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<DataLoaderResult<T>> loader) {
|
||||
// currently we ignore loader resets...
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Wrapper class for data loading results.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* A {@link DataLoaderResult} may be successful or failed. It carries either the failure's {@link Exception} or the
|
||||
* actual result.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* result type.
|
||||
*/
|
||||
public class DataLoaderResult<T> {
|
||||
// private static final String TAG = DataLoaderResult.class.getName();
|
||||
|
||||
private final Exception exception;
|
||||
private final boolean cached;
|
||||
private final T result;
|
||||
|
||||
public DataLoaderResult(T result, boolean isCached) {
|
||||
this.result = result;
|
||||
this.cached = isCached;
|
||||
this.exception = null;
|
||||
}
|
||||
|
||||
public DataLoaderResult(Exception exception) {
|
||||
this.exception = exception;
|
||||
this.cached = false;
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
public boolean isSuccessful() {
|
||||
return exception == null;
|
||||
}
|
||||
|
||||
public Exception getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isResultCached() {
|
||||
if (!isSuccessful()) {
|
||||
throw new IllegalStateException("Failures cannot be cached!");
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
|
||||
/**
|
||||
* A {@link Loader} that (immediately) returns a {@link Callable}'s result. All results are announced as non-cached.
|
||||
*
|
||||
* @param <T> result type.
|
||||
*/
|
||||
public class ImmediateDataLoader<T> extends Loader<DataLoaderResult<T>> {
|
||||
|
||||
private Callable<T> resultCallable;
|
||||
|
||||
public ImmediateDataLoader(Context context, Callable<T> resultCallable) {
|
||||
super(context);
|
||||
this.resultCallable = resultCallable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
publishResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onForceLoad() {
|
||||
publishResult();
|
||||
}
|
||||
|
||||
private void publishResult() {
|
||||
try {
|
||||
// We act as a never caching DataLoader to ensure that it looks like remote access!
|
||||
deliverResult(new DataLoaderResult<T>(resultCallable.call(), false));
|
||||
} catch (Exception e) {
|
||||
deliverResult(new DataLoaderResult<T>(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
|
||||
/**
|
||||
* Simple wrapper for a {@link DataLoaderCallbacks} creating an {@link ImmediateDataLoader}.
|
||||
* @param <T> the result type.
|
||||
*/
|
||||
public class ImmediateDataLoaderCallbacks<T> extends DataLoaderCallbacks<T> {
|
||||
public ImmediateDataLoaderCallbacks(final Context context, LoadClient<T> clientCallback,
|
||||
final Callable<T> loadingFunc) {
|
||||
super(clientCallback, new LoaderCreator<T>() {
|
||||
@Override
|
||||
public Loader<DataLoaderResult<T>> create(int id, Bundle args) throws Exception {
|
||||
return new ImmediateDataLoader<T>(context, loadingFunc);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
package com.sap.sailing.racecommittee.app.data.loaders;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URL;
|
||||
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Context;
|
||||
import android.content.Loader;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.data.handlers.DataHandler;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpGetRequest;
|
||||
import com.sap.sailing.racecommittee.app.data.http.HttpRequest;
|
||||
import com.sap.sailing.racecommittee.app.data.parsers.DataParser;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A {@link Loader} that loads data by accessing a remote resource.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* An {@link OnlineDataLoader} may return cached results as announced by its {@link DataHandler}. Call
|
||||
* {@link OnlineDataLoader#forceLoad()} to ensure that the remote resource is checked for new data.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* The data returned by the remote resource is parsed by the given {@link DataParser} and may be cached through your
|
||||
* implementation of {@link DataHandler#onResult(Object)}.
|
||||
* </p>
|
||||
*
|
||||
* @param <T>
|
||||
* result type.
|
||||
*/
|
||||
public class OnlineDataLoader<T> extends AsyncTaskLoader<DataLoaderResult<T>> {
|
||||
private static final String TAG = OnlineDataLoader.class.getName();
|
||||
|
||||
protected DataParser<T> dataParser;
|
||||
protected DataHandler<T> dataHandler;
|
||||
protected HttpRequest httpRequest;
|
||||
|
||||
/**
|
||||
* Initializes a new {@link OnlineDataLoader} which initiates HTTP GET requests to load the remote data.
|
||||
*/
|
||||
public OnlineDataLoader(Context context, URL requestUrl, DataParser<T> dataParser, DataHandler<T> dataHandler) {
|
||||
this(context, new HttpGetRequest(requestUrl), dataParser, dataHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@link OnlineDataLoader} which executes the given {@link HttpRequest} to load the remote data.
|
||||
*/
|
||||
public OnlineDataLoader(Context context, HttpRequest request, DataParser<T> dataParser, DataHandler<T> dataHandler) {
|
||||
super(context);
|
||||
this.httpRequest = request;
|
||||
this.dataParser = dataParser;
|
||||
this.dataHandler = dataHandler;
|
||||
|
||||
ExLog.i(TAG, String.format("Loader created: %s", Integer.toHexString(this.hashCode())));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (dataHandler.hasCachedResults()) {
|
||||
ExLog.i(TAG, String.format("Using cached results... %s", Integer.toHexString(this.hashCode())));
|
||||
deliverResult(new DataLoaderResult<T>(dataHandler.getCachedResults(), true));
|
||||
} else {
|
||||
ExLog.i(TAG, String.format("No cached results. Forcing load now %s", Integer.toHexString(this.hashCode())));
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onForceLoad() {
|
||||
ExLog.i(TAG, String.format("Forcing load %s", Integer.toHexString(this.hashCode())));
|
||||
super.onForceLoad();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deliverResult(DataLoaderResult<T> result) {
|
||||
if (result.isSuccessful()) {
|
||||
dataHandler.onResult(result.getResult());
|
||||
}
|
||||
super.deliverResult(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataLoaderResult<T> loadInBackground() {
|
||||
try {
|
||||
return new DataLoaderResult<T>(loadDataInBackground(), false);
|
||||
} catch (Exception e) {
|
||||
ExLog.ex(TAG, e);
|
||||
return new DataLoaderResult<T>(e);
|
||||
}
|
||||
}
|
||||
|
||||
private T loadDataInBackground() throws Exception {
|
||||
Reader reader = null;
|
||||
try {
|
||||
InputStream inputStream = httpRequest.execute();
|
||||
reader = new InputStreamReader(inputStream);
|
||||
return dataParser.parse(reader);
|
||||
} finally {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -9,11 +9,11 @@ import com.sap.sailing.domain.base.CourseBase;
|
||||
import com.sap.sailing.server.gateway.deserialization.JsonDeserializer;
|
||||
import com.sap.sailing.server.gateway.deserialization.impl.Helpers;
|
||||
|
||||
public class CourseDataParser implements DataParser<CourseBase> {
|
||||
public class CourseBaseParser implements DataParser<CourseBase> {
|
||||
|
||||
private JsonDeserializer<CourseBase> deserializer;
|
||||
|
||||
public CourseDataParser(JsonDeserializer<CourseBase> deserializer) {
|
||||
public CourseBaseParser(JsonDeserializer<CourseBase> deserializer) {
|
||||
this.deserializer = deserializer;
|
||||
}
|
||||
|
||||
+6
-6
@@ -8,11 +8,11 @@ import com.sap.sailing.domain.base.racegroup.RaceGroup;
|
||||
|
||||
public interface FleetIdentifier {
|
||||
|
||||
public Fleet getFleet();
|
||||
|
||||
public SeriesBase getSeries();
|
||||
|
||||
public RaceGroup getRaceGroup();
|
||||
public Fleet getFleet();
|
||||
|
||||
public Serializable getId();
|
||||
public SeriesBase getSeries();
|
||||
|
||||
public RaceGroup getRaceGroup();
|
||||
|
||||
public Serializable getId();
|
||||
}
|
||||
+8
-1
@@ -32,7 +32,14 @@ public class FleetIdentifierImpl implements FleetIdentifier {
|
||||
}
|
||||
|
||||
public Serializable getId() {
|
||||
return String.format("%s.%s.%s", getRaceGroup().getName(), getSeries().getName(), getFleet().getName());
|
||||
return String.format("%s.%s.%s",
|
||||
escapeIdentifierFragment(getRaceGroup().getName()),
|
||||
escapeIdentifierFragment(getSeries().getName()),
|
||||
escapeIdentifierFragment(getFleet().getName()));
|
||||
}
|
||||
|
||||
protected String escapeIdentifierFragment(String fragment) {
|
||||
return fragment.replace(".", "\\.");
|
||||
}
|
||||
|
||||
}
|
||||
+17
-21
@@ -10,28 +10,24 @@ import com.sap.sailing.racecommittee.app.domain.ManagedRaceIdentifier;
|
||||
|
||||
public class ManagedRaceIdentifierImpl extends FleetIdentifierImpl implements ManagedRaceIdentifier {
|
||||
|
||||
private String raceName;
|
||||
|
||||
public ManagedRaceIdentifierImpl(
|
||||
String raceName,
|
||||
Fleet fleetWithRaceNames,
|
||||
SeriesBase series,
|
||||
RaceGroup raceGroup) {
|
||||
super(fleetWithRaceNames, series, raceGroup);
|
||||
this.raceName = raceName;
|
||||
}
|
||||
|
||||
public ManagedRaceIdentifierImpl(String raceName, FleetIdentifier identifier) {
|
||||
this(raceName, identifier.getFleet(), identifier.getSeries(), identifier.getRaceGroup());
|
||||
}
|
||||
private String raceName;
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
public ManagedRaceIdentifierImpl(String raceName, Fleet fleetWithRaceNames, SeriesBase series, RaceGroup raceGroup) {
|
||||
super(fleetWithRaceNames, series, raceGroup);
|
||||
this.raceName = raceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
return String.format("%s.%s", super.getId(), getRaceName());
|
||||
}
|
||||
public ManagedRaceIdentifierImpl(String raceName, FleetIdentifier identifier) {
|
||||
this(raceName, identifier.getFleet(), identifier.getSeries(), identifier.getRaceGroup());
|
||||
}
|
||||
|
||||
public String getRaceName() {
|
||||
return raceName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable getId() {
|
||||
return String.format("%s.%s", super.getId(), escapeIdentifierFragment(getRaceName()));
|
||||
}
|
||||
|
||||
}
|
||||
+19
@@ -1,5 +1,7 @@
|
||||
package com.sap.sailing.racecommittee.app.logging;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
@@ -127,6 +129,10 @@ public class ExLog {
|
||||
public synchronized static void e(String tag, String msg) {
|
||||
getInstance().error(tag, msg);
|
||||
}
|
||||
|
||||
public synchronized static void ex(String tag, Exception e) {
|
||||
getInstance().exception(tag, e);
|
||||
}
|
||||
|
||||
private final static String logMsgTemplate = "%s - %s - %s : %s";
|
||||
|
||||
@@ -179,6 +185,19 @@ public class ExLog {
|
||||
if (isTargetActive(Target.FILE))
|
||||
logToFile(LogLevel.ERROR, tag, msg);
|
||||
}
|
||||
|
||||
private void exception(String tag, Exception e) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter stream = new PrintWriter(stringWriter);
|
||||
e.printStackTrace(stream);
|
||||
String msg = stringWriter.toString();
|
||||
|
||||
if (isTargetActive(Target.LOGCAT))
|
||||
Log.e(tag, msg);
|
||||
|
||||
if (isTargetActive(Target.FILE))
|
||||
logToFile(LogLevel.ERROR, tag, msg);
|
||||
}
|
||||
|
||||
private boolean isTargetActive(Target logcat) {
|
||||
return activeLoggingTargets.contains(logcat);
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.sap.sailing.racecommittee.app.logging;
|
||||
|
||||
/**
|
||||
* Stolen from API Level 14.
|
||||
*
|
||||
*/
|
||||
public interface LifecycleCallbacks {
|
||||
void onCreate(Object activityOrFragment);
|
||||
|
||||
void onStart(Object activityOrFragment);
|
||||
|
||||
void onResume(Object activityOrFragment);
|
||||
|
||||
void onPause(Object activityOrFragment);
|
||||
|
||||
void onStop(Object activityOrFragment);
|
||||
|
||||
void onSaveInstanceState(Object activityOrFragment);
|
||||
|
||||
void onDestroy(Object activityOrFragment);
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.sap.sailing.racecommittee.app.logging;
|
||||
|
||||
/**
|
||||
* Logger to track all activity and fragment lifecycle events.
|
||||
*/
|
||||
public class LifecycleLogger implements LifecycleCallbacks {
|
||||
|
||||
private static final String TAG = LifecycleLogger.class.getName();
|
||||
private static boolean isLifecycleLoggingEnabled = false;
|
||||
|
||||
public static void enableLifecycleLogging(boolean enabled) {
|
||||
isLifecycleLoggingEnabled = enabled;
|
||||
}
|
||||
|
||||
private void onEvent(Object activityOrFragment, String action) {
|
||||
if (isLifecycleLoggingEnabled) {
|
||||
ExLog.i(TAG,
|
||||
String.format("%s %s %s", action, activityOrFragment.getClass().getSimpleName(),
|
||||
Integer.toHexString(System.identityHashCode(activityOrFragment))));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Creating");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Starting");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Resuming");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Pausing");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Stopping");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Saving instance");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(Object activityOrFragment) {
|
||||
onEvent(activityOrFragment, "Destroying");
|
||||
}
|
||||
|
||||
}
|
||||
+40
-26
@@ -9,13 +9,15 @@ import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import com.sap.sailing.domain.common.TimePoint;
|
||||
import com.sap.sailing.domain.common.impl.MillisecondsTimePoint;
|
||||
@@ -38,6 +40,7 @@ import com.sap.sailing.server.gateway.serialization.impl.CompetitorJsonSerialize
|
||||
import com.sap.sailing.server.gateway.serialization.racelog.impl.RaceLogEventSerializer;
|
||||
|
||||
public class RaceStateService extends Service {
|
||||
|
||||
private final static String TAG = RaceStateService.class.getName();
|
||||
|
||||
/**
|
||||
@@ -50,6 +53,7 @@ public class RaceStateService extends Service {
|
||||
}
|
||||
|
||||
private final static String EXTRAS_SERVICE_ID = RaceStateService.class.getName() + ".serviceId";
|
||||
private final static int NOTIFICATION_ID = 42;
|
||||
|
||||
private final IBinder mBinder = new RaceStateServiceBinder();
|
||||
|
||||
@@ -66,6 +70,9 @@ public class RaceStateService extends Service {
|
||||
private Map<ManagedRace, RaceStateEventListener> registeredStateEventListeners;
|
||||
|
||||
private Map<Serializable, List<PendingIntent>> managedIntents;
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notificationBuilder;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@@ -77,10 +84,27 @@ public class RaceStateService extends Service {
|
||||
this.registeredStateChangeListeners = new HashMap<ManagedRace, RaceStateChangedListener>();
|
||||
this.registeredStateEventListeners = new HashMap<ManagedRace, RaceStateEventListener>();
|
||||
this.managedIntents = new HashMap<Serializable, List<PendingIntent>>();
|
||||
|
||||
startForeground();
|
||||
ExLog.i(TAG, "Started.");
|
||||
|
||||
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
setupNotificationBuilder();
|
||||
|
||||
startForeground(NOTIFICATION_ID, notificationBuilder.build());
|
||||
super.onCreate();
|
||||
ExLog.i(TAG, "Started.");
|
||||
}
|
||||
|
||||
private void setupNotificationBuilder() {
|
||||
Intent launcherIntent = new Intent(this, LoginActivity.class);
|
||||
launcherIntent.setAction(Intent.ACTION_MAIN);
|
||||
launcherIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, launcherIntent, 0);
|
||||
notificationBuilder = new NotificationCompat.Builder(this)
|
||||
.setSmallIcon(R.drawable.sap_sailing_app_icon)
|
||||
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.sap_sailing_app_icon))
|
||||
.setContentTitle(getText(R.string.service_info))
|
||||
.setContentText(getText(R.string.service_text_no_races))
|
||||
.setContentIntent(contentIntent)
|
||||
.setOngoing(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,27 +156,6 @@ public class RaceStateService extends Service {
|
||||
ExLog.i(TAG, "All races unregistered.");
|
||||
}
|
||||
|
||||
private void startForeground() {
|
||||
CharSequence text = getText(R.string.service_title);
|
||||
|
||||
// Set the icon, scrolling text and timestamp
|
||||
Notification notification = new Notification(R.drawable.sap_sailing_app_icon, text, System.currentTimeMillis());
|
||||
|
||||
Intent intent = new Intent(this, LoginActivity.class);
|
||||
// clear all activities above started and reuse if already existing!
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
// The PendingIntent to launch our activity if the user selects this
|
||||
// notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
notification.setLatestEventInfo(this, getText(R.string.service_info), text, contentIntent);
|
||||
notification.flags |= Notification.FLAG_NO_CLEAR;
|
||||
|
||||
// Send the notification.
|
||||
this.startForeground(42, notification);
|
||||
}
|
||||
|
||||
private void handleStartCommand(Intent intent) {
|
||||
String action = intent.getAction();
|
||||
ExLog.i(TAG, String.format("Command action '%s' received.", action));
|
||||
@@ -197,6 +200,11 @@ public class RaceStateService extends Service {
|
||||
private void handleClearRaces(Intent intent) {
|
||||
unregisterAllRaces();
|
||||
clearAllRaces();
|
||||
|
||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder
|
||||
.setNumber(0)
|
||||
.setContentText(getString(R.string.service_text_no_races))
|
||||
.build());
|
||||
}
|
||||
|
||||
private void clearAllRaces() {
|
||||
@@ -211,6 +219,12 @@ public class RaceStateService extends Service {
|
||||
return;
|
||||
}
|
||||
registerRace(race);
|
||||
|
||||
int numRaces = managedIntents.keySet().size();
|
||||
notificationManager.notify(NOTIFICATION_ID, notificationBuilder
|
||||
.setNumber(numRaces)
|
||||
.setContentText(String.format(getString(R.string.service_text_num_races), numRaces))
|
||||
.build());
|
||||
}
|
||||
|
||||
private ManagedRace getRaceFromIntent(Intent intent) {
|
||||
@@ -245,7 +259,7 @@ public class RaceStateService extends Service {
|
||||
|
||||
ExLog.i(TAG, "Race " + race.getId() + " registered.");
|
||||
} else {
|
||||
ExLog.e(TAG, "Race " + race.getId() + " was already registered. Ignoring.");
|
||||
ExLog.w(TAG, "Race " + race.getId() + " was already registered. Ignoring.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-9
@@ -1,8 +1,7 @@
|
||||
package com.sap.sailing.racecommittee.app.services.sending;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
@@ -44,13 +43,8 @@ public class EventSenderTask extends AsyncTask<Intent, Void, Pair<Intent, Intege
|
||||
|
||||
try {
|
||||
ExLog.i(TAG, "Posting event: " + serializedEvent);
|
||||
HttpRequest post = new HttpJsonPostRequest(URI.create(url), serializedEvent.toString());
|
||||
try {
|
||||
final InputStream inputStream = post.execute();
|
||||
inputStream.close();
|
||||
} finally {
|
||||
post.disconnect();
|
||||
}
|
||||
HttpRequest post = new HttpJsonPostRequest(new URL(url), serializedEvent.toString());
|
||||
post.execute().close();
|
||||
ExLog.i(TAG, "Post successful for the following event: " + serializedEvent);
|
||||
} catch (Exception e) {
|
||||
ExLog.e(TAG, String.format("Post not successful, exception occured: %s", e.toString()));
|
||||
|
||||
+14
-15
@@ -2,12 +2,10 @@ package com.sap.sailing.racecommittee.app.ui.activities;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
@@ -25,7 +23,7 @@ import com.sap.sailing.racecommittee.app.services.sending.EventSendingService.Ev
|
||||
/**
|
||||
* Base activity for all race committee cockpit activities enabling basic menu functionality.
|
||||
*/
|
||||
public abstract class BaseActivity extends Activity {
|
||||
public abstract class BaseActivity extends LoggableActivity {
|
||||
|
||||
private class EventSendingServiceConnection implements ServiceConnection, EventSendingServiceLogger {
|
||||
@Override
|
||||
@@ -77,7 +75,6 @@ public abstract class BaseActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle item selection
|
||||
switch (item.getItemId()) {
|
||||
case R.id.options_menu_settings:
|
||||
ExLog.i(TAG, "Clicked SETTINGS.");
|
||||
@@ -86,8 +83,7 @@ public abstract class BaseActivity extends Activity {
|
||||
case R.id.options_menu_reload:
|
||||
ExLog.i(TAG, "Clicked RESET.");
|
||||
InMemoryDataStore.INSTANCE.reset();
|
||||
fadeActivity(LoginActivity.class, true);
|
||||
return true;
|
||||
return onReset();
|
||||
case R.id.options_menu_live:
|
||||
ExLog.i(TAG, "Clicked LIVE.");
|
||||
Toast.makeText(this, getLiveIconText(), Toast.LENGTH_LONG).show();
|
||||
@@ -109,31 +105,34 @@ public abstract class BaseActivity extends Activity {
|
||||
updateSendingServiceInformation();
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
super.onBackPressed();
|
||||
ExLog.i(TAG, String.format("Back pressed on activity %s", this.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
protected boolean onHomeClicked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ExLog.i(TAG, String.format("Creating activity %s", this.getClass().getSimpleName()));
|
||||
|
||||
protected boolean onReset() {
|
||||
fadeActivity(LoginActivity.class, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
ExLog.i(TAG, String.format("Starting activity %s", this.getClass().getSimpleName()));
|
||||
Intent intent = new Intent(this, EventSendingService.class);
|
||||
bindService(intent, sendingServiceConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
|
||||
ExLog.i(TAG, String.format("Stopping activity %s", this.getClass().getSimpleName()));
|
||||
if (boundSendingService) {
|
||||
unbindService(sendingServiceConnection);
|
||||
boundSendingService = false;
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.LifecycleLogger;
|
||||
|
||||
public abstract class LoggableActivity extends Activity {
|
||||
|
||||
private LifecycleLogger lifeLogger;
|
||||
|
||||
public LoggableActivity() {
|
||||
this.lifeLogger = new LifecycleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
lifeLogger.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
lifeLogger.onStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
lifeLogger.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
lifeLogger.onPause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
lifeLogger.onStop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
lifeLogger.onDestroy(this);
|
||||
}
|
||||
}
|
||||
+18
-7
@@ -15,7 +15,7 @@ import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.AppPreferences;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.BaseDialogFragment;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.AttachedDialogFragment;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.DialogListenerHost;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.LoginDialog;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.lists.CourseAreaListFragment;
|
||||
@@ -27,6 +27,8 @@ import com.sap.sailing.racecommittee.app.ui.fragments.lists.selection.ItemSelect
|
||||
public class LoginActivity extends BaseActivity implements EventSelectedListenerHost,
|
||||
CourseAreaSelectedListenerHost, DialogListenerHost {
|
||||
private final static String TAG = LoginActivity.class.getName();
|
||||
|
||||
private final static String CourseAreaListFragmentTag = "CourseAreaListFragmentTag";
|
||||
|
||||
private LoginDialog loginDialog;
|
||||
private CourseArea selectedCourseArea;
|
||||
@@ -35,6 +37,16 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
this.loginDialog = new LoginDialog();
|
||||
this.selectedCourseArea = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReset() {
|
||||
Fragment courseAreaFragment = getFragmentManager().findFragmentByTag(CourseAreaListFragmentTag);
|
||||
if (courseAreaFragment != null) {
|
||||
getFragmentManager().beginTransaction().remove(courseAreaFragment).commit();
|
||||
}
|
||||
recreate();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
@@ -49,13 +61,14 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
|
||||
// on first create add event list fragment
|
||||
if (savedInstanceState == null) {
|
||||
ExLog.i(TAG, "Seems to be first start. Creating event fragment.");
|
||||
addEventListFragment();
|
||||
}
|
||||
}
|
||||
|
||||
private void addEventListFragment() {
|
||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
||||
transaction.add(R.id.login_view_left_container, new EventListFragment());
|
||||
transaction.replace(R.id.login_view_left_container, new EventListFragment());
|
||||
transaction.setTransition(FragmentTransaction.TRANSIT_NONE);
|
||||
transaction.commit();
|
||||
}
|
||||
@@ -68,7 +81,7 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
fragment.setArguments(args);
|
||||
FragmentTransaction transaction = getFragmentManager().beginTransaction();
|
||||
transaction.setCustomAnimations(R.animator.slide_in, R.animator.slide_out);
|
||||
transaction.replace(R.id.login_view_right_container, fragment);
|
||||
transaction.replace(R.id.login_view_right_container, fragment, CourseAreaListFragmentTag);
|
||||
transaction.commit();
|
||||
ExLog.i("LoginActivity", "CourseFragment created.");
|
||||
}
|
||||
@@ -87,7 +100,6 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
}
|
||||
|
||||
private void showCourseAreaListFragment(Serializable eventId) {
|
||||
Toast.makeText(LoginActivity.this, eventId.toString(), Toast.LENGTH_LONG).show();
|
||||
addCourseAreaListFragment(eventId);
|
||||
}
|
||||
|
||||
@@ -114,7 +126,7 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
return new DialogResultListener() {
|
||||
|
||||
@Override
|
||||
public void onDialogPositiveButton(BaseDialogFragment dialog) {
|
||||
public void onDialogPositiveButton(AttachedDialogFragment dialog) {
|
||||
switch (loginDialog.getSelectedLoginType()) {
|
||||
case OFFICER:
|
||||
ExLog.i(TAG, "Communication with backend is active.");
|
||||
@@ -136,14 +148,13 @@ public class LoginActivity extends BaseActivity implements EventSelectedListener
|
||||
return;
|
||||
}
|
||||
|
||||
Toast.makeText(LoginActivity.this, selectedCourseArea.getId().toString(), Toast.LENGTH_LONG).show();
|
||||
Intent message = new Intent(LoginActivity.this, RacingActivity.class);
|
||||
message.putExtra(AppConstants.COURSE_AREA_UUID_KEY, selectedCourseArea.getId());
|
||||
fadeActivity(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogNegativeButton(BaseDialogFragment dialog) {
|
||||
public void onDialogNegativeButton(AttachedDialogFragment dialog) {
|
||||
/* nothing here... */
|
||||
}
|
||||
};
|
||||
|
||||
+65
-62
@@ -31,13 +31,16 @@ import com.sap.sailing.racecommittee.app.ui.fragments.RaceInfoFragment;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.lists.ManagedRaceListFragment;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.lists.ManagedRaceListFragment.FilterMode;
|
||||
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceInfoListener;
|
||||
import com.sap.sailing.racecommittee.app.utils.CollectionUtils;
|
||||
|
||||
public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
public class RacingActivity extends SessionActivity implements RaceInfoListener {
|
||||
// private final static String TAG = RacingActivity.class.getName();
|
||||
private final static String ListFragmentTag = RacingActivity.class.getName() + ".ManagedRaceListFragment";
|
||||
|
||||
|
||||
private static final String TAG = RacingActivity.class.getName();
|
||||
|
||||
private static final int RacesLoaderId = 0;
|
||||
|
||||
private class FilterModeSelectionBinder implements OnNavigationListener {
|
||||
|
||||
private ManagedRaceListFragment targetList;
|
||||
@@ -68,6 +71,59 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
}
|
||||
}
|
||||
|
||||
private class RaceLoadClient implements LoadClient<Collection<ManagedRace>> {
|
||||
|
||||
private Collection<ManagedRace> lastSeenRaces = null;
|
||||
private CourseArea courseArea;
|
||||
|
||||
public RaceLoadClient(CourseArea courseArea) {
|
||||
this.courseArea = courseArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadSucceded(Collection<ManagedRace> data, boolean isCached) {
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
|
||||
// Let's do the setup stuff only when the data is changed (or its the first time)
|
||||
if (lastSeenRaces != null && CollectionUtils.isEqualCollection(data, lastSeenRaces)) {
|
||||
ExLog.i(TAG, "Same races are already loaded...");
|
||||
} else {
|
||||
lastSeenRaces = data;
|
||||
|
||||
registerOnService(data);
|
||||
raceListFragment.setupOn(data);
|
||||
|
||||
Toast.makeText(RacingActivity.this,
|
||||
String.format(getString(R.string.racing_load_success), data.size()), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(RacingActivity.this);
|
||||
builder.setMessage(String.format(getString(R.string.generic_load_failure), reason.getMessage()))
|
||||
.setTitle(getString(R.string.loading_failure)).setIcon(R.drawable.ic_dialog_alert_holo_light)
|
||||
.setCancelable(true)
|
||||
.setPositiveButton(getString(R.string.retry), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
setProgressBarIndeterminateVisibility(true);
|
||||
|
||||
ExLog.i(TAG, "Issuing a reload of managed races");
|
||||
getLoaderManager().restartLoader(RacesLoaderId, null,
|
||||
dataManager.createRacesLoader(courseArea.getId(), RaceLoadClient.this));
|
||||
dialog.cancel();
|
||||
}
|
||||
}).setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
builder.create().show();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selection list of all races
|
||||
*/
|
||||
@@ -80,12 +136,6 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
|
||||
private ReadonlyDataManager dataManager;
|
||||
|
||||
@Override
|
||||
protected boolean onHomeClicked() {
|
||||
fadeActivity(LoginActivity.class, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
// features must be requested before anything else
|
||||
@@ -109,12 +159,15 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
Toast.makeText(this, getString(R.string.racing_course_area_missing), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
setupActionBar(courseArea);
|
||||
// unload and unregister from all races here!
|
||||
unloadAllRaces();
|
||||
loadRaces(courseArea);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
logoutSession();
|
||||
}
|
||||
|
||||
private ManagedRaceListFragment getOrCreateRaceListFragment() {
|
||||
Fragment fragment = getFragmentManager().findFragmentByTag(ListFragmentTag);
|
||||
// on first create add race list fragment
|
||||
@@ -149,8 +202,6 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
|
||||
private void setupActionBar(CourseArea courseArea) {
|
||||
ActionBar actionBar = getActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
actionBar.setTitle(String.format(getString(R.string.racingview_header), courseArea.getName()));
|
||||
|
||||
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
|
||||
@@ -160,40 +211,12 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
new FilterModeSelectionBinder(raceListFragment, actionBar, adapter, ManagedRaceListFragment.FilterMode.values());
|
||||
}
|
||||
|
||||
private void unloadAllRaces() {
|
||||
ExLog.i(TAG, "Issuing intent action clear races");
|
||||
Intent intent = new Intent(AppConstants.INTENT_ACTION_CLEAR_RACES);
|
||||
this.startService(intent);
|
||||
}
|
||||
|
||||
private void loadRaces(final CourseArea courseArea) {
|
||||
setProgressBarIndeterminateVisibility(true);
|
||||
|
||||
ExLog.i(TAG, "Issuing loading of managed races from data manager");
|
||||
dataManager.loadRaces(courseArea.getId(), new LoadClient<Collection<ManagedRace>>() {
|
||||
public void onLoadSucceded(Collection<ManagedRace> data) {
|
||||
onLoadRacesSucceded(courseArea, data);
|
||||
}
|
||||
|
||||
public void onLoadFailed(Exception reason) {
|
||||
onLoadRacesFailed(courseArea, reason);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void onLoadRacesSucceded(CourseArea courseArea, Collection<ManagedRace> data) {
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
|
||||
registerOnService(data);
|
||||
raceListFragment.setupOn(data);
|
||||
|
||||
Toast.makeText(RacingActivity.this, String.format(getString(R.string.racing_load_success), data.size()),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private void onLoadRacesFailed(final CourseArea courseArea, Exception reason) {
|
||||
setProgressBarIndeterminateVisibility(false);
|
||||
showLoadFailedDialog(courseArea, reason.getMessage());
|
||||
getLoaderManager().initLoader(RacesLoaderId, null,
|
||||
dataManager.createRacesLoader(courseArea.getId(), new RaceLoadClient(courseArea)));
|
||||
}
|
||||
|
||||
private void registerOnService(Collection<ManagedRace> races) {
|
||||
@@ -207,26 +230,6 @@ public class RacingActivity extends BaseActivity implements RaceInfoListener {
|
||||
}
|
||||
}
|
||||
|
||||
private void showLoadFailedDialog(final CourseArea courseArea, String message) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setMessage(
|
||||
String.format(getString(R.string.generic_load_failure), message))
|
||||
.setTitle(getString(R.string.loading_failure)).setIcon(R.drawable.ic_dialog_alert_holo_light).setCancelable(true)
|
||||
.setPositiveButton(getString(R.string.retry), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
loadRaces(courseArea);
|
||||
}
|
||||
}).setNegativeButton(getString(R.string.cancel), new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int id) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
if (!isFinishing()) {
|
||||
AlertDialog alert = builder.create();
|
||||
alert.show();
|
||||
}
|
||||
}
|
||||
|
||||
public void onRaceItemClicked(ManagedRace managedRace) {
|
||||
infoFragment = new RaceInfoFragment();
|
||||
infoFragment.setArguments(RaceFragment.createArguments(managedRace));
|
||||
|
||||
+4
-11
@@ -29,7 +29,7 @@ import com.sap.sailing.racecommittee.app.ui.adapters.PhotoAdapter;
|
||||
import com.sap.sailing.racecommittee.app.ui.views.CameraView;
|
||||
import com.sap.sailing.racecommittee.app.utils.MailHelper;
|
||||
|
||||
public class ResultsCapturingActivity extends BaseActivity {
|
||||
public class ResultsCapturingActivity extends SessionActivity {
|
||||
private static String ARGUMENTS_KEY_SUBJECT = "subject";
|
||||
private static String ARGUMENTS_KEY_TEXT = "text";
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ResultsCapturingActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setupActionBar();
|
||||
|
||||
@@ -111,13 +111,13 @@ public class ResultsCapturingActivity extends BaseActivity {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
setupCamera();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
releaseCamera();
|
||||
}
|
||||
@@ -161,12 +161,6 @@ public class ResultsCapturingActivity extends BaseActivity {
|
||||
currentImageFile = createFinisherImageFile(currentImageIndex++);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onHomeClicked() {
|
||||
fadeActivity(LoginActivity.class, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void setupListView() {
|
||||
TextView header = new TextView(this);
|
||||
header.setText(getString(R.string.results_capturing_view_list_header));
|
||||
@@ -181,7 +175,6 @@ public class ResultsCapturingActivity extends BaseActivity {
|
||||
|
||||
private void setupActionBar() {
|
||||
ActionBar actionBar = getActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
actionBar.setTitle(getString(R.string.results_capturing_title));
|
||||
}
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.activities;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
import android.app.ActionBar;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class SessionActivity extends BaseActivity {
|
||||
|
||||
private static final String TAG = BaseActivity.class.getName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
ActionBar actionBar = getActionBar();
|
||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
ExLog.i(TAG, String.format("Logging in from activity %s", this.getClass().getSimpleName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onHomeClicked() {
|
||||
return logoutSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onReset() {
|
||||
return logoutSession();
|
||||
}
|
||||
|
||||
protected boolean logoutSession() {
|
||||
ExLog.i(TAG, String.format("Logging out from activity %s", this.getClass().getSimpleName()));
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.logout_dialog_title))
|
||||
.setMessage(getString(R.string.logout_dialog_message))
|
||||
.setPositiveButton(getString(R.string.logout), new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
doLogout();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(getString(R.string.cancel), new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
/* nothing here */
|
||||
}
|
||||
})
|
||||
.create();
|
||||
dialog.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void doLogout() {
|
||||
unloadAllRaces();
|
||||
fadeActivity(LoginActivity.class, true);
|
||||
}
|
||||
|
||||
private void unloadAllRaces() {
|
||||
ExLog.i(TAG, "Issuing intent action clear races");
|
||||
Intent intent = new Intent(AppConstants.INTENT_ACTION_CLEAR_RACES);
|
||||
this.startService(intent);
|
||||
}
|
||||
|
||||
}
|
||||
+19
-2
@@ -3,6 +3,7 @@ package com.sap.sailing.racecommittee.app.ui.activities;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.ListPreference;
|
||||
@@ -24,6 +25,11 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.layout.settings_view);
|
||||
|
||||
setupStartProcedurePreferences();
|
||||
setupLanguageButton();
|
||||
}
|
||||
|
||||
private void setupStartProcedurePreferences() {
|
||||
final ListPreference startProcedurePreference = (ListPreference) findPreference("defaultStartProcedureType");
|
||||
|
||||
List<CharSequence> entries = new ArrayList<CharSequence>();
|
||||
@@ -47,8 +53,19 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void setupLanguageButton() {
|
||||
Preference button = (Preference)findPreference("languagePref");
|
||||
button.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference arg0) {
|
||||
Intent intent = new Intent(Intent.ACTION_MAIN);
|
||||
intent.setClassName("com.android.settings", "com.android.settings.LanguageSettings");
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -15,7 +15,7 @@ import com.sap.sailing.racecommittee.app.R;
|
||||
public class SystemInformationActivity extends BaseActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.system_information_view);
|
||||
setupVersionView();
|
||||
|
||||
+18
-18
@@ -20,6 +20,7 @@ import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.sap.sailing.domain.common.Bearing;
|
||||
@@ -37,9 +38,8 @@ import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
import com.sap.sailing.racecommittee.app.ui.views.CompassView;
|
||||
import com.sap.sailing.racecommittee.app.ui.views.CompassView.CompassDirectionListener;
|
||||
import com.sap.sailing.racecommittee.app.utils.GeoUtils;
|
||||
|
||||
public class WindActivity extends BaseActivity implements CompassDirectionListener, LocationListener {
|
||||
public class WindActivity extends SessionActivity implements CompassDirectionListener, LocationListener {
|
||||
|
||||
private final static int FIVE_SEC = 5000;
|
||||
private final static int EVERY_POSITION_CHANGE = 0;
|
||||
@@ -47,10 +47,9 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
CompassView compassView;
|
||||
EditText windBearingEditText;
|
||||
EditText windSpeedEditText;
|
||||
EditText latitudeEditText;
|
||||
EditText longitudeEditText;
|
||||
SeekBar windSpeedSeekBar;
|
||||
Button sendButton;
|
||||
TextView waitingForGpsTextView;
|
||||
|
||||
LocationManager locationManager;
|
||||
Location currentLocation;
|
||||
@@ -58,17 +57,16 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
DecimalFormat bearingFormat;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.wind_view);
|
||||
|
||||
compassView = (CompassView) findViewById(R.id.compassView);
|
||||
windBearingEditText = (EditText) findViewById(R.id.editTextWindDirection);
|
||||
windSpeedEditText = (EditText) findViewById(R.id.editTextWindSpeed);
|
||||
latitudeEditText = (EditText) findViewById(R.id.et_position_lat);
|
||||
longitudeEditText = (EditText) findViewById(R.id.et_position_lon);
|
||||
windSpeedSeekBar = (SeekBar) findViewById(R.id.seekbar_wind_speed);
|
||||
sendButton = (Button) findViewById(R.id.btn_wind_send);
|
||||
waitingForGpsTextView = (TextView) findViewById(R.id.textWaitingForGPS);
|
||||
|
||||
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
||||
@@ -144,9 +142,9 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
double enteredWindSpeed = AppPreferences.getWindSpeed(this);
|
||||
windSpeedSeekBar.setProgress(Double.valueOf(enteredWindSpeed).intValue() * 10);
|
||||
windSpeedEditText.setText(speedFormat.format(enteredWindSpeed));
|
||||
double enteredWindBearing = AppPreferences.getWindBearing(this);
|
||||
compassView.setDirection((float)enteredWindBearing);
|
||||
windBearingEditText.setText(bearingFormat.format(enteredWindBearing));
|
||||
double enteredWindBearingFrom = AppPreferences.getWindBearingFromDirection(this);
|
||||
compassView.setDirection((float)enteredWindBearingFrom);
|
||||
windBearingEditText.setText(bearingFormat.format(enteredWindBearingFrom));
|
||||
}
|
||||
|
||||
private void buildAlertMessageNoGps() {
|
||||
@@ -169,12 +167,14 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
|
||||
|
||||
protected void saveEntriesInPreferences(Wind wind) {
|
||||
AppPreferences.setWindBearing(getBaseContext(), wind.getBearing().getDegrees());
|
||||
// Wind.getBearing() returns a value that assumes that the wind flows in that direction
|
||||
// But for this app we need to display the direction the wind is coming from
|
||||
AppPreferences.setWindBearingFromDirection(getBaseContext(), wind.getBearing().reverse().getDegrees());
|
||||
AppPreferences.setWindSpeed(getBaseContext(), wind.getKnots());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
|
||||
compassView.setDirectionListener(this);
|
||||
@@ -187,7 +187,7 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
public void onPause() {
|
||||
locationManager.removeUpdates(this);
|
||||
super.onPause();
|
||||
}
|
||||
@@ -195,8 +195,7 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
currentLocation = location;
|
||||
latitudeEditText.setText(String.valueOf(GeoUtils.getDegMinSecFormatForDecimalDegree(location.getLatitude())));
|
||||
longitudeEditText.setText(String.valueOf(GeoUtils.getDegMinSecFormatForDecimalDegree(location.getLongitude())));
|
||||
waitingForGpsTextView.setText("");
|
||||
sendButton.setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -227,9 +226,10 @@ public class WindActivity extends BaseActivity implements CompassDirectionListen
|
||||
Position currentPosition = new DegreePosition(currentLocation.getLatitude(), currentLocation.getLongitude());
|
||||
double windSpeed = Double.valueOf(windSpeedEditText.getText().toString().replace(",", "."));
|
||||
double windBearing = Double.valueOf(windBearingEditText.getText().toString());
|
||||
Bearing bearing = new DegreeBearingImpl(windBearing);
|
||||
SpeedWithBearing speedBearing = new KnotSpeedWithBearingImpl(windSpeed, bearing);
|
||||
|
||||
Bearing bearing_from = new DegreeBearingImpl(windBearing);
|
||||
// this is not a standard bearing but the direction where the wind comes from, needs to be converted
|
||||
// to match the assumption that a bearing is always the direction the wind flows to
|
||||
SpeedWithBearing speedBearing = new KnotSpeedWithBearingImpl(windSpeed, bearing_from.reverse());
|
||||
return new WindImpl(currentPosition, MillisecondsTimePoint.now(), speedBearing);
|
||||
}
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.LifecycleLogger;
|
||||
|
||||
public abstract class LoggableFragment extends Fragment {
|
||||
|
||||
private LifecycleLogger lifeLogger;
|
||||
|
||||
public LoggableFragment() {
|
||||
this.lifeLogger = new LifecycleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
lifeLogger.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
lifeLogger.onStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
lifeLogger.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
lifeLogger.onPause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
lifeLogger.onStop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
lifeLogger.onDestroy(this);
|
||||
}
|
||||
|
||||
}
|
||||
+6
-5
@@ -2,16 +2,17 @@ package com.sap.sailing.racecommittee.app.ui.fragments;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.AppConstants;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.utils.TickListener;
|
||||
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
|
||||
public abstract class RaceFragment extends Fragment implements TickListener {
|
||||
public abstract class RaceFragment extends LoggableFragment implements TickListener {
|
||||
|
||||
//private static final String TAG = RaceFragment.class.getName();
|
||||
|
||||
public static Bundle createArguments(ManagedRace race) {
|
||||
Bundle arguments = new Bundle();
|
||||
@@ -63,7 +64,7 @@ public abstract class RaceFragment extends Fragment implements TickListener {
|
||||
|
||||
@Override
|
||||
public void notifyTick() {
|
||||
// may be overriden in subclasses.
|
||||
// see subclasses.
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -218,7 +218,7 @@ public class RaceInfoFragment extends RaceFragment implements RaceStateChangedLi
|
||||
LastWindFixFinder windFinder = new LastWindFixFinder(getRace().getState().getRaceLog());
|
||||
if (windFinder.analyze()!=null){
|
||||
Wind wind = windFinder.analyze();
|
||||
windInfoHeader.setText(String.format(getString(R.string.wind_info), wind.getKnots(), wind.getBearing().toString()));
|
||||
windInfoHeader.setText(String.format(getString(R.string.wind_info), wind.getKnots(), wind.getBearing().reverse().toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -29,9 +29,9 @@ public class RaceInfoFragmentChooser {
|
||||
|
||||
private RaceFragment createInfoFragment(Class<? extends RaceFragment> fragmentClass, ManagedRace managedRace) {
|
||||
try {
|
||||
ExLog.i(TAG, String.format("Fragment %s is chosen.", fragmentClass.getName()));
|
||||
RaceFragment fragment = fragmentClass.newInstance();
|
||||
fragment.setArguments(RaceFragment.createArguments(managedRace));
|
||||
ExLog.i(TAG, String.format("Fragment %s may be choosen", fragmentClass.getName()));
|
||||
return fragment;
|
||||
} catch (Exception e) {
|
||||
ExLog.e(TAG, String.format("Exception while instantiating race info fragment:\n%s", e.toString()));
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
|
||||
public abstract class ActivityAttachedDialogFragment extends BaseDialogFragment {
|
||||
public abstract class ActivityAttachedDialogFragment extends AttachedDialogFragment {
|
||||
|
||||
protected DialogListenerHost hostActivity;
|
||||
|
||||
|
||||
+53
-54
@@ -1,54 +1,53 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
public abstract class BaseDialogFragment extends DialogFragment {
|
||||
private final static String TAG = BaseDialogFragment.class.getName();
|
||||
|
||||
protected abstract CharSequence getNegativeButtonLabel();
|
||||
|
||||
protected abstract CharSequence getPositiveButtonLabel();
|
||||
|
||||
protected abstract Builder createDialog(AlertDialog.Builder builder);
|
||||
|
||||
protected abstract DialogListenerHost getHost();
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return createDialog(
|
||||
new Builder(getActivity()).setNegativeButton(getNegativeButtonLabel(), new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onNegativeButton();
|
||||
}
|
||||
}).setPositiveButton(getPositiveButtonLabel(), new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onPositiveButton();
|
||||
}
|
||||
})).create();
|
||||
}
|
||||
|
||||
protected void onNegativeButton() {
|
||||
if (getHost() != null) {
|
||||
getHost().getListener().onDialogNegativeButton(this);
|
||||
} else {
|
||||
ExLog.w(TAG, "Dialog host was null.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPositiveButton() {
|
||||
if (getHost() != null) {
|
||||
getHost().getListener().onDialogPositiveButton(this);
|
||||
} else {
|
||||
ExLog.w(TAG, "Dialog host was null.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
|
||||
public abstract class AttachedDialogFragment extends LoggableDialogFragment {
|
||||
private final static String TAG = AttachedDialogFragment.class.getName();
|
||||
|
||||
protected abstract CharSequence getNegativeButtonLabel();
|
||||
|
||||
protected abstract CharSequence getPositiveButtonLabel();
|
||||
|
||||
protected abstract Builder createDialog(AlertDialog.Builder builder);
|
||||
|
||||
protected abstract DialogListenerHost getHost();
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
return createDialog(
|
||||
new Builder(getActivity()).setNegativeButton(getNegativeButtonLabel(), new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onNegativeButton();
|
||||
}
|
||||
}).setPositiveButton(getPositiveButtonLabel(), new OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
onPositiveButton();
|
||||
}
|
||||
})).create();
|
||||
}
|
||||
|
||||
protected void onNegativeButton() {
|
||||
if (getHost() != null) {
|
||||
getHost().getListener().onDialogNegativeButton(this);
|
||||
} else {
|
||||
ExLog.w(TAG, "Dialog host was null.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void onPositiveButton() {
|
||||
if (getHost() != null) {
|
||||
getHost().getListener().onDialogPositiveButton(this);
|
||||
} else {
|
||||
ExLog.w(TAG, "Dialog host was null.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+3
-4
@@ -1,15 +1,14 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
|
||||
import android.app.DatePickerDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.widget.DatePicker;
|
||||
|
||||
public class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener,
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
|
||||
public class DatePickerFragment extends LoggableDialogFragment implements DatePickerDialog.OnDateSetListener,
|
||||
DatePickerDialog.OnDismissListener {
|
||||
|
||||
private DatePickerDialog.OnDateSetListener listener;
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@ package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
public interface DialogListenerHost {
|
||||
public interface DialogResultListener {
|
||||
void onDialogNegativeButton(BaseDialogFragment dialog);
|
||||
void onDialogPositiveButton(BaseDialogFragment dialog);
|
||||
void onDialogNegativeButton(AttachedDialogFragment dialog);
|
||||
void onDialogPositiveButton(AttachedDialogFragment dialog);
|
||||
}
|
||||
|
||||
DialogResultListener getListener();
|
||||
|
||||
+79
-94
@@ -7,6 +7,7 @@ import java.util.List;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -47,7 +48,9 @@ import com.sap.sailing.racecommittee.app.ui.comparators.NaturalNamedComparator;
|
||||
import com.sap.sailing.racecommittee.app.utils.ESSMarkImageHelper;
|
||||
|
||||
public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
//private final static String TAG = ESSCourseDesignDialogFragment.class.getName();
|
||||
// private final static String TAG = ESSCourseDesignDialogFragment.class.getName();
|
||||
|
||||
private static int MarksLoaderId = 0;
|
||||
|
||||
private List<Mark> aMarkList;
|
||||
private MarkGridAdapter gridAdapter;
|
||||
@@ -57,15 +60,15 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
private CourseElementListAdapter previousCourseElementAdapter;
|
||||
private DragSortListView newCourseListView;
|
||||
private ListView previousCourseListView;
|
||||
|
||||
|
||||
private DragSortController dragSortController;
|
||||
|
||||
|
||||
private Button publishButton;
|
||||
private Button unpublishButton;
|
||||
private Button takePreviousButton;
|
||||
|
||||
|
||||
private ReadonlyDataManager dataManager;
|
||||
|
||||
|
||||
private int dragStartMode = DragSortController.ON_DRAG;
|
||||
private boolean removeEnabled = true;
|
||||
private int removeMode = DragSortController.FLING_REMOVE;
|
||||
@@ -83,17 +86,19 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
getDialog().setTitle(getActivity().getText(R.string.course_design_dialog_title));
|
||||
|
||||
dataManager = DataManager.create(getActivity());
|
||||
|
||||
aMarkList = new ArrayList<Mark>();
|
||||
|
||||
aMarkList = new ArrayList<Mark>();
|
||||
courseElements = new ArrayList<CourseListDataElement>();
|
||||
previousCourseElements = new ArrayList<CourseListDataElement>();
|
||||
|
||||
gridAdapter = new MarkGridAdapter(getActivity(), aMarkList, ESSMarkImageHelper.getInstance());
|
||||
courseElementAdapter = new DraggableCourseElementListAdapter(getActivity(), courseElements, ESSMarkImageHelper.getInstance());
|
||||
previousCourseElementAdapter = new CourseElementListAdapter(getActivity(), previousCourseElements, ESSMarkImageHelper.getInstance());
|
||||
|
||||
courseElementAdapter = new DraggableCourseElementListAdapter(getActivity(), courseElements,
|
||||
ESSMarkImageHelper.getInstance());
|
||||
previousCourseElementAdapter = new CourseElementListAdapter(getActivity(), previousCourseElements,
|
||||
ESSMarkImageHelper.getInstance());
|
||||
|
||||
loadMarks();
|
||||
loadCourseOnServer();
|
||||
fillPreviousCourseElementsWithLastPublishedCourseDesign();
|
||||
|
||||
GridView gridView = (GridView) getView().findViewById(R.id.gridViewAssets);
|
||||
gridView.setAdapter(gridAdapter);
|
||||
@@ -107,7 +112,7 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
newCourseListView = (DragSortListView) getView().findViewById(R.id.listViewNewCourse);
|
||||
newCourseListView.setAdapter(courseElementAdapter);
|
||||
newCourseListView.setDropListener(new DragSortListView.DropListener() {
|
||||
@@ -121,16 +126,16 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
newCourseListView.setRemoveListener(new DragSortListView.RemoveListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void remove(int toBeRemoved) {
|
||||
CourseListDataElement item = courseElementAdapter.getItem(toBeRemoved);
|
||||
courseElementAdapter.remove(item);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
newCourseListView.setOnItemLongClickListener(new OnItemLongClickListener() {
|
||||
|
||||
@Override
|
||||
@@ -140,7 +145,7 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
dragSortController = buildDragSortController(newCourseListView);
|
||||
newCourseListView.setFloatViewManager(dragSortController);
|
||||
newCourseListView.setOnTouchListener(dragSortController);
|
||||
@@ -163,14 +168,12 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
} else {
|
||||
copyPreviousToNewCourseDesign();
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Toast.makeText(getActivity(), "No course available to copy", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
publishButton = (Button) getView().findViewById(R.id.publishCourseDesignButton);
|
||||
publishButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@@ -180,13 +183,19 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
sendCourseDataAndDismiss(courseData);
|
||||
} catch (IllegalStateException ex) {
|
||||
if (ex.getMessage().equals("Gate has no right buoy")) {
|
||||
Toast.makeText(getActivity(), "A right buoy is missing for a gate. Please select the right buoy.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(getActivity(),
|
||||
"A right buoy is missing for a gate. Please select the right buoy.", Toast.LENGTH_LONG)
|
||||
.show();
|
||||
} else if (ex.getMessage().equals("Each waypoints needs a passing side")) {
|
||||
Toast.makeText(getActivity(), "A waypoint has no passing side. Please select the passing side by clicking long on the waypoint.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(
|
||||
getActivity(),
|
||||
"A waypoint has no passing side. Please select the passing side by clicking long on the waypoint.",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Toast.makeText(getActivity(), "The course design has to have at least one waypoint.", Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(getActivity(), "The course design has to have at least one waypoint.",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,19 +203,16 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
|
||||
unpublishButton = (Button) getView().findViewById(R.id.unpublishCourseDesignButton);
|
||||
unpublishButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
CourseBase emptyCourse = new CourseDataImpl("Unpublished course design");
|
||||
sendCourseDataAndDismiss(emptyCourse);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a DragSortController and thereby defines the behaviour of the drag sort list
|
||||
* Creates a DragSortController and thereby defines the behavior of the drag sort list
|
||||
*/
|
||||
public DragSortController buildDragSortController(DragSortListView dragSortListView) {
|
||||
DragSortController controller = new DragSortController(dragSortListView);
|
||||
@@ -219,54 +225,30 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
controller.setBackgroundColor(getActivity().getResources().getColor(R.color.welter_medium_blue));
|
||||
return controller;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
onLoadMarksSucceeded(dataManager.getDataStore().getMarks());
|
||||
}
|
||||
|
||||
private void loadCourseOnServer() {
|
||||
dataManager.loadCourse(getRace(), new LoadClient<CourseBase>() {
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
fillPreviousCourseElementsWithLastPublishedCourseDesign();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadSucceded(CourseBase data) {
|
||||
/*if (Util.size(data.getWaypoints()) > 0) {
|
||||
fillPreviousCourseElementsInList(data);
|
||||
} else*/ {
|
||||
fillPreviousCourseElementsWithLastPublishedCourseDesign();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void fillPreviousCourseElementsWithLastPublishedCourseDesign() {
|
||||
CourseBase lastPublishedCourseDesign = InMemoryDataStore.INSTANCE.getLastPublishedCourseDesign();
|
||||
if(lastPublishedCourseDesign != null) {
|
||||
if (lastPublishedCourseDesign != null) {
|
||||
fillPreviousCourseElementsInList(lastPublishedCourseDesign);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadMarks() {
|
||||
dataManager.loadMarks(getRace(), new LoadClient<Collection<Mark>>() {
|
||||
Loader<?> marksLoader = getLoaderManager().restartLoader(MarksLoaderId, null,
|
||||
dataManager.createMarksLoader(getRace(), new LoadClient<Collection<Mark>>() {
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
Toast.makeText(getActivity(), String.format("Marks: %s",reason.toString()), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadSucceded(Collection<Mark> data) {
|
||||
onLoadMarksSucceeded(data);
|
||||
}
|
||||
|
||||
});
|
||||
@Override
|
||||
public void onLoadSucceded(Collection<Mark> data, boolean isCached) {
|
||||
onLoadMarksSucceeded(data);
|
||||
}
|
||||
}));
|
||||
// ignore any cached results and force a remote load of the marks,
|
||||
// because we always need the most current.
|
||||
marksLoader.forceLoad();
|
||||
}
|
||||
|
||||
protected void onLoadMarksSucceeded(Collection<Mark> data) {
|
||||
@@ -295,10 +277,10 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
|
||||
for (Waypoint waypoint : courseData.getWaypoints()) {
|
||||
ControlPoint controlPoint = waypoint.getControlPoint();
|
||||
|
||||
|
||||
if (controlPoint instanceof Mark) {
|
||||
CourseListDataElement element = new CourseListDataElement();
|
||||
element.setLeftMark((Mark)controlPoint);
|
||||
element.setLeftMark((Mark) controlPoint);
|
||||
element.setRoundingDirection(getRoundingDirection(waypoint.getPassingSide()));
|
||||
elementList.add(element);
|
||||
} else if (controlPoint instanceof Gate) {
|
||||
@@ -327,24 +309,28 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
}
|
||||
|
||||
protected CourseBase convertCourseElementsToACourseData() throws IllegalStateException, IllegalArgumentException {
|
||||
//TODO find a proper name for the highly flexible ESS courses to be shown on the regatta overview page
|
||||
CourseBase design = new CourseDataImpl("Course template");
|
||||
// TODO find a proper name for the highly flexible ESS courses to be shown on the regatta overview page
|
||||
CourseBase design = new CourseDataImpl("Course");
|
||||
List<Waypoint> waypoints = new ArrayList<Waypoint>();
|
||||
|
||||
for (CourseListDataElement courseElement : courseElements) {
|
||||
if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate) && courseElement.getRightMark() != null) {
|
||||
String gateName = "Gate " + courseElement.getLeftMark().getName() + " / " + courseElement.getRightMark().getName();
|
||||
if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate)
|
||||
&& courseElement.getRightMark() != null) {
|
||||
String gateName = "Gate " + courseElement.getLeftMark().getName() + " / "
|
||||
+ courseElement.getRightMark().getName();
|
||||
Gate gate = new GateImpl(courseElement.getLeftMark(), courseElement.getRightMark(), gateName);
|
||||
Waypoint waypoint = new WaypointImpl(gate);
|
||||
|
||||
|
||||
waypoints.add(waypoint);
|
||||
} else if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate) && courseElement.getRightMark() == null) {
|
||||
} else if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate)
|
||||
&& courseElement.getRightMark() == null) {
|
||||
throw new IllegalStateException("Gate has no right buoy");
|
||||
} else if (courseElement.getRoundingDirection().equals(RoundingDirection.None)) {
|
||||
throw new IllegalStateException("Each waypoints needs a passing side");
|
||||
} else {
|
||||
Waypoint waypoint = new WaypointImpl(courseElement.getLeftMark(), getNauticalSide(courseElement.getRoundingDirection()));
|
||||
|
||||
Waypoint waypoint = new WaypointImpl(courseElement.getLeftMark(),
|
||||
getNauticalSide(courseElement.getRoundingDirection()));
|
||||
|
||||
waypoints.add(waypoint);
|
||||
}
|
||||
|
||||
@@ -365,19 +351,19 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
NauticalSide side = null;
|
||||
if (roundingDirection.name().equalsIgnoreCase(NauticalSide.PORT.name())) {
|
||||
side = NauticalSide.PORT;
|
||||
} else if (roundingDirection.name().equalsIgnoreCase(NauticalSide.STARBOARD.name())){
|
||||
} else if (roundingDirection.name().equalsIgnoreCase(NauticalSide.STARBOARD.name())) {
|
||||
side = NauticalSide.STARBOARD;
|
||||
}
|
||||
return side;
|
||||
}
|
||||
|
||||
|
||||
private RoundingDirection getRoundingDirection(NauticalSide passingSide) {
|
||||
RoundingDirection direction = null;
|
||||
if (passingSide == null) {
|
||||
direction = RoundingDirection.None;
|
||||
} else if (passingSide.name().equalsIgnoreCase(RoundingDirection.Port.name())) {
|
||||
direction = RoundingDirection.Port;
|
||||
} else if (passingSide.name().equalsIgnoreCase(RoundingDirection.Starboard.name())){
|
||||
} else if (passingSide.name().equalsIgnoreCase(RoundingDirection.Starboard.name())) {
|
||||
direction = RoundingDirection.Starboard;
|
||||
} else {
|
||||
direction = RoundingDirection.Gate;
|
||||
@@ -400,18 +386,18 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
//do nothing
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
builder.create();
|
||||
builder.show();
|
||||
}
|
||||
|
||||
|
||||
protected void copyPreviousToNewCourseDesign() {
|
||||
courseElements.clear();
|
||||
courseElements.addAll(previousCourseElements);
|
||||
courseElementAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected void onMarkClickedOnGrid(Mark mark) {
|
||||
if (courseElements.isEmpty()) {
|
||||
@@ -426,10 +412,11 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private CourseListDataElement getFirstGateCourseElementWithoutRightMark() {
|
||||
for (CourseListDataElement courseElement : courseElements) {
|
||||
if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate) && courseElement.getRightMark() == null) {
|
||||
if (courseElement.getRoundingDirection().equals(RoundingDirection.Gate)
|
||||
&& courseElement.getRightMark() == null) {
|
||||
return courseElement;
|
||||
}
|
||||
}
|
||||
@@ -448,15 +435,13 @@ public class ESSCourseDesignDialogFragment extends RaceDialogFragment {
|
||||
directions.add(direction.name());
|
||||
}
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setTitle(R.string.pick_a_rounding_direction)
|
||||
.setItems(R.array.rounding_directions, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int position) {
|
||||
// for i18n we expect following order in array: 1. Port, 2. Starboard, 3. Gate
|
||||
//String[] directions = getActivity().getResources().getStringArray(R.array.rounding_directions);
|
||||
RoundingDirection pickedDirection = RoundingDirection.relevantValues()[position];
|
||||
onRoundingDirectionPicked(courseElement, pickedDirection);
|
||||
}
|
||||
});
|
||||
builder.setTitle(R.string.pick_a_rounding_direction).setItems(R.array.rounding_directions,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int position) {
|
||||
RoundingDirection pickedDirection = RoundingDirection.relevantValues()[position];
|
||||
onRoundingDirectionPicked(courseElement, pickedDirection);
|
||||
}
|
||||
});
|
||||
builder.create();
|
||||
builder.show();
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
import android.app.Fragment;
|
||||
|
||||
public abstract class FragmentAttachedDialogFragment extends BaseDialogFragment {
|
||||
public abstract class FragmentAttachedDialogFragment extends AttachedDialogFragment {
|
||||
|
||||
@Override
|
||||
protected DialogListenerHost getHost() {
|
||||
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
|
||||
|
||||
import android.app.DialogFragment;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.sap.sailing.racecommittee.app.logging.LifecycleLogger;
|
||||
|
||||
/**
|
||||
* Simple base class for {@link DialogFragment}'s to add some logging.
|
||||
*/
|
||||
public abstract class LoggableDialogFragment extends DialogFragment {
|
||||
|
||||
private LifecycleLogger lifeLogger;
|
||||
|
||||
public LoggableDialogFragment() {
|
||||
this.lifeLogger = new LifecycleLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
lifeLogger.onCreate(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
lifeLogger.onStart(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
lifeLogger.onResume(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
lifeLogger.onPause(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
lifeLogger.onStop(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
lifeLogger.onDestroy(this);
|
||||
}
|
||||
|
||||
}
|
||||
+77
-54
@@ -9,6 +9,7 @@ import java.util.List;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Loader;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -19,6 +20,7 @@ import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.mobeta.android.dslv.DragSortController;
|
||||
import com.mobeta.android.dslv.DragSortListView;
|
||||
@@ -29,6 +31,7 @@ import com.sap.sailing.domain.common.impl.Util;
|
||||
import com.sap.sailing.domain.common.impl.Util.Triple;
|
||||
import com.sap.sailing.racecommittee.app.R;
|
||||
import com.sap.sailing.racecommittee.app.data.OnlineDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
|
||||
import com.sap.sailing.racecommittee.app.data.clients.LoadClient;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.DomainFactoryImpl;
|
||||
import com.sap.sailing.racecommittee.app.logging.ExLog;
|
||||
@@ -37,28 +40,28 @@ import com.sap.sailing.racecommittee.app.ui.adapters.finishing.CompetitorsAdapte
|
||||
import com.sap.sailing.racecommittee.app.ui.comparators.NaturalNamedComparator;
|
||||
|
||||
public class PositioningFragment extends RaceDialogFragment {
|
||||
|
||||
|
||||
private DragSortListView positioningListView;
|
||||
private ListView competitorListView;
|
||||
private DragSortController dragSortController;
|
||||
|
||||
|
||||
private CompetitorsAdapter competitorsAdapter;
|
||||
private CompetitorPositioningListAdapter positioningAdapter;
|
||||
|
||||
|
||||
protected List<Competitor> competitors;
|
||||
protected List<Triple<Serializable, String, MaxPointsReason>> positionedCompetitors;
|
||||
protected Comparator<Named> competitorComparator;
|
||||
|
||||
|
||||
private int dragStartMode = DragSortController.ON_DRAG;
|
||||
private boolean removeEnabled = true;
|
||||
private int removeMode = DragSortController.FLING_REMOVE;
|
||||
private boolean sortEnabled = true;
|
||||
private boolean dragEnabled = true;
|
||||
|
||||
|
||||
private boolean isDialog() {
|
||||
return getDialog() != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
if (isDialog()) {
|
||||
@@ -66,11 +69,11 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
return inflater.inflate(R.layout.race_positioning_view, container, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
|
||||
|
||||
if (isDialog()) {
|
||||
Button okButton = (Button) getView().findViewById(R.id.buttonPositionOk);
|
||||
okButton.setVisibility(Button.VISIBLE);
|
||||
@@ -82,19 +85,20 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
competitors = new ArrayList<Competitor>();
|
||||
Util.addAll(getRace().getCompetitors(), competitors);
|
||||
competitorComparator = new NaturalNamedComparator();
|
||||
Collections.sort(competitors, competitorComparator);
|
||||
competitorsAdapter = new CompetitorsAdapter(getActivity(), R.layout.welter_grid_competitor_cell, competitors);
|
||||
|
||||
|
||||
loadCompetitors();
|
||||
|
||||
|
||||
positionedCompetitors = initializeFinishPositioningList();
|
||||
deletePositionedCompetitorsFromUnpositionedList();
|
||||
positioningAdapter = new CompetitorPositioningListAdapter(getActivity(), R.layout.welter_positioning_item, positionedCompetitors);
|
||||
|
||||
positioningAdapter = new CompetitorPositioningListAdapter(getActivity(), R.layout.welter_positioning_item,
|
||||
positionedCompetitors);
|
||||
|
||||
positioningListView = (DragSortListView) getView().findViewById(R.id.dragSortListPositioning);
|
||||
positioningListView.setAdapter(positioningAdapter);
|
||||
positioningListView.setDropListener(new DragSortListView.DropListener() {
|
||||
@@ -108,9 +112,9 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
positioningListView.setRemoveListener(new DragSortListView.RemoveListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void remove(int toBeRemoved) {
|
||||
Triple<Serializable, String, MaxPointsReason> item = positioningAdapter.getItem(toBeRemoved);
|
||||
@@ -124,9 +128,9 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
public boolean onItemLongClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
|
||||
createMaxPointsReasonSelectionDialog(positionedCompetitors.get(position));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
dragSortController = buildDragSortController(positioningListView);
|
||||
positioningListView.setFloatViewManager(dragSortController);
|
||||
positioningListView.setOnTouchListener(dragSortController);
|
||||
@@ -139,18 +143,13 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
|
||||
public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
|
||||
Competitor competitor = (Competitor) competitorsAdapter.getItem(position);
|
||||
ExLog.i("RaceFinishingFragment", "Grid is clicked at position " + position + " for competitor " + competitor.getName());
|
||||
ExLog.i("RaceFinishingFragment", "Grid is clicked at position " + position + " for competitor "
|
||||
+ competitor.getName());
|
||||
onCompetitorClickedOnGrid(competitor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
onLoadCompetitorsSucceeded(getRace().getCompetitors());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a DragSortController and thereby defines the behaviour of the drag sort list
|
||||
*/
|
||||
@@ -167,37 +166,57 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
|
||||
private void loadCompetitors() {
|
||||
getActivity().setProgressBarIndeterminateVisibility(true);
|
||||
ReadonlyDataManager dataManager = OnlineDataManager.create(getActivity());
|
||||
Loader<?> competitorLoaders = getLoaderManager().initLoader(0, null,
|
||||
dataManager.createCompetitorsLoader(getRace(), new LoadClient<Collection<Competitor>>() {
|
||||
|
||||
OnlineDataManager.create(getActivity()).loadCompetitors(getRace(), new LoadClient<Collection<Competitor>>() {
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
getActivity().setProgressBarIndeterminateVisibility(false);
|
||||
Toast.makeText(getActivity(), String.format("Competitors: %s", reason.toString()),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadFailed(Exception reason) {
|
||||
onLoadCompetitorsSucceeded(getRace().getCompetitors());
|
||||
}
|
||||
@Override
|
||||
public void onLoadSucceded(Collection<Competitor> data, boolean isCached) {
|
||||
if (!isCached) {
|
||||
getActivity().setProgressBarIndeterminateVisibility(false);
|
||||
}
|
||||
onLoadCompetitorsSucceeded(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoadSucceded(Collection<Competitor> data) {
|
||||
onLoadCompetitorsSucceeded(data);
|
||||
}
|
||||
|
||||
});
|
||||
}));
|
||||
// Force load to get non-cached remote competitors...
|
||||
competitorLoaders.forceLoad();
|
||||
}
|
||||
|
||||
protected void onLoadCompetitorsSucceeded(Collection<Competitor> data) {
|
||||
competitors.clear();
|
||||
competitors.addAll(data);
|
||||
Collections.sort(competitors, competitorComparator);
|
||||
deleteObsoleteCompetitorsFromPositionedList(data);
|
||||
deletePositionedCompetitorsFromUnpositionedList();
|
||||
competitorsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void deleteObsoleteCompetitorsFromPositionedList(Collection<Competitor> validCompetitors) {
|
||||
List<Triple<Serializable, String, MaxPointsReason>> toBeDeleted = new ArrayList<Util.Triple<Serializable, String, MaxPointsReason>>();
|
||||
for (Triple<Serializable, String, MaxPointsReason> positionedItem : positionedCompetitors) {
|
||||
if (!validCompetitors.contains(DomainFactoryImpl.INSTANCE.getExistingCompetitorById(positionedItem.getA()))) {
|
||||
toBeDeleted.add(positionedItem);
|
||||
}
|
||||
}
|
||||
positionedCompetitors.removeAll(toBeDeleted);
|
||||
}
|
||||
|
||||
private void deletePositionedCompetitorsFromUnpositionedList() {
|
||||
for (Triple<Serializable, String, MaxPointsReason> positionedItem : positionedCompetitors) {
|
||||
Competitor competitor = DomainFactoryImpl.INSTANCE.getExistingCompetitorById(positionedItem.getA());
|
||||
competitors.remove(competitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<Triple<Serializable, String, MaxPointsReason>> initializeFinishPositioningList() {
|
||||
List<Triple<Serializable, String, MaxPointsReason>> positionings;
|
||||
if (getRace().getState().getFinishPositioningList() != null) {
|
||||
@@ -207,7 +226,7 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
return positionings;
|
||||
}
|
||||
|
||||
|
||||
private void setItemToNewPositioning(int from, int to, Triple<Serializable, String, MaxPointsReason> item) {
|
||||
positioningAdapter.remove(item);
|
||||
positioningAdapter.insert(item, to);
|
||||
@@ -216,16 +235,16 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
private void createMaxPointsReasonSelectionDialog(final Triple<Serializable, String, MaxPointsReason> item) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
final CharSequence[] maxPointsReasons = getAllMaxPointsReasons();
|
||||
builder.setTitle(R.string.select_penalty_reason)
|
||||
.setItems(maxPointsReasons, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int position) {
|
||||
setMaxPointsReasonForItem(item, maxPointsReasons[position]);
|
||||
}
|
||||
});
|
||||
builder.setTitle(R.string.select_penalty_reason).setItems(maxPointsReasons,
|
||||
new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int position) {
|
||||
setMaxPointsReasonForItem(item, maxPointsReasons[position]);
|
||||
}
|
||||
});
|
||||
builder.create();
|
||||
builder.show();
|
||||
}
|
||||
|
||||
|
||||
private CharSequence[] getAllMaxPointsReasons() {
|
||||
List<CharSequence> result = new ArrayList<CharSequence>();
|
||||
for (MaxPointsReason reason : MaxPointsReason.values()) {
|
||||
@@ -234,19 +253,22 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
return result.toArray(new CharSequence[result.size()]);
|
||||
}
|
||||
|
||||
protected void setMaxPointsReasonForItem(Triple<Serializable, String, MaxPointsReason> item, CharSequence maxPointsReasonName) {
|
||||
protected void setMaxPointsReasonForItem(Triple<Serializable, String, MaxPointsReason> item,
|
||||
CharSequence maxPointsReasonName) {
|
||||
MaxPointsReason maxPointsReason = MaxPointsReason.valueOf(maxPointsReasonName.toString());
|
||||
Triple<Serializable, String, MaxPointsReason> newItem = new Triple<Serializable, String, MaxPointsReason>(item.getA(), item.getB(), maxPointsReason);
|
||||
Triple<Serializable, String, MaxPointsReason> newItem = new Triple<Serializable, String, MaxPointsReason>(
|
||||
item.getA(), item.getB(), maxPointsReason);
|
||||
int currentIndexOfItem = positionedCompetitors.indexOf(item);
|
||||
replaceItemInPositioningList(currentIndexOfItem, item, newItem);
|
||||
|
||||
|
||||
if (!maxPointsReason.equals(MaxPointsReason.NONE)) {
|
||||
setCompetitorToBottomOfPositioningList(newItem);
|
||||
}
|
||||
getRace().getState().setFinishPositioningListChanged(positionedCompetitors);
|
||||
}
|
||||
|
||||
private void replaceItemInPositioningList(int currentIndexOfItem, Triple<Serializable, String, MaxPointsReason> item, Triple<Serializable, String, MaxPointsReason> newItem) {
|
||||
private void replaceItemInPositioningList(int currentIndexOfItem,
|
||||
Triple<Serializable, String, MaxPointsReason> item, Triple<Serializable, String, MaxPointsReason> newItem) {
|
||||
positioningAdapter.remove(item);
|
||||
positioningAdapter.insert(newItem, currentIndexOfItem);
|
||||
}
|
||||
@@ -270,24 +292,25 @@ public class PositioningFragment extends RaceDialogFragment {
|
||||
}
|
||||
|
||||
private void addNewCompetitorToPositioningList(Competitor competitor) {
|
||||
|
||||
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor.getId(), competitor.getName(), MaxPointsReason.NONE));
|
||||
|
||||
positionedCompetitors.add(new Triple<Serializable, String, MaxPointsReason>(competitor.getId(), competitor
|
||||
.getName(), MaxPointsReason.NONE));
|
||||
positioningAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
protected void onCompetitorRemovedFromPositioningList(Triple<Serializable, String, MaxPointsReason> item) {
|
||||
Competitor competitor = DomainFactoryImpl.INSTANCE.getExistingCompetitorById(item.getA());
|
||||
addNewCompetitorToCompetitorList(competitor);
|
||||
removeCompetitorFromPositionings(item);
|
||||
getRace().getState().setFinishPositioningListChanged(positionedCompetitors);
|
||||
}
|
||||
|
||||
|
||||
private void addNewCompetitorToCompetitorList(Competitor competitor) {
|
||||
competitors.add(competitor);
|
||||
Collections.sort(competitors, competitorComparator);
|
||||
competitorsAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
|
||||
protected void removeCompetitorFromPositionings(Triple<Serializable, String, MaxPointsReason> item) {
|
||||
positionedCompetitors.remove(item);
|
||||
positioningAdapter.notifyDataSetChanged();
|
||||
|
||||
+3
-3
@@ -28,7 +28,7 @@ import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
|
||||
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
|
||||
import com.sap.sailing.racecommittee.app.domain.impl.BoatClassSeriesFleet;
|
||||
|
||||
public class ProtestTimeDialogFragment extends BaseDialogFragment {
|
||||
public class ProtestTimeDialogFragment extends AttachedDialogFragment {
|
||||
|
||||
private static String ARGS_RACE_IDS = ProtestTimeDialogFragment.class.getSimpleName() + ".raceids";
|
||||
|
||||
@@ -84,12 +84,12 @@ public class ProtestTimeDialogFragment extends BaseDialogFragment {
|
||||
public DialogResultListener getListener() {
|
||||
return new DialogResultListener() {
|
||||
@Override
|
||||
public void onDialogNegativeButton(BaseDialogFragment dialog) {
|
||||
public void onDialogNegativeButton(AttachedDialogFragment dialog) {
|
||||
// no operation
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogPositiveButton(BaseDialogFragment dialog) {
|
||||
public void onDialogPositiveButton(AttachedDialogFragment dialog) {
|
||||
setAndAnnounceProtestTime();
|
||||
}
|
||||
};
|
||||
|
||||
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user