Merge remote-tracking branch 'server/bug4240_4232'

This commit is contained in:
Axel Uhl committed 2017-10-13 18:27:39 +02:00
commit 339afab28c
92 files changed
+1247 -569

No files matched your search

@@ -2,19 +2,25 @@ package com.sap.sailing.domain.racelog.analyzing.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.ConfirmedFinishPositioningListFinder;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sse.common.Util;
public class ConfirmedFinishPositioningListFinderTest extends
PassAwareRaceLogAnalyzerTest<ConfirmedFinishPositioningListFinder, CompetitorResults> {
@@ -27,9 +33,17 @@ public class ConfirmedFinishPositioningListFinderTest extends
@Override
protected TargetPair getTargetEventsAndResultForPassAwareTests(int passId, AbstractLogEventAuthor author) {
RaceLogFinishPositioningConfirmedEvent event = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1, passId, author);
when(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(CompetitorResults.class));
when(event.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mockCompetitorResults());
return new TargetPair(Arrays.asList(event), event.getPositionedCompetitorsIDsNamesMaxPointsReasons());
}
private CompetitorResults mockCompetitorResults(CompetitorResult... results) {
final CompetitorResultsImpl result = new CompetitorResultsImpl();
for (final CompetitorResult r : results) {
result.add(r);
}
return result;
}
@Test
public void testNullForNone() {
@@ -42,11 +56,58 @@ public class ConfirmedFinishPositioningListFinderTest extends
public void testMostRecent() {
RaceLogFinishPositioningConfirmedEvent event1 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 1);
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(RaceLogFinishPositioningConfirmedEvent.class, 2);
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(mock(CompetitorResults.class));
final CompetitorResultImpl oldResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.NONE, 1.0, /* finishing time */ null, /* comment */ null);
final CompetitorResultImpl oldResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults olderResults = mockCompetitorResults(oldResultC1, oldResultC2);
final CompetitorResultImpl newResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults newerResults = mockCompetitorResults(newResultC2);
when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(olderResults);
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(newerResults);
raceLog.add(event1);
raceLog.add(event2);
assertCompetitorResultsEquals(mockCompetitorResults(oldResultC1, newResultC2), analyzer.analyze());
}
@Test
public void testMixtureOfPartialResultsOfDifferentPriority() {
RaceLogFinishPositioningConfirmedEvent event1 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 1);
RaceLogFinishPositioningConfirmedEvent event2 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 2);
RaceLogFinishPositioningConfirmedEvent event3 = createEvent(/* priority */ 2, RaceLogFinishPositioningConfirmedEvent.class, 3);
RaceLogFinishPositioningConfirmedEvent event4 = createEvent(/* priority */ 1, RaceLogFinishPositioningConfirmedEvent.class, 4);
final CompetitorResultImpl e1ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, MaxPointsReason.DNC, 6.0, /* finishing time */ null, /* comment */ null);
final CompetitorResultImpl e1ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.NONE, 2.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults e1Results = mockCompetitorResults(e1ResultC1, e1ResultC2);
final CompetitorResultImpl e2ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults e2Results = mockCompetitorResults(e2ResultC2);
final CompetitorResultImpl e3ResultC2 = new CompetitorResultImpl("Comp2", "Comp 2", 2, MaxPointsReason.DSQ, 6.0, /* finishing time */ null, /* comment */ null);
final CompetitorResultImpl e3ResultC3 = new CompetitorResultImpl("Comp3", "Comp 3", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults e3Results = mockCompetitorResults(e3ResultC2, e3ResultC3);
final CompetitorResultImpl e4ResultC1 = new CompetitorResultImpl("Comp1", "Comp 1", 1, /* maxPointsReason */ null, /* score */ null, /* finishing time */ null, /* comment */ null);
final CompetitorResultImpl e4ResultC4 = new CompetitorResultImpl("Comp4", "Comp 4", 2, MaxPointsReason.DNF, 3.0, /* finishing time */ null, /* comment */ null);
final CompetitorResults e4Results = mockCompetitorResults(e4ResultC1, e4ResultC4);
when(event1.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e1Results);
when(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e2Results);
when(event3.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e3Results);
when(event4.getPositionedCompetitorsIDsNamesMaxPointsReasons()).thenReturn(e4Results);
// insert in more or less random order
raceLog.add(event4);
raceLog.add(event2);
raceLog.add(event1);
raceLog.add(event3);
// e1ResultC1 is expected to be overruled by e4ResultC1 because the latter has the same priority and comes later
// e1ResultC2 is expected to be overruled by e2ResultC2 due to same priority but later time; and e3ResultC2 has less priority
// e3ResultC3 and e4ResultC4 stand by themselves; they are not overruled by anything
assertCompetitorResultsEquals(mockCompetitorResults(e4ResultC1, e2ResultC2, e3ResultC3, e4ResultC4), analyzer.analyze());
}
assertEquals(event2.getPositionedCompetitorsIDsNamesMaxPointsReasons(), analyzer.analyze());
/**
* Results are considered equal if they contain equal sets of {@link CompetitorResult}s.
*/
private void assertCompetitorResultsEquals(CompetitorResults o1, CompetitorResults o2) {
Set<CompetitorResult> o1Results = new HashSet<>();
Util.addAll(o1, o1Results);
Set<CompetitorResult> o2Results = new HashSet<>();
Util.addAll(o2, o2Results);
assertEquals(o1Results, o2Results);
}
}
@@ -9,6 +9,7 @@ import java.util.UUID;
import org.junit.Before;
import com.sap.sailing.domain.abstractlog.AbstractLogEventAuthor;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.RaceLogAnalyzer;
@@ -29,7 +30,11 @@ public abstract class RaceLogAnalyzerTest<AnalyzerType extends RaceLogAnalyzer<?
protected abstract AnalyzerType createAnalyzer(RaceLog raceLog);
protected static <T extends RaceLogEvent> T createEvent(Class<T> type, long milliseconds) {
return createEvent(type, milliseconds, 0, UUID.randomUUID());
return createEvent(/* priority */ 0, type, milliseconds);
}
protected static <T extends RaceLogEvent> T createEvent(int priority, Class<T> type, long milliseconds) {
return createEvent(priority, type, milliseconds, 0, UUID.randomUUID());
}
protected static <T extends RaceLogEvent> T createEvent(Class<T> type, long milliseconds, Serializable id) {
@@ -41,7 +46,12 @@ public abstract class RaceLogAnalyzerTest<AnalyzerType extends RaceLogAnalyzer<?
}
protected static <T extends RaceLogEvent> T createEvent(Class<T> type, long milliseconds, int passId, Serializable id) {
return createEvent(type, milliseconds, passId, id, mock(AbstractLogEventAuthor.class));
return createEvent(/* priority */ 0, type, milliseconds, passId, id);
}
protected static <T extends RaceLogEvent> T createEvent(int priority, Class<T> type, long milliseconds, int passId, Serializable id) {
final AbstractLogEventAuthor author = new LogEventAuthorImpl("Author", priority);
return createEvent(type, milliseconds, passId, id, author);
}
protected static <T extends RaceLogEvent> T createEvent(Class<T> type, long milliseconds, int passId, AbstractLogEventAuthor author) {
@@ -7,4 +7,13 @@ package com.sap.sailing.domain.abstractlog.race;
*/
public interface CompetitorResults extends Iterable<CompetitorResult> {
boolean add(CompetitorResult result);
/**
* @return {@code true} if there are more than one {@link CompetitorResult} contained with equal
* {@link CompetitorResult#getOneBasedRank() rank}. A client can take this as an indicator that
* there may be an inconsistency, caused, e.g., by merging results entered on different devices
* concurrently. The client shall use the {@link #iterator()} method to enumerate the
* {@link CompetitorResult} objects, finding the conflicting elements.
*/
boolean hasConflicts();
}
@@ -0,0 +1,60 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningEvent;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
/**
* Fetches competitor results from the current pass in a {@link RaceLog}. Results may be provided in multiple, partial
* race log events, all of potentially different priority, with time stamps and potential overlaps, providing different
* results for the same competitor at different times, with different priorities. This finder merges all these results
* from the current pass and prefers higher priorities (numerically less) over lower priorities (numerically greater),
* and later results over earlier results with equal priority. It can therefore rely on the order in which race log
* events are produced by {@link #getPassEventsDescending()}.<p>
*
* The analyzer will return {@code null} if no result has been found at all.
*
* @author Axel Uhl (D043530)
*
*/
public class AbstractFinishPositioningListFinder extends RaceLogAnalyzer<CompetitorResults> {
/**
* The type of event we're looking for in the log
*/
private final Class<? extends RaceLogFinishPositioningEvent> clz;
public AbstractFinishPositioningListFinder(RaceLog raceLog, Class<? extends RaceLogFinishPositioningEvent> clz) {
super(raceLog);
this.clz = clz;
}
@Override
protected CompetitorResults performAnalysis() {
boolean resultFound = false;
final Map<Serializable, CompetitorResult> resultsByCompetitor = new HashMap<>();
for (RaceLogEvent event : getPassEventsDescending()) {
if (clz.isInstance(event)) {
RaceLogFinishPositioningEvent finishPositioningEvent = (RaceLogFinishPositioningEvent) event;
final CompetitorResults positionedCompetitorsIDsNamesMaxPointsReasons = finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
if (positionedCompetitorsIDsNamesMaxPointsReasons != null) {
resultFound = true;
for (final CompetitorResult r : positionedCompetitorsIDsNamesMaxPointsReasons) {
if (!resultsByCompetitor.containsKey(r.getCompetitorId())) {
resultsByCompetitor.put(r.getCompetitorId(), r);
}
}
}
}
}
final CompetitorResultsImpl result = new CompetitorResultsImpl();
result.addAll(resultsByCompetitor.values());
return resultFound ? result : null;
}
}
@@ -1,24 +1,10 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningConfirmedEvent;
public class ConfirmedFinishPositioningListFinder extends RaceLogAnalyzer<CompetitorResults> {
public class ConfirmedFinishPositioningListFinder extends AbstractFinishPositioningListFinder {
public ConfirmedFinishPositioningListFinder(RaceLog raceLog) {
super(raceLog);
}
@Override
protected CompetitorResults performAnalysis() {
for (RaceLogEvent event : getPassEventsDescending()) {
if (event instanceof RaceLogFinishPositioningConfirmedEvent) {
RaceLogFinishPositioningConfirmedEvent finishPositioningEvent = (RaceLogFinishPositioningConfirmedEvent) event;
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
}
}
return null;
super(raceLog, RaceLogFinishPositioningConfirmedEvent.class);
}
}
@@ -1,25 +1,10 @@
package com.sap.sailing.domain.abstractlog.race.analyzing.impl;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.RaceLogEvent;
import com.sap.sailing.domain.abstractlog.race.RaceLogFinishPositioningListChangedEvent;
public class FinishPositioningListFinder extends RaceLogAnalyzer<CompetitorResults> {
public class FinishPositioningListFinder extends AbstractFinishPositioningListFinder {
public FinishPositioningListFinder(RaceLog raceLog) {
super(raceLog);
}
@Override
protected CompetitorResults performAnalysis() {
for (RaceLogEvent event : getPassEventsDescending()) {
if (event instanceof RaceLogFinishPositioningListChangedEvent) {
RaceLogFinishPositioningListChangedEvent finishPositioningEvent = (RaceLogFinishPositioningListChangedEvent) event;
return finishPositioningEvent.getPositionedCompetitorsIDsNamesMaxPointsReasons();
}
}
return null;
super(raceLog, RaceLogFinishPositioningListChangedEvent.class);
}
}
@@ -1,10 +1,26 @@
package com.sap.sailing.domain.abstractlog.race.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
public class CompetitorResultsImpl extends ArrayList<CompetitorResult> implements CompetitorResults {
private static final long serialVersionUID = 4928351242700897387L;
@Override
public boolean hasConflicts() {
final Set<Integer> oneBasedRanks = new HashSet<>();
for (final CompetitorResult r : this) {
final int oneBasedRank = r.getOneBasedRank();
if (oneBasedRank != 0) {
if (!oneBasedRanks.add(oneBasedRank)) {
return true;
}
}
}
return false;
}
}
@@ -4,6 +4,11 @@
<div id="mainContent">
<h4 class="articleHeadline">What's New - SAP Sailing Race Manager</h4>
<div class="innerContent">
<h5 class="articleSubheadline">August 2018</h5>
<ul class="bulletList">
<li>The result list can now be edited without a finish time.</li>
</ul>
<h5 class="articleSubheadline">June 2017</h5>
<ul class="bulletList">
<li>It is now possible to capture results during any phase of a race,
Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warning_yellow_36dp" />
</selector>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warning_yellow_24dp" />
</selector>
Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 533 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 279 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

@@ -4,6 +4,9 @@
<!-- pressed -->
<item android:drawable="@drawable/ic_delete_yellow_24dp" android:state_pressed="true" />
<!-- disabled -->
<item android:drawable="@drawable/ic_delete_grey_24dp" android:state_enabled="false" />
<!-- default -->
<item android:drawable="@drawable/ic_delete_black_24dp" />
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warning_yellow_24dp" />
</selector>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_warning_yellow_18dp" />
</selector>
@@ -44,15 +44,29 @@
android:layout_above="@id/panel_button_footer"
android:layout_below="@id/panel_button_header">
<ImageView
android:id="@+id/panel_image"
android:layout_width="@dimen/side_button_imageSize"
android:layout_height="@dimen/side_button_imageSize"
<RelativeLayout
android:id="@+id/panel_image_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerInParent="true"
android:visibility="gone"
tools:src="@drawable/flag_papa_64dp"
tools:visibility="gone" />
android:layout_centerInParent="true">
<ImageView
android:id="@+id/panel_image"
android:layout_width="@dimen/side_button_imageSize"
android:layout_height="@dimen/side_button_imageSize"
tools:src="@drawable/flag_papa_64dp" />
<ImageView
android:id="@+id/panel_additional_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/panel_image"
android:layout_alignRight="@id/panel_image"
android:visibility="gone"
tools:src="@drawable/ic_warning_yellow"
tools:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/panel_value"
@@ -81,7 +95,7 @@
android:track="@drawable/switch_track"
android:visibility="gone"
tools:targetApi="LOLLIPOP"
tools:visibility="visible" />
tools:visibility="gone" />
</RelativeLayout>
<FrameLayout
@@ -19,7 +19,7 @@
android:layout_height="wrap_content"
android:text="@string/finished_tracking"
android:textAppearance="?attr/textPanelHeader"
android:textSize="@dimen/textSize_18"/>
android:textSize="@dimen/textSize_18" />
<ImageView
android:id="@+id/list_lock"
@@ -38,14 +38,43 @@
android:layout_height="match_parent"
android:layout_below="@id/list">
<TextView
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:drawablePadding="@dimen/compound_padding"
android:drawableTop="?attr/dns"
android:gravity="center_horizontal"
android:text="@string/finished_edit"
android:textAppearance="?attr/textPanelCaption" />
android:layout_centerInParent="true">
<RelativeLayout
android:id="@+id/image_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<ImageView
android:id="@+id/list_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/compound_padding"
android:src="?attr/dns" />
<ImageView
android:id="@+id/panel_additional_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/list_icon"
android:layout_alignRight="@id/list_icon"
android:src="@drawable/ic_warning_yellow_small"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/image_layout"
android:gravity="center_horizontal"
android:text="@string/finished_edit"
android:textAppearance="?attr/textPanelCaption" />
</RelativeLayout>
</RelativeLayout>
</merge>
@@ -13,13 +13,26 @@
android:layout_centerVertical="true"
android:orientation="vertical">
<ImageView
android:id="@+id/protest_image"
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
tools:src="@drawable/flag_bravo_48dp" />
android:layout_height="wrap_content">
<ImageView
android:id="@+id/protest_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/default_margin"
android:layout_marginRight="@dimen/default_margin"
tools:src="@drawable/flag_bravo_48dp" />
<ImageView
android:id="@+id/protest_warning_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/ic_warning_yellow"
android:visibility="gone"/>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/navigation_drawer_cell_height">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="@dimen/navigation_drawer_cell_height">
<RelativeLayout
android:id="@+id/panel_right"
@@ -24,7 +24,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="?attr/textXLarge"
tools:text="13:36"/>
tools:text="13:36" />
<TextView
android:id="@+id/race_started"
@@ -32,7 +32,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_started"
android:textAppearance="?attr/textXSmall"/>
android:textAppearance="?attr/textXSmall" />
<TextView
android:id="@+id/race_finished"
@@ -40,7 +40,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_finished"
android:textAppearance="?attr/textXSmall"/>
android:textAppearance="?attr/textXSmall" />
</LinearLayout>
<TextView
@@ -51,7 +51,7 @@
android:text="@string/race_unscheduled"
android:textColor="?attr/sap_light_gray"
android:textSize="@dimen/textSize_18"
android:visibility="gone"/>
android:visibility="gone" />
<ImageView
android:id="@+id/update_badge"
@@ -62,7 +62,17 @@
android:scaleType="matrix"
android:src="@drawable/updated"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
<ImageView
android:id="@+id/panel_additional_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:visibility="gone"
android:layout_margin="2dp"
android:src="@drawable/ic_warning_yellow" />
</RelativeLayout>
<RelativeLayout
@@ -76,7 +86,7 @@
android:id="@+id/race_marker"
android:layout_width="@dimen/obesity_line"
android:layout_height="match_parent"
android:src="?attr/marker_race"/>
android:src="?attr/marker_race" />
<LinearLayout
android:id="@+id/additional_info"
@@ -93,7 +103,7 @@
android:layout_margin="5dp"
android:src="?attr/link_24dp"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
<LinearLayout
android:id="@+id/race_flag"
@@ -110,7 +120,7 @@
android:layout_height="25dp"
android:layout_gravity="center"
android:scaleType="centerInside"
tools:src="@drawable/flag_alpha_64dp"/>
tools:src="@drawable/flag_alpha_64dp" />
<TextView
android:id="@+id/flag_timer"
@@ -119,7 +129,7 @@
android:layout_gravity="center"
android:drawableLeft="?attr/arrow_down"
android:textAppearance="?attr/textXSmall"
tools:text="01:12"/>
tools:text="01:12" />
</LinearLayout>
</LinearLayout>
@@ -141,7 +151,7 @@
android:ellipsize="middle"
android:maxLines="1"
android:textAppearance="?attr/textNormal"
tools:text="Race 3"/>
tools:text="Race 3" />
<TextView
android:id="@+id/depends_on"
@@ -152,7 +162,7 @@
android:textAppearance="?attr/textXSmall"
android:visibility="gone"
tools:text="5 minutes after ABC"
tools:visibility="visible"/>
tools:visibility="visible" />
</LinearLayout>
</RelativeLayout>
@@ -164,11 +174,11 @@
android:background="?attr/factor_background"
android:textAppearance="?attr/textXSmall"
android:textColor="?attr/white_invert"
tools:text="x 3.5"/>
tools:text="x 3.5" />
<ImageView
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:background="?attr/black"/>
android:background="?attr/black" />
</RelativeLayout>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout
android:id="@+id/race_content_header"
@@ -33,14 +33,14 @@
android:singleLine="true"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_header_size"
tools:text="@string/time"/>
tools:text="@string/time" />
<ImageView
android:id="@+id/time_marker"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:src="?attr/marker"/>
android:src="?attr/marker" />
<RelativeLayout
android:layout_width="wrap_content"
@@ -65,7 +65,7 @@
android:layout_toRightOf="@+id/linked_locked_area"
android:textColor="?attr/white"
android:textSize="@dimen/panel_button_caption_size"
tools:text="@string/time_start"/>
tools:text="@string/time_start" />
<LinearLayout
android:id="@+id/linked_locked_area"
@@ -81,7 +81,7 @@
android:layout_height="@dimen/side_button_lockSize"
android:src="?attr/lock_outline"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
<ImageView
android:id="@+id/linked_race"
@@ -90,7 +90,7 @@
android:layout_gravity="center_vertical"
android:src="?attr/link_24dp"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
</LinearLayout>
</RelativeLayout>
@@ -114,7 +114,7 @@
android:textSize="@dimen/panel_button_caption_size"
android:visibility="invisible"
tools:text="@string/time"
tools:visibility="visible"/>
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>
@@ -126,13 +126,14 @@
android:layout_height="match_parent"
android:layout_weight="10"
android:visibility="gone"
app:buttonAdditionalImage="@drawable/ic_warning_yellow_24dp"
app:buttonCaption="@string/competitor_list"
app:buttonImage="?attr/competitor_list"
app:buttonType="typeImage"
app:captionPosition="bottom"
app:imageSize="48dp"
app:linePosition="left"
tools:visibility="visible"/>
tools:visibility="visible" />
</LinearLayout>
</com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout>
</RelativeLayout>
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout
android:id="@+id/race_content_header"
@@ -29,14 +29,14 @@
android:gravity="center"
android:textColor="?attr/white"
android:textSize="@dimen/textSize_40"
tools:text="@string/time"/>
tools:text="@string/time" />
<ImageView
android:id="@+id/time_marker"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:src="?attr/marker"/>
android:src="?attr/marker" />
<RelativeLayout
android:layout_width="wrap_content"
@@ -59,7 +59,7 @@
android:layout_centerVertical="true"
android:layout_toRightOf="@+id/linked_locked_area"
android:textAppearance="?attr/textSmall"
tools:text="@string/time_start"/>
tools:text="@string/time_start" />
<LinearLayout
android:id="@+id/linked_locked_area"
@@ -75,7 +75,7 @@
android:layout_height="wrap_content"
android:src="?attr/lock_outline"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
<ImageView
android:id="@+id/linked_race"
@@ -84,7 +84,7 @@
android:layout_gravity="center_vertical"
android:src="?attr/link_24dp"
android:visibility="gone"
tools:visibility="visible"/>
tools:visibility="visible" />
</LinearLayout>
</RelativeLayout>
@@ -107,7 +107,7 @@
android:textAppearance="?attr/textSmall"
android:visibility="invisible"
tools:text="@string/time"
tools:visibility="visible"/>
tools:visibility="visible" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
@@ -118,13 +118,14 @@
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="gone"
app:buttonAdditionalImage="@drawable/ic_warning_yellow_36dp"
app:buttonCaption="@string/competitor_list"
app:buttonImage="?attr/competitor_list"
app:buttonType="typeImage"
app:captionPosition="bottom"
app:imageSize="64dp"
app:linePosition="left"
tools:visibility="visible"/>
tools:visibility="visible" />
</LinearLayout>
</com.sap.sailing.racecommittee.app.ui.layouts.TimePanelHeaderLayout>
</RelativeLayout>
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingRight="24dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="24dp"
android:paddingRight="24dp">
<LinearLayout
android:id="@+id/competitor_position_layout"
@@ -19,14 +19,14 @@
android:layout_gravity="center"
android:layout_weight="1"
android:text="@string/position"
android:textColor="@color/dialog_color_text"/>
android:textColor="@color/dialog_color_text" />
<Spinner
android:id="@+id/competitor_position"
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:background="@drawable/spinner_background_light"
android:spinnerMode="dropdown"/>
android:spinnerMode="dropdown" />
</LinearLayout>
<LinearLayout
@@ -42,7 +42,7 @@
android:layout_gravity="center"
android:layout_weight="1"
android:text="@string/penalty"
android:textColor="@color/dialog_color_text"/>
android:textColor="@color/dialog_color_text" />
<Spinner
android:id="@+id/competitor_penalty"
@@ -51,7 +51,7 @@
android:layout_marginBottom="@dimen/side_padding"
android:layout_marginTop="@dimen/side_padding"
android:background="@drawable/spinner_background_light"
android:spinnerMode="dropdown"/>
android:spinnerMode="dropdown" />
</LinearLayout>
<LinearLayout
@@ -67,83 +67,78 @@
android:layout_gravity="center"
android:layout_weight="1"
android:text="@string/score"
android:textColor="@color/dialog_color_text"/>
android:textColor="@color/dialog_color_text" />
<EditText
android:id="@+id/competitor_score"
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:inputType="numberDecimal"
android:textColor="?attr/white"/>
android:textColor="?attr/white" />
</LinearLayout>
<LinearLayout
android:id="@+id/competitor_finish_date_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:text="@string/finishing_date"
android:textColor="@color/dialog_color_text"/>
<Spinner
android:id="@+id/competitor_finish_date"
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/side_padding"
android:layout_marginTop="@dimen/side_padding"
android:background="@drawable/spinner_background_light"
android:spinnerMode="dropdown"/>
</LinearLayout>
<LinearLayout
<RelativeLayout
android:id="@+id/competitor_finish_time_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/competitor_finish_time_input"
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:orientation="horizontal">
<TextView
android:id="@+id/competitor_finish_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/editTextBackground"
android:gravity="center_vertical"
android:inputType="none"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="?attr/white" />
<TextView
android:id="@+id/competitor_finish_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/default_margin_half"
android:layout_weight="1"
android:background="?attr/editTextBackground"
android:gravity="center_vertical"
android:inputType="none"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="?attr/white" />
<FrameLayout
android:id="@+id/competitor_finish_date_delete"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_delete_24dp" />
</FrameLayout>
</LinearLayout>
<TextView
android:id="@+id/competitor_finish_time_label"
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_gravity="center"
android:layout_weight="1"
android:layout_toLeftOf="@id/competitor_finish_time_input"
android:maxLines="2"
android:text="@string/finishing_time"
android:textColor="@color/dialog_color_text"/>
<LinearLayout
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:orientation="horizontal">
<NumberPicker
android:id="@+id/competitor_finish_time_hours"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<NumberPicker
android:id="@+id/competitor_finish_time_minutes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"/>
<NumberPicker
android:id="@+id/competitor_finish_time_seconds"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
</LinearLayout>
android:textColor="@color/dialog_color_text" />
</RelativeLayout>
<LinearLayout
android:id="@+id/competitor_comment_layout"
@@ -158,13 +153,13 @@
android:layout_gravity="center"
android:layout_weight="1"
android:text="@string/comment"
android:textColor="@color/dialog_color_text"/>
android:textColor="@color/dialog_color_text" />
<EditText
android:id="@+id/competitor_comment"
android:layout_width="@dimen/competitor_edit_width"
android:layout_height="wrap_content"
android:inputType="text"
android:textColor="?attr/white"/>
android:textColor="?attr/white" />
</LinearLayout>
</LinearLayout>
@@ -8,6 +8,7 @@
android:paddingRight="24dp">
<LinearLayout
android:id="@+id/competitor_position_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -76,29 +77,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/competitor_finish_date_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="@dimen/float_label_padding"
android:paddingTop="@dimen/side_padding">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="8dp"
android:text="@string/finishing_date"
android:textColor="@color/dialog_color_text"/>
<Spinner
android:id="@+id/competitor_finish_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/spinner_background_light"
android:spinnerMode="dropdown"/>
</LinearLayout>
<LinearLayout
android:id="@+id/competitor_finish_time_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -109,40 +88,55 @@
android:id="@+id/competitor_finish_time_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:paddingBottom="8dp"
android:text="@string/finishing_time"
android:textColor="@color/dialog_color_text"/>
<LinearLayout
android:layout_width="@dimen/competitor_edit_width"
android:id="@+id/competitor_finish_time_input"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<NumberPicker
android:id="@+id/competitor_finish_time_hours"
<TextView
android:id="@+id/competitor_finish_date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/side_padding"
android:layout_weight="1"/>
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:background="?attr/editTextBackground"
android:gravity="center_vertical"
android:inputType="none"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="?attr/white" />
<NumberPicker
android:id="@+id/competitor_finish_time_minutes"
<TextView
android:id="@+id/competitor_finish_time"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/side_padding"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="@dimen/side_padding"
android:layout_weight="1"/>
android:layout_gravity="center_vertical"
android:layout_marginLeft="@dimen/default_margin_half"
android:layout_weight="1"
android:background="?attr/editTextBackground"
android:gravity="center_vertical"
android:inputType="none"
android:textAppearance="?android:attr/textAppearanceMediumInverse"
android:textColor="?attr/white" />
<NumberPicker
android:id="@+id/competitor_finish_time_seconds"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/side_padding"
android:layout_weight="1"/>
<FrameLayout
android:id="@+id/competitor_finish_date_delete"
android:layout_width="42dp"
android:layout_height="42dp"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_delete_24dp" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<NumberPicker
android:id="@+id/picker_hour"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants" />
<NumberPicker
android:id="@+id/picker_minute"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:descendantFocusability="blocksDescendants" />
<NumberPicker
android:id="@+id/picker_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants" />
</LinearLayout>
@@ -192,8 +192,8 @@
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<string name="choose_xray_flag_down">Einzelrückruf entfernen</string>
<string name="login_type_officer_on_start_vessel">Als Startschiff-Wettfahrtleiter anmelden</string>
<string name="login_type_officer_on_finish_vessel">Als Zielschiff-Wettfahrtleiter anmelden</string>
<string name="login_type_superuser">Als Superuser anmelden</string>
<string name="login_type_officer_on_vessel">Als Wettfahrtleiter auf dem Boot anmelden</string>
<string name="login_type_shore_control">Als Regattaleitung an Land anmelden</string>
<string name="gate_launch_stops_after">Gate Launch stoppt nach %dmin</string>
<string name="override_default_course_designer_type_select_header">Kursdesigner</string>
@@ -425,10 +425,10 @@
<string name="error_wrong_degree_value_title">Fehler</string>
<string name="error_wrong_degree_value_message">Bitte geben Sie einen Wert zwischen 0 und 360 an.</string>
<string name="author_type_officer_start">Startschiff-Wettfahrtleiter</string>
<string name="author_type_officer_finish">Zielschiff-Wettfahrtleiter</string>
<string name="author_type_officer_vessel">Wettfahrtleiter auf Wasser</string>
<string name="author_type_shore_control">Regattaleitung an Land</string>
<string name="author_viewer">Demo-Modus</string>
<string name="author_type_superuser">Superuser</string>
<string name="change_proceed">fortfahren</string>
<string name="change_cancel">Abbrechen</string>
<string name="change_message">Nach den Wettfahrtregeln sind diese Daten im aktuellen Rennenstatus nicht veränderbar.\nSie könnten jedoch die falschen Eingaben korrigieren.</string>
@@ -17,6 +17,7 @@
</attr>
<attr name="buttonImage" format="reference" />
<attr name="buttonAdditionalImage" format="reference" />
<attr name="buttonValue" format="reference|string" />
<attr name="buttonSwitch" format="reference|string" />
@@ -32,7 +33,7 @@
<enum name="bottom" value="1" />
</attr>
<attr name="imageSize" format="reference|dimension"/>
<attr name="imageSize" format="reference|dimension" />
<attr name="showLock" format="boolean" />
</declare-styleable>
@@ -73,7 +73,8 @@
<dimen name="flags">64dp</dimen>
<dimen name="competitor_dialog_width">420dp</dimen>
<dimen name="competitor_edit_width">200dp</dimen>
<dimen name="competitor_edit_width">270dp</dimen>
<dimen name="competitor_edit_picker_width">200dp</dimen>
<dimen name="dialog_top_padding">24dp</dimen>
<dimen name="abort_dialog_height">215dp</dimen>
@@ -95,6 +96,7 @@
<dimen name="management_text_small">@dimen/textSize_18</dimen>
<dimen name="header_margin_top">13dp</dimen>
<dimen name="dialog_margin">24dp</dimen>
<dimen name="wind_input">55dp</dimen>
@@ -48,8 +48,8 @@
<string name="label_login_events">Regatta</string>
<string name="label_login_course_area">Area</string>
<string name="label_login_position">Position</string>
<string name="login_type_officer_on_start_vessel">Login as race officer on the selected course\'s start vessel.</string>
<string name="login_type_officer_on_finish_vessel">Login as race officer on the selected course\'s finish vessel.</string>
<string name="login_type_superuser">Login as super user</string>
<string name="login_type_officer_on_vessel">Login as race officer on a vessel.</string>
<string name="login_type_shore_control">Login as shore control.</string>
<string name="login_type_viewer">Login as view-only (demo mode) user.</string>
<string name="racelist_unscheduled">Not yet scheduled</string>
@@ -450,10 +450,10 @@
<string name="error_wrong_degree_value_title">Error</string>
<string name="error_wrong_degree_value_message">Please provide a value between 0 and 360</string>
<string name="author_type_officer_start">Race Officer on Start Vessel</string>
<string name="author_type_officer_finish">Race Officer on Finish Vessel</string>
<string name="author_type_officer_vessel">Race Officer on Vessel</string>
<string name="author_type_shore_control">Shore Control</string>
<string name="author_viewer">Viewer</string>
<string name="author_viewer">Demo Mode</string>
<string name="author_type_superuser">Super user</string>
<string name="change_proceed">Proceed</string>
<string name="change_cancel">Cancel</string>
<string name="change_message">According to the race rules this data is not changeable in the current\nrace state. You may proceed nevertheless to correct wrong inputs.</string>
@@ -17,6 +17,10 @@
<item name="android:windowNoTitle">false</item>
</style>
<style name="AppTheme.PickerDialog" parent="Theme.AppCompat.Light.Dialog">
<item name="colorAccent">@color/dialog_color_button</item>
</style>
<style name="AlertDialogHeader">
<item name="android:textAppearance">@style/TextAppearance.AppCompat.Title</item>
<item name="android:textColor">@color/dialog_color_header</item>
@@ -2,7 +2,7 @@
<resources>
<!-- Base application theme -->
<style name="AppTheme.Light" parent="AppTheme.Light.Base"/>
<style name="AppTheme.Light" parent="AppTheme.Light.Base" />
<style name="AppTheme.Light.Base" parent="AppTheme.Light.Custom">
<item name="windowActionModeOverlay">true</item>
@@ -13,10 +13,10 @@ public class AppConstants {
public final static String FLAG_KEY = PACKAGE_NAME + ".raceFlag";
public final static String EXTRA_FORCE_REFRESH = PACKAGE_NAME + ".forceRefresh";
public final static String AUTHOR_TYPE_OFFICER_START = "Race Officer on Start Vessel";
public final static String AUTHOR_TYPE_OFFICER_FINISH = "Race Officer on Finish Vessel";
public final static String AUTHOR_TYPE_OFFICER_VESSEL = "Race Officer on Vessel";
public final static String AUTHOR_TYPE_SHORE_CONTROL = "Shore Control";
public final static String AUTHOR_TYPE_VIEWER = "Viewer";
public final static String AUTHOR_TYPE_SUPERUSER = "Super User";
public final static String DARK_THEME = "dark";
public final static String LIGHT_THEME = "light";
@@ -41,8 +41,14 @@ public class AppConstants {
// Inner process events
public final static String INTENT_ACTION_TOGGLE = PACKAGE_NAME + ".action.toggle";
public final static String INTENT_ACTION_CLICK = PACKAGE_NAME + ".action.click";
public final static String INTENT_ACTION_EXTRA = PACKAGE_NAME + ".extra";
public final static String INTENT_ACTION_ON_LIFECYCLE = PACKAGE_NAME + ".action.on";
public final static String INTENT_ACTION_EXTRA = PACKAGE_NAME + ".action.extra";
public final static String INTENT_ACTION_EXTRA_FORCED = INTENT_ACTION_EXTRA + ".forced";
// Lifecycle events as extra
public final static String INTENT_ACTION_EXTRA_LIFECYCLE = INTENT_ACTION_EXTRA + ".lifecycle";
public final static String INTENT_ACTION_EXTRA_START = "start";
public final static String INTENT_ACTION_EXTRA_STOP = "stop";
public final static String INTENT_ACTION_TOGGLE_PROCEDURE = "procedure";
public final static String INTENT_ACTION_TOGGLE_PROCEDURE_MORE_MODE = "more_mode";
@@ -67,8 +73,6 @@ public class AppConstants {
public final static String INTENT_ACTION_TOGGLE_AREA = "area";
public final static String INTENT_ACTION_TOGGLE_POSITION = "position";
public final static String INTENT_ACTION_CLICK_COMPETITOR = "competitor";
private final static String INTENT_ACTION_TIME = PACKAGE_NAME + "action.time";
public final static String INTENT_ACTION_TIME_HIDE = INTENT_ACTION_TIME + ".hide";
public final static String INTENT_ACTION_TIME_SHOW = INTENT_ACTION_TIME + ".show";
@@ -23,6 +23,7 @@ import com.sap.sailing.domain.base.racegroup.RaceGroup;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeriesFleet;
import com.sap.sailing.domain.common.Wind;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.common.racelog.RacingProcedureType;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.AppPreferences;
import com.sap.sailing.racecommittee.app.R;
@@ -46,6 +47,7 @@ import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.BaseFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceFinishingFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceFlagViewerFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceSummaryFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.TrackingListFragment;
import com.sap.sailing.racecommittee.app.ui.views.PanelButton;
import com.sap.sailing.racecommittee.app.utils.PreferenceHelper;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
@@ -578,7 +580,17 @@ public class RacingActivity extends SessionActivity implements RaceListCallbacks
if (mSelectedRace.getStatus() != RaceLogRaceStatus.FINISHING) {
content = RaceFlagViewerFragment.newInstance();
} else {
content = RaceFinishingFragment.newInstance();
boolean forced = intent.getBooleanExtra(AppConstants.INTENT_ACTION_EXTRA_FORCED, false);
if (forced) {
content = RaceFinishingFragment.newInstance();
} else {
RacingProcedureType procedureType = mSelectedRace.getState().getRacingProcedure().getType();
if (preferences.getRacingProcedureIsResultEntryEnabled(procedureType)) {
content = TrackingListFragment.newInstance(args, 1);
} else {
content = RaceFinishingFragment.newInstance();
}
}
}
content.setArguments(args);
transaction.replace(R.id.race_content, content);
@@ -52,7 +52,7 @@ public class PenaltyAdapter extends RecyclerView.Adapter<PenaltyAdapter.ViewHold
public void onBindViewHolder(ViewHolder holder, int position) {
final CompetitorResultEditableImpl item = mFiltered.get(position);
int bgId = R.attr.sap_gray_black_30;
if (item.getOneBasedRank() == 0) {
if (item.getOneBasedRank() != 0) {
bgId = R.attr.sap_gray_black_20;
}
holder.itemView.setBackgroundColor(ThemeHelper.getColor(mContext, bgId));
@@ -14,6 +14,7 @@ import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.BitmapHelper;
import com.sap.sailing.android.shared.util.BroadcastManager;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
@@ -92,8 +93,13 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
for (final ManagedRace race : mAllRaces) {
viewItemsRaces.put(race, new RaceListDataTypeRace(race, mInflater));
final SeriesBase series = race.getSeries();
boolean hasConflict = race.getState().getConfirmedFinishPositioningList() != null && race.getState().getConfirmedFinishPositioningList().hasConflicts();
if (!viewItemsSeriesHeaders.containsKey(series)) {
viewItemsSeriesHeaders.put(series, new RaceListDataTypeHeader(new RaceGroupSeries(race), mInflater));
viewItemsSeriesHeaders.put(series, new RaceListDataTypeHeader(new RaceGroupSeries(race), mInflater, hasConflict));
} else {
if (hasConflict) {
viewItemsSeriesHeaders.get(series).setHasConflict(true);
}
}
}
}
@@ -174,6 +180,7 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
BroadcastManager.getInstance(getContext()).addIntent(intent);
}
});
holder.protest_warning_image.setVisibility(header.hasConflict() ? View.VISIBLE : View.GONE);
convertView.setTag(R.id.race_list_header, raceListElement);
}
} else if (type == ViewType.RACE.index) {
@@ -193,6 +200,10 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
holder.race_name.setText(RaceHelper.getReverseRaceFleetName(race.getRace()));
RaceState state = race.getRace().getState();
if (state != null) {
CompetitorResults results = state.getConfirmedFinishPositioningList();
if (results != null) {
holder.warning_sign.setVisibility(results.hasConflicts() ? View.VISIBLE : View.GONE);
}
if (state.getStartTime() != null) {
int startRes = R.string.race_started;
if (state.getFinishedTime() == null) {
@@ -390,6 +401,9 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
if (holder.explicit_factor != null) {
holder.explicit_factor.setVisibility(View.GONE);
}
if (holder.warning_sign != null) {
holder.warning_sign.setVisibility(View.GONE);
}
holder.setMarker(0);
}
@@ -508,11 +522,13 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
/* package */ TextView race_unscheduled;
/* package */ TextView flag_timer;
/* package */ ImageView protest_image;
/* package */ ImageView protest_warning_image;
/* package */ TextView boat_class;
/* package */ TextView fleet_series;
/* package */ ImageView has_dependent_races;
/* package */ TextView depends_on;
/* package */ TextView explicit_factor;
/* package */ ImageView warning_sign;
/* package */ void findViews(View layout) {
panel_left = ViewHelper.get(layout, R.id.panel_left);
@@ -529,11 +545,13 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
race_unscheduled = ViewHelper.get(layout, R.id.race_unscheduled);
flag_timer = ViewHelper.get(layout, R.id.flag_timer);
protest_image = ViewHelper.get(layout, R.id.protest_image);
protest_warning_image = ViewHelper.get(layout, R.id.protest_warning_image);
boat_class = ViewHelper.get(layout, R.id.boat_class);
fleet_series = ViewHelper.get(layout, R.id.fleet_series);
has_dependent_races = ViewHelper.get(layout, R.id.has_dependent_races);
depends_on = ViewHelper.get(layout, R.id.depends_on);
explicit_factor = ViewHelper.get(layout, R.id.explicit_factor);
warning_sign = ViewHelper.get(layout, R.id.panel_additional_image);
}
/* package */ void showFlag(LayerDrawable flag, Drawable arrow, String timer) {
@@ -12,15 +12,13 @@ import android.view.ViewGroup;
public class RaceListDataTypeHeader implements RaceListDataType, IsFleetFragment {
private RaceGroupSeries data;
private boolean hasConflict;
private final LayoutInflater mInflater;
public RaceListDataTypeHeader(RaceGroupSeries data, LayoutInflater layoutInflater) {
this(data, true, layoutInflater);
}
public RaceListDataTypeHeader(RaceGroupSeries data, boolean isFleetVisible, LayoutInflater layoutInflater) {
public RaceListDataTypeHeader(RaceGroupSeries data, LayoutInflater layoutInflater, boolean hasConflicts) {
this.data = data;
this.mInflater = layoutInflater;
this.hasConflict = hasConflicts;
}
public RaceGroupSeries getRegattaSeries() {
@@ -35,6 +33,14 @@ public class RaceListDataTypeHeader implements RaceListDataType, IsFleetFragment
return data.getSeries();
}
public void setHasConflict(boolean hasConflict) {
this.hasConflict = hasConflict;
}
public boolean hasConflict() {
return hasConflict;
}
@Override
public String toString() {
return data.getDisplayName();
@@ -11,6 +11,7 @@ import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.AppUtils;
import com.sap.sailing.android.shared.util.BitmapHelper;
import com.sap.sailing.android.shared.util.BroadcastManager;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.BaseRaceStateChangedListener;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeries;
@@ -88,7 +89,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
private boolean mUpdateList = true;
private View mProgress;
private final Set<ManagedRace> mAllRaces;
private BaseRaceStateChangedListener stateListener = new BaseRaceStateChangedListener() {
@Override
public void onStartTimeChanged(ReadonlyRaceState state) {
@@ -310,6 +311,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
@Override
public void onResume() {
super.onResume();
TickSingleton.INSTANCE.registerListener(this);
IntentFilter filter = new IntentFilter();
filter.addAction(AppConstants.INTENT_ACTION_SHOW_PROTEST);
@@ -338,6 +340,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
@Override
public void onStart() {
super.onStart();
unregisterOnAllRaces();
registerOnAllRaces();
for (ManagedRace race : mManagedRacesById.values()) {
@@ -348,6 +351,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
@Override
public void onStop() {
unregisterOnAllRaces();
super.onStop();
}
@@ -420,6 +424,23 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
mAdapter.onRacesChanged();
mAdapter.notifyDataSetChanged();
filterChanged();
showConflictSign();
}
private void showConflictSign() {
boolean showSign = false;
for (ManagedRace race : mAllRaces) {
CompetitorResults results = race.getState().getFinishPositioningList();
if (results != null && results.hasConflicts()) {
showSign = true;
break;
}
}
if (showSign) {
mAllRacesButton.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_warning_yellow_24dp, 0);
} else {
mAllRacesButton.setCompoundDrawables(null, null, null, null);
}
}
public void openDrawer() {
@@ -0,0 +1,89 @@
package com.sap.sailing.racecommittee.app.ui.fragments.dialogs;
import java.util.Locale;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.support.annotation.NonNull;
import android.support.annotation.StyleRes;
import android.view.View;
import android.widget.NumberPicker;
public class FullTimePickerDialog extends AlertDialog {
private NumberPicker mHour;
private NumberPicker mMinute;
private NumberPicker mSecond;
public FullTimePickerDialog(Context context, int res, @NonNull final OnTimeSetListener listener, int hourOfDay, int minute, int second,
boolean is24Hour) {
super(context, resolveDialogTheme(res));
View view = getLayoutInflater().inflate(R.layout.time_picker_hms, null);
mHour = ViewHelper.get(view, R.id.picker_hour);
mMinute = ViewHelper.get(view, R.id.picker_minute);
mSecond = ViewHelper.get(view, R.id.picker_second);
initPicker(mHour, 0, (is24Hour) ? 23 : 12, (!is24Hour && hourOfDay > 12) ? hourOfDay - 12 : hourOfDay);
initPicker(mMinute, 0, 59, minute);
initPicker(mSecond, 0, 59, second);
updateTitle();
int margin = context.getResources().getDimensionPixelSize(R.dimen.dialog_margin);
setView(view, margin, 0, margin, 0);
setButton(BUTTON_POSITIVE, context.getString(android.R.string.ok), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
listener.onTimeSet(FullTimePickerDialog.this, mHour.getValue(), mMinute.getValue(), mSecond.getValue());
dismiss();
}
});
setButton(BUTTON_NEGATIVE, context.getString(android.R.string.cancel), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
}
});
}
private static int resolveDialogTheme(@StyleRes int resId) {
if (resId == 0) {
resId = R.style.AppTheme_PickerDialog;
}
return resId;
}
private void initPicker(NumberPicker picker, int start, int end, int initial) {
ThemeHelper.setPickerColor(getContext(), picker, ThemeHelper.getColor(getContext(), R.attr.white), ThemeHelper
.getColor(getContext(), R.attr.sap_blue_1));
picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
@Override
public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
updateTitle();
}
});
picker.setMinValue(start);
picker.setMaxValue(end);
picker.setValue(initial);
picker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(int value) {
return String.format(Locale.getDefault(), "%02d", value);
}
});
}
private void updateTitle() {
setTitle(String.format(Locale.getDefault(), "%02d:%02d:%02d", mHour.getValue(), mMinute.getValue(), mSecond.getValue()));
}
public interface OnTimeSetListener {
void onTimeSet(FullTimePickerDialog dialog, int hourOfDay, int minutes, int second);
}
}
@@ -3,13 +3,6 @@ package com.sap.sailing.racecommittee.app.ui.fragments.lists;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.racecommittee.app.AppConstants;
@@ -20,14 +13,23 @@ import com.sap.sailing.racecommittee.app.ui.adapters.checked.CheckedItem;
import com.sap.sailing.racecommittee.app.ui.adapters.checked.CheckedItemAdapter;
import com.sap.sailing.racecommittee.app.ui.fragments.lists.selection.PositionSelectedListenerHost;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListAdapter;
import android.widget.ListView;
public class PositionListFragment extends LoggableListFragment {
private LogEventAuthorImpl author;
private AppPreferences preferences;
private List<LoginTypeItem> values;
private PositionSelectedListenerHost host;
public PositionListFragment() {
values = new ArrayList<>();
}
public static PositionListFragment newInstance() {
@@ -44,18 +46,18 @@ public class PositionListFragment extends LoggableListFragment {
preferences = AppPreferences.on(getActivity());
final ArrayList<String> values = new ArrayList<>();
values.add(getString(R.string.login_type_officer_on_start_vessel));
values.add(getString(R.string.login_type_officer_on_finish_vessel));
values.add(getString(R.string.login_type_shore_control));
values.add(new LoginTypeItem(1, getString(R.string.login_type_officer_on_vessel), AppConstants.AUTHOR_TYPE_OFFICER_VESSEL, LoginType.OFFICER));
values.add(new LoginTypeItem(2, getString(R.string.login_type_shore_control), AppConstants.AUTHOR_TYPE_SHORE_CONTROL, LoginType.OFFICER));
// TODO define configuration to activate super user
// values.add(new LoginTypeItem(0, getString(R.string.login_type_superuser), AppConstants.AUTHOR_TYPE_SUPERUSER, LoginType.OFFICER));
if (preferences.isDemoAllowed()) {
values.add(getString(R.string.login_type_viewer));
values.add(new LoginTypeItem(3, getString(R.string.login_type_viewer), AppConstants.AUTHOR_TYPE_VIEWER, LoginType.VIEWER));
}
final List<CheckedItem> items = new ArrayList<>();
for (String displayedText : values) {
for (LoginTypeItem loginType : values) {
CheckedItem item = new CheckedItem();
item.setText(displayedText);
item.setText(loginType.mLabel);
items.add(item);
}
@@ -75,33 +77,10 @@ public class PositionListFragment extends LoggableListFragment {
checkedItemAdapter.setCheckedPosition(position);
checkedItemAdapter.notifyDataSetChanged();
}
LoginType selectedLoginType;
switch (position) {
// see loginTypeDescriptions for the indices of the login types
case 0:
selectedLoginType = LoginType.OFFICER;
preferences.setSendingActive(true);
author = new LogEventAuthorImpl(AppConstants.AUTHOR_TYPE_OFFICER_START, 0);
break;
case 1:
selectedLoginType = LoginType.OFFICER;
preferences.setSendingActive(true);
author = new LogEventAuthorImpl(AppConstants.AUTHOR_TYPE_OFFICER_FINISH, 1);
break;
case 2:
selectedLoginType = LoginType.OFFICER;
preferences.setSendingActive(true);
author = new LogEventAuthorImpl(AppConstants.AUTHOR_TYPE_SHORE_CONTROL, 2);
break;
case 3:
selectedLoginType = LoginType.VIEWER;
preferences.setSendingActive(false);
author = new LogEventAuthorImpl(AppConstants.AUTHOR_TYPE_VIEWER, 3);
break;
default:
selectedLoginType = LoginType.NONE;
break;
}
LoginTypeItem item = values.get(position);
LoginType selectedLoginType = item.mType;
author = new LogEventAuthorImpl(item.mName, item.mPrio);
preferences.setSendingActive(item.mType == LoginType.OFFICER);
preferences.setAuthor(author);
ExLog.i(getActivity(), PositionListFragment.class.getName(), "Logging in as: " + selectedLoginType + "->" + author);
if (host != null) {
@@ -112,4 +91,20 @@ public class PositionListFragment extends LoggableListFragment {
public LogEventAuthorImpl getAuthor() {
return author;
}
private static class LoginTypeItem {
private int mPrio;
private String mLabel;
private String mName;
private LoginType mType;
LoginTypeItem(int prio, String label, String name, LoginType type) {
mPrio = prio;
mLabel = label;
mName = name;
mType = type;
}
}
}
@@ -1,5 +1,11 @@
package com.sap.sailing.racecommittee.app.ui.fragments.panels;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.BaseFragment;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import android.annotation.TargetApi;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -15,12 +21,6 @@ import android.support.v7.app.AlertDialog;
import android.view.View;
import android.widget.ImageView;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.BaseFragment;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
public abstract class BasePanelFragment extends RaceFragment {
/**
@@ -175,6 +175,12 @@ public abstract class BasePanelFragment extends RaceFragment {
}
}
FragmentTransaction transaction = manager.beginTransaction();
if (idRes != R.id.race_content) {
Fragment frag = manager.findFragmentById(R.id.race_content);
if (frag != null) {
transaction.remove(frag);
}
}
transaction.replace(idRes, fragment);
transaction.commit();
}
@@ -1,5 +1,13 @@
package com.sap.sailing.racecommittee.app.ui.fragments.panels;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.PhotoListFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.TrackingListFragment;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -12,15 +20,9 @@ import android.support.v4.content.LocalBroadcastManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.PhotoListFragment;
import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.TrackingListFragment;
public class FinishedButtonFragment extends BasePanelFragment {
private final static String TAG = FinishedButtonFragment.class.getName();
@@ -32,6 +34,7 @@ public class FinishedButtonFragment extends BasePanelFragment {
private View mPhotoLock;
private RelativeLayout mList;
private View mListLock;
private ImageView mWarning;
public FinishedButtonFragment() {
mReceiver = new IntentReceiver();
@@ -78,6 +81,8 @@ public class FinishedButtonFragment extends BasePanelFragment {
}
mListLock = ViewHelper.get(layout, R.id.list_lock);
mWarning = ViewHelper.get(layout, R.id.panel_additional_image);
return layout;
}
@@ -94,6 +99,11 @@ public class FinishedButtonFragment extends BasePanelFragment {
if (!preferences.getRacingProcedureIsResultEntryEnabled(getRaceState().getRacingProcedure().getType())) {
mList.setVisibility(View.GONE);
} else {
CompetitorResults results = getRaceState().getConfirmedFinishPositioningList();
if (results != null) {
mWarning.setVisibility(results.hasConflicts() ? View.VISIBLE : View.GONE);
}
}
}
@@ -158,7 +168,8 @@ public class FinishedButtonFragment extends BasePanelFragment {
break;
case LEVEL_TOGGLED:
replaceFragment(PhotoListFragment.newInstance(getRecentArguments()), getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true));
replaceFragment(PhotoListFragment
.newInstance(getRecentArguments()), getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true));
break;
default:
@@ -181,7 +192,8 @@ public class FinishedButtonFragment extends BasePanelFragment {
break;
case LEVEL_TOGGLED:
replaceFragment(TrackingListFragment.newInstance(getRecentArguments(), 0), getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true));
replaceFragment(TrackingListFragment
.newInstance(getRecentArguments(), 0), getFrameId(getActivity(), R.id.finished_edit, R.id.finished_content, true));
break;
default:
@@ -5,7 +5,9 @@ import static com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFi
import java.text.SimpleDateFormat;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.BroadcastManager;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult;
import com.sap.sailing.domain.abstractlog.race.state.ReadonlyRaceState;
@@ -105,10 +107,11 @@ public class TimePanelFragment extends BasePanelFragment {
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (preferences.getRacingProcedureIsResultEntryEnabled(getRace().getState().getRacingProcedure().getType())) {
if (preferences.getRacingProcedureIsResultEntryEnabled(getRaceState().getRacingProcedure().getType())) {
mClickListener = new CompetitorPanelClick();
mCompetitorList.setListener(mClickListener);
mCompetitorList.setVisibility(View.VISIBLE);
checkWarnings(getRaceState());
}
}
@@ -126,6 +129,7 @@ public class TimePanelFragment extends BasePanelFragment {
filter.addAction(AppConstants.INTENT_ACTION_CLEAR_TOGGLE);
filter.addAction(AppConstants.INTENT_ACTION_TIME_SHOW);
filter.addAction(AppConstants.INTENT_ACTION_TIME_HIDE);
filter.addAction(AppConstants.INTENT_ACTION_ON_LIFECYCLE);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver, filter);
sendIntent(AppConstants.INTENT_ACTION_CLEAR_TOGGLE);
@@ -232,7 +236,6 @@ public class TimePanelFragment extends BasePanelFragment {
changeVisibility(mTimeLock, null, View.VISIBLE);
break;
case FINISHED:
changeVisibility(mTimeLock, null, View.VISIBLE);
break;
@@ -243,9 +246,10 @@ public class TimePanelFragment extends BasePanelFragment {
}
}
private void toggleCompetitorList() {
if (RaceLogRaceStatus.FINISHING.equals(getRaceState().getStatus())) {
mCompetitorList.toggleMarker();
private void checkWarnings(ReadonlyRaceState state) {
CompetitorResults results = state.getConfirmedFinishPositioningList();
if (results != null) {
mCompetitorList.showAdditionalImage(results.hasConflicts());
}
}
@@ -257,8 +261,6 @@ public class TimePanelFragment extends BasePanelFragment {
checkStatus();
uncheckMarker(null);
toggleCompetitorList();
}
@Override
@@ -267,6 +269,20 @@ public class TimePanelFragment extends BasePanelFragment {
mLinkedRace = null;
}
@Override
public void onFinishingPositioningsChanged(ReadonlyRaceState state) {
super.onFinishingPositioningsChanged(state);
checkWarnings(state);
}
@Override
public void onFinishingPositionsConfirmed(ReadonlyRaceState state) {
super.onFinishingPositionsConfirmed(state);
checkWarnings(state);
}
}
private class RaceHeaderClick implements View.OnClickListener, DialogInterface.OnClickListener {
@@ -318,7 +334,9 @@ public class TimePanelFragment extends BasePanelFragment {
sendIntent(AppConstants.INTENT_ACTION_TOGGLE, AppConstants.INTENT_ACTION_EXTRA, AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR);
switch (view.toggleMarker()) {
case PanelButton.LEVEL_NORMAL:
sendIntent(AppConstants.INTENT_ACTION_SHOW_MAIN_CONTENT);
Intent intent = new Intent(AppConstants.INTENT_ACTION_SHOW_MAIN_CONTENT);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA_FORCED, true);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
break;
case PanelButton.LEVEL_TOGGLED:
@@ -355,9 +373,10 @@ public class TimePanelFragment extends BasePanelFragment {
if (AppConstants.INTENT_ACTION_CLEAR_TOGGLE.equals(action)) {
uncheckMarker(null);
}
if (AppConstants.INTENT_ACTION_TOGGLE.equals(action)) {
if (intent.getExtras() != null) {
String data = intent.getExtras().getString(AppConstants.INTENT_ACTION_EXTRA);
String data = intent.getStringExtra(AppConstants.INTENT_ACTION_EXTRA);
if (AppConstants.INTENT_ACTION_TOGGLE_TIME.equals(data)) {
uncheckMarker(mRaceHeader);
} else if (AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR.equals(data)) {
@@ -368,13 +387,18 @@ public class TimePanelFragment extends BasePanelFragment {
}
}
if (AppConstants.INTENT_ACTION_CLICK.equals(action)) {
if (AppConstants.INTENT_ACTION_ON_LIFECYCLE.equals(action)) {
if (intent.getExtras() != null) {
String data = intent.getExtras().getString(AppConstants.INTENT_ACTION_EXTRA);
if (AppConstants.INTENT_ACTION_CLICK_COMPETITOR.equals(data)) {
if (mCompetitorList != null && mClickListener != null) {
// TODO find a way for show finishing list
// mClickListener.onClick(mCompetitorList);
String event = intent.getStringExtra(AppConstants.INTENT_ACTION_EXTRA_LIFECYCLE);
String data = intent.getStringExtra(AppConstants.INTENT_ACTION_EXTRA);
if (AppConstants.INTENT_ACTION_EXTRA_START.equals(event)) {
if (AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR.equals(data)) {
mCompetitorList.setMarkerLevel(PanelButton.LEVEL_TOGGLED);
}
}
if (AppConstants.INTENT_ACTION_EXTRA_STOP.equals(event)) {
if (AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR.equals(data)) {
mCompetitorList.setMarkerLevel(PanelButton.LEVEL_NORMAL);
}
}
}
@@ -1,14 +1,18 @@
package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.sap.sailing.android.shared.logging.ExLog;
import com.sap.sailing.android.shared.util.AppUtils;
import com.sap.sailing.android.shared.util.BitmapHelper;
import com.sap.sailing.android.shared.util.BroadcastManager;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
@@ -44,6 +48,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.os.Build;
import android.os.Bundle;
@@ -81,6 +86,8 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
private PenaltyAdapter mAdapter;
private TextView mEntryCount;
private CompetitorResultsList<CompetitorResultEditableImpl> mCompetitorResults;
private CompetitorResultsList<CompetitorResultEditableImpl> mLastSend;
private CompetitorResults mLastPublished;
private View mListButtonLayout;
private ImageView mListButton;
private HeaderLayout mHeader;
@@ -97,6 +104,8 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
public View onCreateView(final LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.race_penalty_fragment, container, false);
mCompetitorResults = new CompetitorResultsList<>(new ArrayList<CompetitorResultEditableImpl>());
mLastSend = new CompetitorResultsList<>(new ArrayList<CompetitorResultEditableImpl>());
mLastPublished = new CompetitorResultsImpl();
SearchView searchView = ViewHelper.get(layout, R.id.competitor_search);
if (searchView != null) {
searchView.setSearchTextWatcher(this);
@@ -107,7 +116,6 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
mListButtonLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendUnconfirmed();
RaceFragment fragment = TrackingListFragment.newInstance(new Bundle(), 1);
int viewId = R.id.race_content;
switch (getRaceState().getStatus()) {
@@ -153,7 +161,7 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
applyButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setReason((String)mPenaltyDropDown.getSelectedItem());
setReason((String) mPenaltyDropDown.getSelectedItem());
}
});
}
@@ -262,23 +270,65 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
mListButtonLayout.setVisibility(View.GONE);
}
}
if (getRaceState().getFinishPositioningList() != null) {
for (CompetitorResult item : getRaceState().getFinishPositioningList()) {
mLastSend.add(new CompetitorResultEditableImpl(item));
}
}
if (getRaceState().getConfirmedFinishPositioningList() != null) {
for (CompetitorResult item : getRaceState().getConfirmedFinishPositioningList()) {
mLastPublished.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item.getOneBasedRank(), item
.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment()));
}
}
loadCompetitors();
}
@Override
public void onStart() {
super.onStart();
Intent intent = new Intent(AppConstants.INTENT_ACTION_ON_LIFECYCLE);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA_LIFECYCLE, AppConstants.INTENT_ACTION_EXTRA_START);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA, AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
}
@Override
public void onStop() {
super.onStop();
sendUnconfirmed();
boolean dirty = false;
for (CompetitorResultEditableImpl item : mCompetitorResults) {
if (item.isDirty()) {
dirty = true;
break;
}
}
if (dirty) {
sendUnconfirmed();
}
Intent intent = new Intent(AppConstants.INTENT_ACTION_ON_LIFECYCLE);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA_LIFECYCLE, AppConstants.INTENT_ACTION_EXTRA_STOP);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA, AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
}
private void sendUnconfirmed() {
getRaceState().setFinishPositioningListChanged(MillisecondsTimePoint.now(), getCompetitorResults());
CompetitorResults results = getCompetitorResultsDiff();
getRaceState().setFinishPositioningListChanged(MillisecondsTimePoint.now(), results);
for (CompetitorResultEditableImpl item : mCompetitorResults) {
item.setDirty(false);
}
}
private void confirmData() {
sendUnconfirmed();
getRaceState().setFinishPositioningConfirmed(MillisecondsTimePoint.now());
Toast.makeText(getActivity(), R.string.publish_clicked, Toast.LENGTH_SHORT).show();
loadCompetitors();
}
private String[] getAllMaxPointsReasons() {
@@ -414,24 +464,33 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
}
private void setPublishButton() {
int count = 0;
Set<Serializable> changed = new HashSet<>();
boolean isChecked = false;
for (CompetitorResultEditableImpl item : mCompetitorResults) {
if (item.isChecked()) {
isChecked = true;
}
if (!MaxPointsReason.NONE.equals(item.getMaxPointsReason())) {
count++;
}
for (CompetitorResult item : getCompetitorResultsDiff()) {
boolean found = false;
for (CompetitorResult server : mLastPublished) {
if (server.equals(item)) {
found = true;
break;
}
}
if (!found) {
changed.add(item.getCompetitorId());
}
}
String text = getString(R.string.publish_button_empty);
// FIXME needs redefine later
// if (count != 0) {
// text = getString(R.string.publish_button_other, count);
// }
if (changed.size() != 0) {
text = getString(R.string.publish_button_other, changed.size());
}
mPublishButton.setText(text);
mPublishButton.setEnabled(count != 0);
mButtonBar.setVisibility((count != 0 || isChecked) ? View.VISIBLE : View.GONE);
mPublishButton.setEnabled(changed.size() != 0);
mButtonBar.setVisibility((changed.size() != 0 || isChecked) ? View.VISIBLE : View.GONE);
}
@Override
@@ -448,9 +507,9 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
.getFinishingTime(), competitor.getComment());
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_AlertDialog);
builder.setTitle(item.getCompetitorDisplayName());
final CompetitorEditLayout layout = new CompetitorEditLayout(getActivity(), item, mCompetitorResults.getFirstRankZeroPosition()+
final CompetitorEditLayout layout = new CompetitorEditLayout(getActivity(), item, mCompetitorResults.getFirstRankZeroPosition() +
/* allow for setting rank as the new last in the list in case the competitor did not have a rank so far */
(item.getOneBasedRank()==0?1:0));
(item.getOneBasedRank() == 0 ? 1 : 0));
builder.setView(layout);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
@@ -462,7 +521,7 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
competitor.setDirty(true);
}
if (!Util.equalsWithNull(competitor.getComment(), item.getComment())) {
competitor.setComment(item.getComment());
competitor.setComment(TextUtils.isEmpty(item.getComment()) ? null : item.getComment());
competitor.setDirty(true);
}
if (!Util.equalsWithNull(competitor.getScore(), item.getScore())) {
@@ -486,43 +545,30 @@ public class PenaltyFragment extends BaseFragment implements PopupMenu.OnMenuIte
}
}
private CompetitorResults getCompetitorResults() {
CompetitorResultsImpl results = new CompetitorResultsImpl();
Collections.sort(mCompetitorResults, new Comparator<CompetitorResultEditableImpl>() {
@Override
public int compare(CompetitorResultEditableImpl left, CompetitorResultEditableImpl right) {
int result;
if (left.getOneBasedRank() == 0 || left.getOneBasedRank() != right.getOneBasedRank()) {
result = 1;
} else {
result = left.getOneBasedRank() - right.getOneBasedRank();
}
return result;
}
});
private CompetitorResults getCompetitorResultsDiff() {
CompetitorResultsImpl result = new CompetitorResultsImpl();
for (CompetitorResultEditableImpl item : mCompetitorResults) {
if (!MaxPointsReason.NONE.equals(item.getMaxPointsReason()) || item.getOneBasedRank() > 0) {
CompetitorResult result = new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item
.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment());
results.add(result);
if (item.isDirty()) {
result.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item.getOneBasedRank(), item
.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment()));
}
}
// sort penalty result to the end
Collections.sort(results, new Comparator<CompetitorResult>() {
@Override
public int compare(CompetitorResult left, CompetitorResult right) {
int result;
if (left.getOneBasedRank() > 0 && right.getOneBasedRank() > 0) {
result = left.getOneBasedRank() - right.getOneBasedRank();
} else if (left.getOneBasedRank() == 0 && right.getOneBasedRank() == 0) {
result = 0;
} else {
result = right.getOneBasedRank() - left.getOneBasedRank();
for (CompetitorResult item : mLastSend) {
boolean found = false;
for (CompetitorResult dirtyItem : result) {
if (item.getCompetitorId().equals(dirtyItem.getCompetitorId())) {
found = true;
}
return result;
}
});
return results;
if (!found) {
result.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item.getOneBasedRank(), item
.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment()));
}
}
return result;
}
@Override
@@ -13,6 +13,7 @@ import com.h6ah4i.android.widget.advrecyclerview.touchguard.RecyclerViewTouchAct
import com.h6ah4i.android.widget.advrecyclerview.utils.WrapperAdapterUtils;
import com.sap.sailing.android.shared.util.AppUtils;
import com.sap.sailing.android.shared.util.BitmapHelper;
import com.sap.sailing.android.shared.util.BroadcastManager;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
@@ -47,6 +48,7 @@ import com.sap.sse.common.impl.MillisecondsTimePoint;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.Loader;
import android.graphics.drawable.NinePatchDrawable;
import android.os.Build;
@@ -91,6 +93,7 @@ public class TrackingListFragment extends BaseFragment
private RecyclerView.Adapter<FinishListAdapter.ViewHolder> mFinishedAdapter;
private CompetitorAdapter mCompetitorAdapter;
private CompetitorResultsList<CompetitorResultWithIdImpl> mFinishedData;
private CompetitorResults mLastPublished;
private List<Competitor> mCompetitorData;
private List<Competitor> mFilteredCompetitorData;
private int mId = 0;
@@ -135,7 +138,6 @@ public class TrackingListFragment extends BaseFragment
listButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendUnconfirmed();
RaceFragment fragment = PenaltyFragment.newInstance();
int viewId = R.id.race_content;
switch (getRaceState().getStatus()) {
@@ -195,6 +197,7 @@ public class TrackingListFragment extends BaseFragment
}
});
}
return layout;
}
@@ -245,12 +248,13 @@ public class TrackingListFragment extends BaseFragment
}
mConfirm = (Button) getView().findViewById(R.id.confirm);
if (mConfirm != null) {
mConfirm.setEnabled(mDots.size() == 0);
mConfirm.setEnabled(true);
mConfirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendUnconfirmed();
getRaceState().setFinishPositioningConfirmed(MillisecondsTimePoint.now());
initLastPublished();
Toast.makeText(getActivity(), R.string.publish_clicked, Toast.LENGTH_SHORT).show();
sendIntent(AppConstants.INTENT_ACTION_CLEAR_TOGGLE);
sendIntent(AppConstants.INTENT_ACTION_SHOW_SUMMARY_CONTENT);
@@ -268,8 +272,20 @@ public class TrackingListFragment extends BaseFragment
mFilteredCompetitorData.addAll(mCompetitorData);
sortCompetitors();
mCompetitorAdapter.notifyDataSetChanged();
initLastPublished();
}
private void initLastPublished() {
mLastPublished = new CompetitorResultsImpl();
if (getRaceState().getConfirmedFinishPositioningList() != null) {
for (CompetitorResult item : getRaceState().getConfirmedFinishPositioningList()) {
mLastPublished.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item.getOneBasedRank(), item
.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment()));
}
}
}
private int getFirstRankZeroPosition() {
return mAdapter.getFirstRankZeroPosition();
}
@@ -277,14 +293,30 @@ public class TrackingListFragment extends BaseFragment
@Override
public void onPause() {
mDragDropManager.cancelDrag();
super.onPause();
}
@Override
public void onStart() {
super.onStart();
Intent intent = new Intent(AppConstants.INTENT_ACTION_ON_LIFECYCLE);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA_LIFECYCLE, AppConstants.INTENT_ACTION_EXTRA_START);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA, AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
}
@Override
public void onStop() {
super.onStop();
sendUnconfirmed();
Intent intent = new Intent(AppConstants.INTENT_ACTION_ON_LIFECYCLE);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA_LIFECYCLE, AppConstants.INTENT_ACTION_EXTRA_STOP);
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA, AppConstants.INTENT_ACTION_TOGGLE_COMPETITOR);
BroadcastManager.getInstance(getActivity()).addIntent(intent);
}
@Override
@@ -342,7 +374,7 @@ public class TrackingListFragment extends BaseFragment
}
private void sendUnconfirmed() {
getRaceState().setFinishPositioningListChanged(MillisecondsTimePoint.now(), getCompetitorResults());
getRaceState().setFinishPositioningListChanged(MillisecondsTimePoint.now(), getCompetitorResultsDiff());
}
private void loadCompetitors() {
@@ -411,7 +443,7 @@ public class TrackingListFragment extends BaseFragment
Collections.sort(sortByRank, new Comparator<CompetitorWithRaceRankImpl>() {
@Override
public int compare(CompetitorWithRaceRankImpl left, CompetitorWithRaceRankImpl right) {
return (int)left.getRaceRank(raceName) - (int)right.getRaceRank(raceName);
return (int) left.getRaceRank(raceName) - (int) right.getRaceRank(raceName);
}
});
List<Competitor> sortedList = new ArrayList<>();
@@ -431,13 +463,21 @@ public class TrackingListFragment extends BaseFragment
}
private void deleteCompetitorsFromFinishedList(Collection<Competitor> validCompetitors) {
List<Integer> positions = new ArrayList<>();
List<CompetitorResultWithIdImpl> toBeDeleted = new ArrayList<>();
for (CompetitorResultWithIdImpl item : mFinishedData) {
if (!validCompetitors.contains(getCompetitorStore().getExistingCompetitorById(item.getCompetitorId()))) {
positions.add(mFinishedData.indexOf(item));
toBeDeleted.add(item);
continue;
}
if (item.getOneBasedRank() == 0 && item.getMaxPointsReason() == MaxPointsReason.NONE) {
positions.add(mFinishedData.indexOf(item));
toBeDeleted.add(item);
}
}
mFinishedData.removeAll(toBeDeleted);
mFinishedAdapter.notifyDataSetChanged();
}
private void deleteCompetitorsFromCompetitorList() {
@@ -453,7 +493,8 @@ public class TrackingListFragment extends BaseFragment
}
private CompetitorResultsList<CompetitorResultWithIdImpl> initializeFinishList() {
CompetitorResultsList<CompetitorResultWithIdImpl> positioning = new CompetitorResultsList<>(Collections.synchronizedList(new ArrayList<CompetitorResultWithIdImpl>()));
CompetitorResultsList<CompetitorResultWithIdImpl> positioning = new CompetitorResultsList<>(Collections
.synchronizedList(new ArrayList<CompetitorResultWithIdImpl>()));
if (getRaceState() != null && getRaceState().getFinishPositioningList() != null) {
for (CompetitorResult results : getRaceState().getFinishPositioningList()) {
positioning.add(new CompetitorResultWithIdImpl(mId, results));
@@ -487,7 +528,7 @@ public class TrackingListFragment extends BaseFragment
mFinishedData.add(pos, new CompetitorResultWithIdImpl(mId, competitor.getId(), name, greatestOneBasedRankSoFar + 1, MaxPointsReason.NONE,
/* score */ null, /* finishingTime */ null, /* comment */ null));
mId++;
mFinishedAdapter.notifyDataSetChanged();
mFinishedAdapter.notifyItemInserted(pos);
if (mDots.size() > 0) {
Toast.makeText(getActivity(), getString(R.string.added_to_result_list, name, pos + 1), Toast.LENGTH_SHORT).show();
}
@@ -495,9 +536,10 @@ public class TrackingListFragment extends BaseFragment
private void removeCompetitorFromList(Competitor competitor) {
mCompetitorData.remove(competitor);
int pos = mFilteredCompetitorData.indexOf(competitor);
mFilteredCompetitorData.remove(competitor);
sortCompetitors();
mCompetitorAdapter.notifyDataSetChanged();
mCompetitorAdapter.notifyItemRemoved(pos);
}
/**
@@ -514,21 +556,19 @@ public class TrackingListFragment extends BaseFragment
* <li>Rank changed from non-0 to other non-0 value: adjust all ranks between and including old and new list
* position</li>
* </ol>
*
* @param fromPosition
* the position (zero-based index) where the item currently is in {@link #mFinishedData}
* @param toPosition
* the position (zero-based index <em>after</em> removal of the item from its {@code fromPosition}) where
* to {@link List#add(int, Object)} the item again in {@link #mFinishedData}
*
* @param fromPosition the position (zero-based index) where the item currently is in {@link #mFinishedData}
* @param toPosition the position (zero-based index <em>after</em> removal of the item from its {@code fromPosition}) where
* to {@link List#add(int, Object)} the item again in {@link #mFinishedData}
*/
@Override
public void onItemMove(int fromPosition, int toPosition) {
CompetitorResultWithIdImpl item = mFinishedData.remove(fromPosition);
mFinishedData.add(toPosition, item);
final int firstPositionChanged = Math.min(getFirstRankZeroPosition(), Math.min(fromPosition, toPosition));
final int lastPositionChanged = Math.min(getFirstRankZeroPosition(), Math.max(fromPosition, toPosition)+1);
final int lastPositionChanged = Math.min(getFirstRankZeroPosition(), Math.max(fromPosition, toPosition) + 1);
adjustRanks(firstPositionChanged, lastPositionChanged);
mFinishedAdapter.notifyItemRangeChanged(firstPositionChanged, lastPositionChanged-firstPositionChanged);
mFinishedAdapter.notifyItemRangeChanged(firstPositionChanged, lastPositionChanged - firstPositionChanged);
}
@Override
@@ -549,47 +589,44 @@ public class TrackingListFragment extends BaseFragment
* In {@link #mFinishedData}, starting at index {@code fromPosition}, updates all ranks so they equal the
* position in the list plus one; stop before reaching the entry at list index {@code toPosition} or the
* {@link #getFirstRankZeroPosition() first penalty position}.
*
*
* @param fromPosition inclusive start index into {@link #mFinishedData} where to start updating the ranks
* @param toPosition exclusive end index into {@link #mFinishedData} where to stop updating the ranks; must not be -1
* @param toPosition exclusive end index into {@link #mFinishedData} where to stop updating the ranks; must not be -1
*/
private void adjustRanks(int fromPosition, int toPosition) {
final int end = Math.min(toPosition, getFirstRankZeroPosition());
for (int i = fromPosition; i < end; i++) {
CompetitorResultWithIdImpl competitorToReplaceWithAdjustedPosition = mFinishedData.get(i);
final int newOneBasedRank = i+1;
final int newOneBasedRank = i + 1;
mFinishedData.set(i, cloneCompetitorResultAndAdjustRank(competitorToReplaceWithAdjustedPosition, newOneBasedRank));
}
}
private CompetitorResultWithIdImpl cloneCompetitorResultAndAdjustRank(
CompetitorResultWithIdImpl competitorToReplaceWithAdjustedPosition, final int newOneBasedRank) {
return new CompetitorResultWithIdImpl(
competitorToReplaceWithAdjustedPosition.getId(),
competitorToReplaceWithAdjustedPosition.getCompetitorId(),
competitorToReplaceWithAdjustedPosition.getCompetitorDisplayName(),
newOneBasedRank,
competitorToReplaceWithAdjustedPosition.getMaxPointsReason(),
competitorToReplaceWithAdjustedPosition.getScore(),
competitorToReplaceWithAdjustedPosition.getFinishingTime(),
competitorToReplaceWithAdjustedPosition.getComment());
private CompetitorResultWithIdImpl cloneCompetitorResultAndAdjustRank(CompetitorResultWithIdImpl competitorToReplaceWithAdjustedPosition,
final int newOneBasedRank) {
return new CompetitorResultWithIdImpl(competitorToReplaceWithAdjustedPosition.getId(), competitorToReplaceWithAdjustedPosition
.getCompetitorId(), competitorToReplaceWithAdjustedPosition
.getCompetitorDisplayName(), newOneBasedRank, competitorToReplaceWithAdjustedPosition
.getMaxPointsReason(), competitorToReplaceWithAdjustedPosition.getScore(), competitorToReplaceWithAdjustedPosition
.getFinishingTime(), competitorToReplaceWithAdjustedPosition.getComment());
}
private void addNewCompetitorToCompetitorList(Competitor competitor) {
mCompetitorData.add(competitor);
mFilteredCompetitorData.add(competitor);
sortCompetitors();
mCompetitorAdapter.notifyDataSetChanged();
mCompetitorAdapter.notifyItemInserted(mFilteredCompetitorData.indexOf(competitor));
}
@Override
public void onLongClick(final CompetitorResultWithIdImpl item) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_AlertDialog);
final CharSequence[] maxPointsReasons = getAllMaxPointsReasons();
builder.setTitle(R.string.select_penalty_reason).setItems(maxPointsReasons, new DialogInterface.OnClickListener() {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.AppTheme_AlertDialog);
builder.setTitle(R.string.select_penalty_reason);
builder.setItems(maxPointsReasons, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int position) {
setMaxPointsReasonForItem(item, maxPointsReasons[position]);
mFinishedAdapter.notifyDataSetChanged();
mFinishedAdapter.notifyItemChanged(mFinishedData.indexOf(item));
}
});
builder.show();
@@ -606,10 +643,10 @@ public class TrackingListFragment extends BaseFragment
}
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.AppTheme_AlertDialog);
builder.setTitle(item.getCompetitorDisplayName());
final CompetitorEditLayout layout = new CompetitorEditLayout(getActivity(), getRace().getState()
.getFinishingTime(), item, mAdapter.getFirstRankZeroPosition()+
final CompetitorEditLayout layout = new CompetitorEditLayout(getActivity(), getRace().getState().getFinishingTime(), item,
mAdapter.getFirstRankZeroPosition() +
/* allow for setting rank as the new last in the list in case the competitor did not have a rank so far */
(item.getOneBasedRank()==0?1:0), false);
(item.getOneBasedRank() == 0 ? 1 : 0), false);
builder.setView(layout);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
@@ -631,6 +668,7 @@ public class TrackingListFragment extends BaseFragment
* <ol>
* <li>Rank set from non-0 to 0 and MaxPointsReason is not NONE: move item to the end of the list, into the
* "penalized section"; decrement ranks greater than old rank</li>
* <li>Rank set from non-0 to 0 and MaxPointsReason is NONE: remove item from finish list</li>
* <li>Rank set from 0 to non-0: move from penalized to ranked section; increment ranks greater than or equal to old
* rank</li>
* <li>Rank changed from non-0 to other non-0 value: adjust all ranks between and including old and new list
@@ -643,11 +681,14 @@ public class TrackingListFragment extends BaseFragment
if (item.getOneBasedRank() != 0 && newItem.getOneBasedRank() == 0 && newItem.getMaxPointsReason() != MaxPointsReason.NONE) {
// move to the end of the area of "penalized" competitors; may also be an unpenalized competitor that hasn't
// been removed yet (e.g., in order to force a score correction reset on the server)
onItemMove(index, mFinishedData.size()-1); // -1 because first the element is removed, so when inserting the list is one element shorter
onItemMove(index, mFinishedData.size() - 1); // -1 because first the element is removed, so when inserting the list is one element shorter
} else if (item.getOneBasedRank() != newItem.getOneBasedRank() && newItem.getOneBasedRank() != 0) {
onItemMove(index, newItem.getOneBasedRank() - 1);
} else if (newItem.getOneBasedRank() == 0 && newItem.getMaxPointsReason() == MaxPointsReason.NONE) {
onItemRemove(index);
} else {
mFinishedAdapter.notifyItemChanged(index);
}
mFinishedAdapter.notifyDataSetChanged();
}
private CharSequence[] getAllMaxPointsReasons() {
@@ -669,13 +710,52 @@ public class TrackingListFragment extends BaseFragment
private CompetitorResults getCompetitorResults() {
CompetitorResults result = new CompetitorResultsImpl();
for (CompetitorResultWithIdImpl item : mFinishedData) {
result.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(),
item.getOneBasedRank(), item.getMaxPointsReason(), item.getScore(), item
.getFinishingTime(), item.getComment()));
result.add(new CompetitorResultImpl(item.getCompetitorId(), item.getCompetitorDisplayName(), item.getOneBasedRank(), item
.getMaxPointsReason(), item.getScore(), item.getFinishingTime(), item.getComment()));
}
return result;
}
private CompetitorResults getCompetitorResultsDiff() {
CompetitorResults result = new CompetitorResultsImpl();
// all changed items
for (CompetitorResult oldItem : mLastPublished) {
boolean found = false;
for (CompetitorResult newItem : mFinishedData) {
if (oldItem.getCompetitorId().equals(newItem.getCompetitorId())) {
if (!oldItem.equals(newItem)) {
result.add(new CompetitorResultImpl(newItem.getCompetitorId(), newItem.getCompetitorDisplayName(), newItem
.getOneBasedRank(), newItem.getMaxPointsReason(), newItem.getScore(), newItem.getFinishingTime(), newItem.getComment()));
}
found = true;
break;
}
}
if (!found) {
result.add(new CompetitorResultImpl(oldItem.getCompetitorId(), oldItem.getCompetitorDisplayName(), 0, oldItem
.getMaxPointsReason(), oldItem.getScore(), oldItem.getFinishingTime(), oldItem.getComment()));
}
}
// all new items
for (CompetitorResultWithIdImpl newItem : mFinishedData) {
boolean found = false;
for (CompetitorResult oldItem : mLastPublished) {
if (oldItem.getCompetitorId().equals(newItem.getCompetitorId())) {
found = true;
break;
}
}
if (!found) {
result.add(new CompetitorResultImpl(newItem.getCompetitorId(), newItem.getCompetitorDisplayName(), newItem.getOneBasedRank(), newItem
.getMaxPointsReason(), newItem.getScore(), newItem.getFinishingTime(), newItem.getComment()));
}
}
return result;
}
@Override
public void onClick(View v) {
if (v != null) {
@@ -702,7 +782,7 @@ public class TrackingListFragment extends BaseFragment
if (mTools != null) {
mTools.setVisibility(mActivePage == 0 ? View.VISIBLE : View.GONE);
}
mConfirm.setEnabled(mActivePage != 0 || mDots.size() == 0);
mConfirm.setEnabled(true);
}
private void sortCompetitors() {
@@ -7,18 +7,6 @@ import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import android.annotation.SuppressLint;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.NumberPicker;
import android.widget.ScrollView;
import android.widget.Spinner;
import com.sap.sailing.android.shared.util.AppUtils;
import com.sap.sailing.android.shared.util.ViewHelper;
import com.sap.sailing.domain.abstractlog.race.CompetitorResult;
@@ -27,13 +15,25 @@ import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.domain.impl.CompetitorResultWithIdImpl;
import com.sap.sailing.racecommittee.app.ui.adapters.StringArraySpinnerAdapter;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.FullTimePickerDialog;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import android.annotation.SuppressLint;
import android.app.DatePickerDialog;
import android.content.Context;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ScrollView;
import android.widget.Spinner;
import android.widget.TextView;
@SuppressLint("ViewConstructor")
public class CompetitorEditLayout extends ScrollView {
public class CompetitorEditLayout extends ScrollView implements DatePickerDialog.OnDateSetListener, FullTimePickerDialog.OnTimeSetListener {
private CompetitorResultWithIdImpl mCompetitor;
private GregorianCalendar mCalendar;
@@ -41,11 +41,10 @@ public class CompetitorEditLayout extends ScrollView {
private Spinner mPosition;
private Spinner mPenalty;
private EditText mScore;
private Spinner mDate;
private NumberPicker mHours;
private NumberPicker mMinutes;
private NumberPicker mSeconds;
private EditText mComment;
private TextView mFinishDate;
private TextView mFinishTime;
private FrameLayout mDelete;
private boolean mRestricted;
@@ -53,11 +52,14 @@ public class CompetitorEditLayout extends ScrollView {
this(context, null, competitor, maxPos, true);
}
public CompetitorEditLayout(Context context, TimePoint startTime, CompetitorResultWithIdImpl competitor, int maxPos, boolean restrictedView) {
public CompetitorEditLayout(final Context context, final TimePoint startTime, CompetitorResultWithIdImpl competitor, int maxPos,
boolean restrictedView) {
super(context);
mRestricted = restrictedView;
mCompetitor = competitor;
int layoutId;
if (AppUtils.with(getContext()).isPhone() && AppUtils.with(getContext()).isHDPI()) {
if (AppUtils.with(getContext()).isPhone()) {
layoutId = R.layout.race_tracking_list_competitor_edit_small;
} else {
layoutId = R.layout.race_tracking_list_competitor_edit_normal;
@@ -71,35 +73,77 @@ public class CompetitorEditLayout extends ScrollView {
if (position != null) {
position.setVisibility(restrictedView ? GONE : VISIBLE);
}
View finishDate = ViewHelper.get(layout, R.id.competitor_finish_date_layout);
if (finishDate != null) {
finishDate.setVisibility(restrictedView ? GONE : VISIBLE);
}
View finishTime = ViewHelper.get(layout, R.id.competitor_finish_time_layout);
if (finishTime != null) {
finishTime.setVisibility(restrictedView ? GONE : VISIBLE);
}
mCompetitor = competitor;
mCalendar = (GregorianCalendar) GregorianCalendar.getInstance();
if (mCompetitor.getFinishingTime() != null) {
mCalendar.setTimeInMillis(mCompetitor.getFinishingTime().asMillis());
}
mHours = ViewHelper.get(layout, R.id.competitor_finish_time_hours);
if (mHours != null) {
formatPicker(mHours, 0, 23);
mHours.setValue(mCalendar.get(Calendar.HOUR_OF_DAY));
final int initialYear = mCalendar.get(Calendar.YEAR);
final int initialMonth = mCalendar.get(Calendar.MONTH);
final int initialDay = mCalendar.get(Calendar.DAY_OF_MONTH);
final int initialHour = mCalendar.get(Calendar.HOUR_OF_DAY);
final int initialMinutes = mCalendar.get(Calendar.MINUTE);
final int initialSecond = mCalendar.get(Calendar.SECOND);
View timeLayout = ViewHelper.get(layout, R.id.competitor_finish_time_layout);
if (timeLayout != null) {
timeLayout.setVisibility(mRestricted ? GONE : VISIBLE);
}
mMinutes = ViewHelper.get(layout, R.id.competitor_finish_time_minutes);
if (mMinutes != null) {
formatPicker(mMinutes, 0, 59);
mMinutes.setValue(mCalendar.get(Calendar.MINUTE));
mFinishDate = ViewHelper.get(layout, R.id.competitor_finish_date);
if (mFinishDate != null) {
mFinishDate.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int year = initialYear;
int month = initialMonth;
int day = initialDay;
if (mCalendar != null) {
year = mCalendar.get(Calendar.YEAR);
month = mCalendar.get(Calendar.MONTH);
day = mCalendar.get(Calendar.DAY_OF_MONTH);
}
DatePickerDialog dialog = new DatePickerDialog(context, R.style.AppTheme_PickerDialog, CompetitorEditLayout.this, year, month, day);
dialog.getDatePicker().setMinDate(startTime.asMillis());
dialog.show();
}
});
}
mSeconds = ViewHelper.get(layout, R.id.competitor_finish_time_seconds);
if (mSeconds != null) {
formatPicker(mSeconds, 0, 59);
mSeconds.setValue(mCalendar.get(Calendar.SECOND));
mFinishTime = ViewHelper.get(layout, R.id.competitor_finish_time);
if (mFinishTime != null) {
mFinishTime.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
int hour = initialHour;
int minutes = initialMinutes;
int second = initialSecond;
if (mCalendar != null) {
hour = mCalendar.get(Calendar.HOUR_OF_DAY);
minutes = mCalendar.get(Calendar.MINUTE);
second = mCalendar.get(Calendar.SECOND);
}
FullTimePickerDialog dialog = new FullTimePickerDialog(context, R.style.AppTheme_PickerDialog, CompetitorEditLayout.this, hour, minutes, second, true);
dialog.show();
}
});
}
if (mCompetitor.getFinishingTime() == null) {
mCalendar = null;
}
mDelete = ViewHelper.get(layout, R.id.competitor_finish_date_delete);
if (mDelete != null) {
mDelete.setEnabled(false);
mDelete.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mCalendar = null;
showFinishTime();
}
});
}
showFinishTime();
mPosition = ViewHelper.get(layout, R.id.competitor_position);
if (mPosition != null) {
StringArraySpinnerAdapter positionAdapter = new StringArraySpinnerAdapter(getPositionList(maxPos));
@@ -114,20 +158,9 @@ public class CompetitorEditLayout extends ScrollView {
mPenalty.setOnItemSelectedListener(new StringArraySpinnerAdapter.SpinnerSelectedListener(penaltyAdapter));
mPenalty.setSelection(penaltyAdapter.getPosition(mCompetitor.getMaxPointsReason().toString()));
}
mDate = ViewHelper.get(layout, R.id.competitor_finish_date);
if (mDate != null && startTime != null) {
String[] dates = getDates(startTime);
StringArraySpinnerAdapter dateAdapter = new StringArraySpinnerAdapter(dates);
mDate.setAdapter(dateAdapter);
mDate.setOnItemSelectedListener(new StringArraySpinnerAdapter.SpinnerSelectedListener(dateAdapter));
mDate.setSelection(findDate(dates, competitor.getFinishingTime()));
if (dates.length == 1) {
mDate.setVisibility(GONE);
}
}
mScore = ViewHelper.get(layout, R.id.competitor_score);
if (mScore != null && mCompetitor.getScore() != null) {
mScore.setText(String.format(Locale.US, "%f", mCompetitor.getScore()));
mScore.setText(String.format(Locale.getDefault(), "%f", mCompetitor.getScore()));
}
mComment = ViewHelper.get(layout, R.id.competitor_comment);
if (mComment != null) {
@@ -136,26 +169,6 @@ public class CompetitorEditLayout extends ScrollView {
addView(layout);
}
private String[] getDates(@NonNull TimePoint startTime) {
TimePoint now = MillisecondsTimePoint.now();
ArrayList<String> dates = TimeUtils.getDates(getContext(), startTime, now);
return dates.toArray(new String[dates.size()]);
}
private int findDate(@NonNull String[] dates, @Nullable TimePoint finishingTime) {
int pos = 0;
if (finishingTime != null) {
SimpleDateFormat simpleFormat = new SimpleDateFormat(getContext().getString(R.string.date_short), Locale.US);
String finishDate = simpleFormat.format(finishingTime.asDate());
for (int i = 0; i < dates.length; i++) {
if (finishDate.equals(dates[i])) {
pos = i;
}
}
}
return pos;
}
private String[] getAllMaxPointsReasons() {
List<String> result = new ArrayList<>();
for (MaxPointsReason reason : MaxPointsReason.values()) {
@@ -173,7 +186,7 @@ public class CompetitorEditLayout extends ScrollView {
}
private void addPositionToPositionList(List<String> result, int i) {
result.add(String.format(Locale.US, "%d", i));
result.add(String.format(Locale.getDefault(), "%d", i));
}
public CompetitorResultWithIdImpl getValue() {
@@ -191,22 +204,11 @@ public class CompetitorEditLayout extends ScrollView {
}
TimePoint finishingTime = null;
if (!mRestricted) {
if (mDate != null) {
String[] date = ((String) mDate.getSelectedItem()).split("-");
mCalendar.set(Calendar.YEAR, Integer.parseInt(date[0]));
mCalendar.set(Calendar.MONTH, Integer.parseInt(date[1]) - 1);
mCalendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(date[2]));
if (mCalendar != null) {
finishingTime = new MillisecondsTimePoint(mCalendar.getTime());
} else {
finishingTime = null;
}
if (mHours != null) {
mCalendar.set(Calendar.HOUR_OF_DAY, mHours.getValue());
}
if (mMinutes != null) {
mCalendar.set(Calendar.MINUTE, mMinutes.getValue());
}
if (mSeconds != null) {
mCalendar.set(Calendar.SECOND, mSeconds.getValue());
}
finishingTime = new MillisecondsTimePoint(mCalendar.getTime());
}
String comment = null;
if (mComment != null) {
@@ -217,19 +219,50 @@ public class CompetitorEditLayout extends ScrollView {
return new CompetitorResultWithIdImpl(mCompetitor.getId(), result);
}
private void formatPicker(@Nullable NumberPicker picker, int minValue, int maxValue) {
if (picker != null) {
picker.setMinValue(minValue);
picker.setMaxValue(maxValue);
picker.setFormatter(new NumberPicker.Formatter() {
@Override
public String format(int value) {
return String.format(Locale.US, "%02d", value);
}
});
ThemeHelper
.setPickerColor(getContext(), picker, getContext().getResources().getColor(R.color.dialog_color_text), getContext().getResources()
.getColor(R.color.dialog_color_button));
@Override
public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
if (mCalendar == null) {
mCalendar = (GregorianCalendar) Calendar.getInstance();
}
mCalendar.set(Calendar.YEAR, year);
mCalendar.set(Calendar.MONTH, monthOfYear);
mCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
showFinishTime();
}
@Override
public void onTimeSet(FullTimePickerDialog dialog, int hourOfDay, int minute, int second) {
if (mCalendar == null) {
mCalendar = (GregorianCalendar) Calendar.getInstance();
}
mCalendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
mCalendar.set(Calendar.MINUTE, minute);
mCalendar.set(Calendar.SECOND, second);
showFinishTime();
}
private void showFinishTime() {
SimpleDateFormat date = new SimpleDateFormat("dd.MM.yyyy", Locale.getDefault());
SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
if (mFinishDate != null) {
if (mCalendar != null) {
mFinishDate.setText(date.format(mCalendar.getTime()));
} else {
mFinishDate.setText(null);
}
}
if (mFinishTime != null) {
if (mCalendar != null) {
mFinishTime.setText(time.format(mCalendar.getTime()));
} else {
mFinishTime.setText(null);
}
}
mDelete.setEnabled(mCalendar != null);
for (int i = 0; i < mDelete.getChildCount(); i++) {
mDelete.getChildAt(i).setEnabled(mDelete.isEnabled());
}
}
}
@@ -1,5 +1,9 @@
package com.sap.sailing.racecommittee.app.ui.views;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.utils.TouchEventListener;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.TypedArray;
@@ -17,78 +21,26 @@ import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.utils.TouchEventListener;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
public class PanelButton extends FrameLayout implements DialogInterface.OnClickListener {
public final static int LEVEL_UNKNOWN = -1;
public final static int LEVEL_NORMAL = 0;
public final static int LEVEL_TOGGLED = 1;
public enum PanelType {
Value(0),
Image(1),
Switch(2),
Flag(3);
private int value;
PanelType(int type) {
value = type;
}
@Nullable
public static PanelType fromId(int id) {
for (PanelType type : PanelType.values()) {
if (type.value == id) {
return type;
}
}
return null;
}
}
public enum CaptionPosition {
top(0),
bottom(1);
private int value;
CaptionPosition(int position) {
value = position;
}
@Nullable
public static CaptionPosition fromId(int id) {
for (CaptionPosition position : CaptionPosition.values()) {
if (position.value == id) {
return position;
}
}
return null;
}
}
private View mLayer;
private View mLock;
private String mCaption;
private TextView mHeader;
private TextView mFooter;
private View mContent;
private TextView mValue;
private View mImageLayout;
private ImageView mImage;
private ImageView mAdditionalImage;
private Switch mSwitch;
private ImageView mMarker;
private View mLine;
private PanelType mType;
private CaptionPosition mCaptionPosition;
private PanelButtonClick mListener;
private TouchEventListener mTouchEventListener;
@@ -148,6 +100,7 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
mValue = (TextView) findViewById(R.id.panel_value);
setPanelText(a.getString(R.styleable.PanelButton_buttonValue));
mImageLayout = findViewById(R.id.panel_image_layout);
mImage = (ImageView) findViewById(R.id.panel_image);
int size = a.getDimensionPixelSize(R.styleable.PanelButton_imageSize, 0);
if (size > 0) {
@@ -167,6 +120,10 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
setLinePosition(a.getInt(R.styleable.PanelButton_linePosition, -1));
mAdditionalImage = (ImageView) findViewById(R.id.panel_additional_image);
mAdditionalImage.setVisibility(GONE);
setButtonAdditionalImage(a.getDrawable(R.styleable.PanelButton_buttonAdditionalImage));
a.recycle();
setMarkerLevel(LEVEL_NORMAL);
@@ -266,6 +223,18 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
}
}
public void setButtonAdditionalImage(Drawable drawable) {
if (mAdditionalImage != null) {
mAdditionalImage.setImageDrawable(drawable);
}
}
public void showAdditionalImage(boolean show) {
if (mAdditionalImage != null) {
mAdditionalImage.setVisibility(show ? VISIBLE : GONE);
}
}
public void setPanelSwitch(@StringRes int id) {
setPanelSwitch(getResources().getString(id));
}
@@ -311,8 +280,8 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
mValue.setVisibility(GONE);
}
if (mImage != null) {
mImage.setVisibility(GONE);
if (mImageLayout != null) {
mImageLayout.setVisibility(GONE);
}
if (mSwitch != null) {
@@ -327,8 +296,8 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
break;
case Image:
if (mImage != null) {
mImage.setVisibility(VISIBLE);
if (mImageLayout != null) {
mImageLayout.setVisibility(VISIBLE);
}
break;
@@ -442,9 +411,51 @@ public class PanelButton extends FrameLayout implements DialogInterface.OnClickL
return mTouchEventListener.onTouchEvent(event);
}
public enum PanelType {
Value(0), Image(1), Switch(2), Flag(3);
private int value;
PanelType(int type) {
value = type;
}
@Nullable
public static PanelType fromId(int id) {
for (PanelType type : PanelType.values()) {
if (type.value == id) {
return type;
}
}
return null;
}
}
public enum CaptionPosition {
top(0), bottom(1);
private int value;
CaptionPosition(int position) {
value = position;
}
@Nullable
public static CaptionPosition fromId(int id) {
for (CaptionPosition position : CaptionPosition.values()) {
if (position.value == id) {
return position;
}
}
return null;
}
}
public interface PanelButtonClick {
void onClick(PanelButton view);
void onChangedSwitch(PanelButton view, boolean isChecked);
}
}
@@ -19,10 +19,10 @@ public class StringHelper {
}
public String getAuthor(String author) {
if (AppConstants.AUTHOR_TYPE_OFFICER_START.equals(author)) {
author = mContext.getString(R.string.author_type_officer_start);
} else if (AppConstants.AUTHOR_TYPE_OFFICER_FINISH.equals(author)) {
author = mContext.getString(R.string.author_type_officer_finish);
if (AppConstants.AUTHOR_TYPE_OFFICER_VESSEL.equals(author)) {
author = mContext.getString(R.string.author_type_officer_vessel);
} else if (AppConstants.AUTHOR_TYPE_SUPERUSER.equals(author)) {
author = mContext.getString(R.string.author_type_superuser);
} else if (AppConstants.AUTHOR_TYPE_SHORE_CONTROL.equals(author)) {
author = mContext.getString(R.string.author_type_shore_control);
} else if (AppConstants.AUTHOR_TYPE_VIEWER.equals(author)) {
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#9e9e9e"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#9e9e9e"
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#f0ab00"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFEEAA29"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="36dp"
android:height="36dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFEEAA29"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="48dp"
android:height="48dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFEEAA29"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="64dp"
android:height="64dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFEEAA29"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="96dp"
android:height="96dp"
android:viewportHeight="24.0"
android:viewportWidth="24.0">
<path
android:fillColor="#FFEEAA29"
android:pathData="M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z" />
</vector>