a first version of a nav drawer that uses a majorly refactored filter and sorting design; filter implementation still empty, test not compiling

Change-Id: I2711757df7d4e72f6c627d2daacabb7b22e6e16f
This commit is contained in:
Axel Uhl committed 2016-04-21 18:23:05 +02:00
1 parent a833c463c6
commit 139f5b4ad4
12 files changed
+380 -493

No files matched your search

@@ -1,10 +1,9 @@
package com.sap.sailing.racecommittee.app.domain.impl;
import android.text.TextUtils;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.SeriesBase;
import com.sap.sailing.domain.base.racegroup.RaceGroup;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeries;
import com.sap.sailing.domain.common.LeaderboardNameConstants;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sse.common.Util;
@@ -18,50 +17,25 @@ import com.sap.sse.common.Util;
* @author Axel Uhl (d043530)
*
*/
public class RaceGroupSeriesFleet {
public class RaceGroupSeriesFleet extends RaceGroupSeries {
private RaceGroup raceGroup;
private Fleet fleet;
private SeriesBase series;
private int seriesOrder;
private int fleetOrder;
public RaceGroupSeriesFleet(ManagedRace race) {
raceGroup = race.getRaceGroup();
series = race.getSeries();
super(race);
fleet = race.getFleet();
seriesOrder = getSeriesIndex(race, series);
fleetOrder = getFleetIndex(series.getFleets(), race.getFleet());
}
private static int getSeriesIndex(ManagedRace race, SeriesBase series) {
return Util.indexOf(race.getRaceGroup().getSeries(), series);
fleetOrder = getFleetIndex(race.getSeries().getFleets(), race.getFleet());
}
private int getFleetIndex(Iterable<? extends Fleet> fleets, Fleet fleet) {
return Util.indexOf(fleets, fleet);
}
public RaceGroup getRaceGroup() {
return raceGroup;
}
public SeriesBase getSeries() {
return series;
}
public Fleet getFleet() {
return fleet;
}
public String getRaceGroupName() {
return raceGroup.getName();
}
public String getSeriesName() {
return series.getName();
}
public String getFleetName() {
return fleet.getName();
}
@@ -71,23 +45,13 @@ public class RaceGroupSeriesFleet {
}
public String getDisplayName(boolean useDisplayName) {
String name = raceGroup.getDisplayName();
if (!useDisplayName || TextUtils.isEmpty(name)) {
name = raceGroup.getName();
}
if (series != null && !series.getName().equals(LeaderboardNameConstants.DEFAULT_SERIES_NAME)) {
name += " - " + series.getName();
}
String name = super.getDisplayName(useDisplayName);
if (fleet != null && !fleet.getName().equals(LeaderboardNameConstants.DEFAULT_FLEET_NAME)) {
name += " - " + fleet.getName();
}
return name;
}
public int getSeriesOrder() {
return seriesOrder;
}
public int getFleetOrder() {
return fleetOrder;
}
@@ -95,11 +59,8 @@ public class RaceGroupSeriesFleet {
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((raceGroup == null) ? 0 : raceGroup.hashCode());
result = prime * result + ((series == null) ? 0 : series.hashCode());
int result = super.hashCode();
result = prime * result + ((fleet == null) ? 0 : fleet.hashCode());
result = prime * result + seriesOrder;
result = prime * result + fleetOrder;
return result;
}
@@ -108,38 +69,18 @@ public class RaceGroupSeriesFleet {
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
RaceGroupSeriesFleet other = (RaceGroupSeriesFleet) obj;
if (raceGroup == null) {
if (other.raceGroup != null) {
return false;
}
} else if (!raceGroup.equals(other.raceGroup)) {
return false;
}
if (fleet == null) {
if (other.fleet != null) {
if (other.fleet != null)
return false;
}
} else if (!fleet.equals(other.fleet)) {
} else if (!fleet.equals(other.fleet))
return false;
}
if (series == null) {
if (other.series != null) {
return false;
}
} else if (!series.equals(other.series)) {
if (fleetOrder != other.fleetOrder)
return false;
}
if (seriesOrder != other.seriesOrder) {
return false;
}
if (fleetOrder != other.fleetOrder) {
return false;
}
return true;
}
@@ -2,7 +2,41 @@ package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.FlagPoleState;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.base.SeriesBase;
import com.sap.sailing.domain.base.racegroup.CurrentRaceComparator;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeries;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeriesComparator;
import com.sap.sailing.domain.common.racelog.FlagPole;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceFilter.FilterSubscriber;
import com.sap.sailing.racecommittee.app.ui.utils.FlagsResources;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import android.content.Context;
import android.content.Intent;
@@ -19,39 +53,16 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
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.SimpleRaceLogIdentifier;
import com.sap.sailing.domain.abstractlog.race.analyzing.impl.StartTimeFinderResult;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.FlagPoleState;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.RacingProcedure;
import com.sap.sailing.domain.common.racelog.FlagPole;
import com.sap.sailing.domain.common.racelog.Flags;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceFilter.FilterSubscriber;
import com.sap.sailing.racecommittee.app.ui.utils.FlagsResources;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> implements FilterSubscriber {
private final static String TAG = ManagedRaceListAdapter.class.getName();
private final Object mLockObject = new Object();
private List<RaceListDataType> mAllViewItems;
private RaceFilter mFilter;
private final RaceFilter mFilter;
private LayoutInflater mInflater;
private Resources mResources;
private List<RaceListDataType> mShownViewItems;
private final List<RaceListDataType> mShownViewItems;
private final Map<ManagedRace, RaceListDataTypeRace> viewItemsRaces;
private final Map<SeriesBase, RaceListDataTypeHeader> viewItemsSeriesHeaders;
private ImageView marker;
private ImageView update_badge;
private LinearLayout race_flag;
@@ -75,12 +86,16 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
private TextView explicit_factor;
private int flag_size;
private DecimalFormat factor_format;
private final Set<ManagedRace> mAllRaces;
public ManagedRaceListAdapter(Context context, List<RaceListDataType> viewItems) {
public ManagedRaceListAdapter(Context context, Set<ManagedRace> allRaces) {
super(context, 0);
mAllViewItems = viewItems;
mShownViewItems = viewItems;
mAllRaces = allRaces;
mShownViewItems = new ArrayList<>();
this.viewItemsRaces = new HashMap<>();
this.viewItemsSeriesHeaders = new HashMap<>();
createViewItemsForRacesAndSeries();
mFilter = new RaceFilter(allRaces, this);
mInflater = LayoutInflater.from(getContext());
mResources = getContext().getResources();
dateFormat = new SimpleDateFormat("kk:mm", getContext().getResources().getConfiguration().locale);
@@ -88,6 +103,25 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
factor_format = new DecimalFormat(context.getString(R.string.race_factor_format));
}
@Override
public void notifyDataSetChanged() {
super.notifyDataSetChanged();
createViewItemsForRacesAndSeries();
getFilter().filter("");
}
private void createViewItemsForRacesAndSeries() {
viewItemsRaces.clear();
viewItemsSeriesHeaders.clear();
for (final ManagedRace race : mAllRaces) {
viewItemsRaces.put(race, new RaceListDataTypeRace(race, mInflater));
final SeriesBase series = race.getSeries();
if (!viewItemsSeriesHeaders.containsKey(series)) {
viewItemsSeriesHeaders.put(series, new RaceListDataTypeHeader(new RaceGroupSeries(race), mInflater));
}
}
}
@Override
public int getCount() {
synchronized (mLockObject) {
@@ -97,9 +131,6 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
@Override
public RaceFilter getFilter() {
if (mFilter == null) {
mFilter = new RaceFilter(mAllViewItems, this);
}
return mFilter;
}
@@ -122,18 +153,13 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
@Override
public View getView(int position, View convertView, ViewGroup parent) {
RaceListDataType raceListElement;
raceListElement = getItem(position);
final RaceListDataType raceListElement = getItem(position);
int type = getItemViewType(position);
TimePoint now = MillisecondsTimePoint.now();
if (convertView == null) {
if (type == ViewType.HEADER.index) {
convertView = mInflater.inflate(R.layout.race_list_area_header, parent, false);
} else if (type == ViewType.RACE.index) {
convertView = mInflater.inflate(R.layout.race_list_area_item, parent, false);
}
convertView = raceListElement.getView(parent);
}
findViews(convertView);
resetValues(convertView);
@@ -145,11 +171,7 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
regatta = header.getRaceGroup().getName();
}
boat_class.setText(regatta);
if (header.isFleetVisible()) {
fleet_series.setText(RaceHelper.getFleetSeries(header.getFleet(), header.getSeries()));
} else {
fleet_series.setText(RaceHelper.getSeriesName(header.getSeries(), ""));
}
fleet_series.setText(RaceHelper.getSeriesName(header.getSeries(), ""));
if (fleet_series.getText().length() == 0) {
fleet_series.setVisibility(View.GONE);
} else {
@@ -259,13 +281,68 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
}
@Override
public void onResult(List<RaceListDataType> filtered) {
public void onResult(List<ManagedRace> filteredRaces) {
synchronized (mLockObject) {
mShownViewItems = filtered;
mShownViewItems.clear();
mShownViewItems.addAll(getShownViewItems(filteredRaces));
notifyDataSetChanged();
}
}
/**
* For the {@code filteredRaces} ensure that exactly the required view items are in {@link #mShownViewItems}. This
* encompasses the header items for all non-empty series and the race items for all races in their series.
*/
private List<RaceListDataType> getShownViewItems(List<ManagedRace> races) {
final Map<RaceListDataTypeHeader, List<RaceListDataTypeRace>> raceItemsByHeader = getRaceItemsGroupedBySeriesHeader(races);
final List<RaceListDataType> result = serializeItems(raceItemsByHeader);
return result;
}
private List<RaceListDataType> serializeItems(final Map<RaceListDataTypeHeader, List<RaceListDataTypeRace>> raceItemsByHeader) {
final List<RaceListDataType> result = new ArrayList<>();
final List<RaceListDataTypeHeader> headers = new ArrayList<>(raceItemsByHeader.keySet());
Collections.sort(headers, new Comparator<RaceListDataTypeHeader>() {
private final RaceGroupSeriesComparator c = new RaceGroupSeriesComparator();
@Override
public int compare(RaceListDataTypeHeader lhs, RaceListDataTypeHeader rhs) {
return c.compare(lhs.getRegattaSeries(), rhs.getRegattaSeries());
}
});
for (final RaceListDataTypeHeader header : headers) {
result.add(header);
final List<RaceListDataTypeRace> raceItems = new ArrayList<>(raceItemsByHeader.get(header));
Collections.sort(raceItems, new Comparator<RaceListDataTypeRace>() {
final CurrentRaceComparator c = new CurrentRaceComparator();
@Override
public int compare(RaceListDataTypeRace lhs, RaceListDataTypeRace rhs) {
return c.compare(lhs.getRace(), rhs.getRace());
}
});
for (final RaceListDataTypeRace raceItem : raceItems) {
result.add(raceItem);
}
}
return result;
}
private Map<RaceListDataTypeHeader, List<RaceListDataTypeRace>> getRaceItemsGroupedBySeriesHeader(final List<ManagedRace> filteredRaces) {
final Map<RaceListDataTypeHeader, List<RaceListDataTypeRace>> raceItemsByHeader = new HashMap<>();
for (final ManagedRace race : filteredRaces) {
final SeriesBase series = race.getSeries();
final RaceListDataTypeHeader seriesHeader = viewItemsSeriesHeaders.get(series);
List<RaceListDataTypeRace> raceItemsInSeries = raceItemsByHeader.get(seriesHeader);
if (raceItemsInSeries == null) {
raceItemsInSeries = new ArrayList<>();
raceItemsByHeader.put(seriesHeader, raceItemsInSeries);
}
raceItemsInSeries.add(viewItemsRaces.get(race));
}
return raceItemsByHeader;
}
public void setSelectedRace(RaceListDataType id) {
mSelectedRace = id;
}
@@ -1,16 +1,12 @@
package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.sap.sailing.domain.base.racegroup.CurrentRaceComparator;
import com.sap.sailing.domain.base.racegroup.CurrentRaceFilter;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.domain.base.racegroup.impl.CurrentRaceFilterImpl;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.domain.impl.RaceGroupSeriesFleet;
import com.sap.sailing.racecommittee.app.ui.fragments.RaceListFragment.FilterMode;
import android.widget.Filter;
@@ -19,23 +15,21 @@ import android.widget.Filter;
* Filters {@link ManagedRace} objects by status and place in the regatta structure. See {@link CurrentRaceFilter}. If
* the {@link #filterMode} is {@link FilterMode#ALL}, no filtering takes place at all, and all races will be displayed.
* If the {@link #filterMode} is {@link FilterMode#ACTIVE}, the set of races to be displayed is computed using a
* {@link CurrentRaceFilter}. For each race to be displayed, a {@link RaceListDataTypeRace} view item is produced. The
* races are grouped into sections, one for each series, and the items within each such series section are ordered using
* a {@link CurrentRaceComparator} while the series sections are ordered by the order in which the series appear in the
* Race Group / regatta.
* {@link CurrentRaceFilter}.
*/
public class RaceFilter extends Filter {
private final CurrentRaceFilter currentRaceFilter = new CurrentRaceFilterImpl();
public interface FilterSubscriber {
void onResult(List<RaceListDataType> filtered);
void onResult(List<ManagedRace> filtered);
}
protected final FilterSubscriber subscriber;
protected Collection<RaceListDataType> items;
protected FilterMode filterMode;
private final FilterSubscriber subscriber;
private final Set<ManagedRace> allRaces;
private FilterMode filterMode;
public RaceFilter(Collection<RaceListDataType> items, FilterSubscriber resultSubscriber) {
this.items = items;
public RaceFilter(Set<ManagedRace> allRaces, FilterSubscriber resultSubscriber) {
this.allRaces = allRaces;
this.subscriber = resultSubscriber;
}
@@ -44,7 +38,7 @@ public class RaceFilter extends Filter {
filter("");
}
protected static FilterResults createResults(Collection<RaceListDataType> result) {
protected static FilterResults createResults(Set<ManagedRace> result) {
FilterResults results = new FilterResults();
results.values = new ArrayList<>(result);
results.count = result.size();
@@ -53,192 +47,21 @@ public class RaceFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults result;
if (filterMode == null || filterMode.equals(FilterMode.ALL)) {
return createResults(items);
result = createResults(allRaces);
} else {
// filter using the CurrentRaceFilter
result = createResults(currentRaceFilter.filterCurrentRaces(allRaces));
}
List<RaceListDataType> filteredItems = new ArrayList<>();
RaceListDataTypeRace currentUnscheduledItem = null;
String currentUnscheduledRaceName = "";
String currentRegattaName = "";
RaceGroupSeriesFleet currentlyRunningFleet = null;
boolean showCurrentFleet;
Map<String, Boolean> finalsStarted = new HashMap<>();
int finishedItems = 0;
int subItems = -1;
List<RaceListDataTypeHeader> headersToRemove = new ArrayList<>();
RaceListDataTypeHeader previousHeader = null;
Map<String, Integer> fleetItemCount = new HashMap<>();
Map<String, Integer> lastRunningRaceInFleet = new HashMap<>();
List<RaceListDataType> allItems = new ArrayList<>(items);
detectStartedFinalsOrMedals(finalsStarted, allItems);
filterByFinalOrMedal(finalsStarted, headersToRemove, allItems);
for (RaceListDataType item : allItems) {
if (item instanceof RaceListDataTypeHeader) {
showCurrentFleet = subItems < 0 || (subItems > 0 && subItems != finishedItems);
if (previousHeader != null && subItems > 0 && subItems == finishedItems && !showCurrentFleet) {
headersToRemove.add(previousHeader);
}
showCurrentFleet = false;
// Mark race header (including races) of subsequent series to be removed if previous series was not in last race
if (fleetItemCount.isEmpty() && lastRunningRaceInFleet.isEmpty()) {
showCurrentFleet = true;
} else {
for (String key : fleetItemCount.keySet()) {
if (fleetItemCount.get(key).equals(lastRunningRaceInFleet.get(key))) {
showCurrentFleet = true;
break;
}
}
}
RaceListDataTypeHeader headerItem = (RaceListDataTypeHeader) item;
filteredItems.add(headerItem);
// new run for all types!
previousHeader = headerItem;
if (!showCurrentFleet) {
if (currentRegattaName.equals("") || currentRegattaName.equals(headerItem.getRaceGroup().getName())) {
headersToRemove.add(headerItem);
}
}
fleetItemCount.clear();
lastRunningRaceInFleet.clear();
currentUnscheduledRaceName = "";
currentRegattaName = previousHeader.getRaceGroup().getName();
currentUnscheduledItem = null;
currentlyRunningFleet = null;
finishedItems = 0;
subItems = 0;
} else if (item instanceof RaceListDataTypeRace) {
subItems++;
RaceListDataTypeRace raceItem = (RaceListDataTypeRace) item;
String fleetName = getFleetName(raceItem);
countFleetItems(fleetItemCount, fleetName);
boolean qualifying = raceItem.getRace().getFleet().getOrdering() == 0 || !raceItem.getRace().getSeries().isMedal();
RaceLogRaceStatus status = raceItem.getCurrentStatus();
// Preserve first unscheduled races that belong to the first race column of the leaderboard
if (qualifying && RaceLogRaceStatus.UNSCHEDULED.equals(status)) {
if (currentUnscheduledRaceName.equals("")) {
currentUnscheduledRaceName = raceItem.getRaceName();
}
if (currentUnscheduledRaceName.equals(raceItem.getRaceName())) {
filteredItems.add(raceItem);
if (currentlyRunningFleet == null) {
currentUnscheduledItem = raceItem;
}
}
}
if (currentUnscheduledItem == null && RaceLogRaceStatus.UNSCHEDULED.equals(status)) {
if (currentlyRunningFleet == null || currentlyRunningFleet.equals(raceItem.getFleet())) {
currentUnscheduledItem = raceItem;
if (!filteredItems.contains(raceItem)) {
filteredItems.add(raceItem);
}
}
} else if (RaceLogRaceStatus.FINISHED.equals(status)) {
finishedItems++;
if (filteredItems.contains(raceItem)) {
filteredItems.remove(raceItem);
}
int fleetCount = fleetItemCount.get(getFleetName(raceItem));
lastRunningRaceInFleet.put(getFleetName(raceItem), fleetCount);
currentlyRunningFleet = raceItem.getFleet();
currentUnscheduledItem = null;
} else if(RaceLogRaceStatus.isPreRunning(status)) {
filteredItems.add(raceItem);
currentUnscheduledItem = null;
currentlyRunningFleet = raceItem.getFleet();
}
else if (RaceLogRaceStatus.isActive(status)) {
int fleetCount = fleetItemCount.get(getFleetName(raceItem));
lastRunningRaceInFleet.put(getFleetName(raceItem), fleetCount);
filteredItems.add(raceItem);
currentUnscheduledItem = null;
currentlyRunningFleet = raceItem.getFleet();
}
}
}
if (previousHeader != null && subItems > 0 && subItems == finishedItems) {
headersToRemove.add(previousHeader);
}
removeFinishedSeries(filteredItems, headersToRemove);
return createResults(filteredItems);
return result;
}
private String getFleetName(RaceListDataTypeRace raceItem) {
return raceItem.getRace().getIdentifier().getFleet().getName();
}
private void countFleetItems(Map<String, Integer> fleetItemCount, String fleetName) {
if (!fleetItemCount.containsKey(fleetName)) {
fleetItemCount.put(fleetName, 0);
}
int count = fleetItemCount.get(fleetName) + 1;
fleetItemCount.put(fleetName, count);
}
private void filterByFinalOrMedal(Map<String, Boolean> finalsStarted, List<RaceListDataTypeHeader> headersToRemove,
List<RaceListDataType> allItems) {
RaceListDataTypeHeader currentHeader = null;
List<RaceListDataType> racesToRemove = new ArrayList<>();
for (RaceListDataType item : allItems) {
if (item instanceof RaceListDataTypeHeader) {
currentHeader = (RaceListDataTypeHeader) item;
} else if (item instanceof RaceListDataTypeRace) {
RaceListDataTypeRace raceItem = (RaceListDataTypeRace) item;
if (raceItem.getRace().getFleet().getOrdering() == 0 && !raceItem.getRace().getSeries().isMedal()) {
String regattaName = raceItem.getRace().getRaceGroup().getName();
if (finalsStarted.containsKey(regattaName) && currentHeader != null) {
headersToRemove.add(currentHeader);
racesToRemove.add(raceItem);
}
}
}
}
allItems.removeAll(racesToRemove);
}
private void detectStartedFinalsOrMedals(Map<String, Boolean> finalsStarted, List<RaceListDataType> allItems) {
for (RaceListDataType item : allItems) {
if (item instanceof RaceListDataTypeRace) {
RaceListDataTypeRace raceItem = (RaceListDataTypeRace) item;
String regattaName = raceItem.getRace().getRaceGroup().getName();
if (raceItem.getRace().getFleet().getOrdering() != 0 || raceItem.getRace().getSeries().isMedal()) {
if (RaceLogRaceStatus.isRunningOrFinished(raceItem.getCurrentStatus())) {
finalsStarted.put(regattaName, true);
}
}
}
}
}
private void removeFinishedSeries(List<RaceListDataType> filteredItems, List<RaceListDataTypeHeader> headersToRemove) {
List<RaceListDataType> itemsToKeep = new ArrayList<>();
boolean keepItems = false;
for (RaceListDataType item : filteredItems) {
if (item instanceof RaceListDataTypeHeader) {
keepItems = !headersToRemove.contains(item);
if (keepItems) {
itemsToKeep.add(item);
}
} else if (item instanceof RaceListDataTypeRace) {
if (keepItems) {
itemsToKeep.add(item);
}
}
}
filteredItems.clear();
filteredItems.addAll(itemsToKeep);
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
subscriber.onResult((List<RaceListDataType>) results.values);
@SuppressWarnings("unchecked")
final List<ManagedRace> filterResults = (List<ManagedRace>) results.values;
subscriber.onResult(filterResults);
}
}
@@ -1,5 +1,7 @@
package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
import android.view.View;
import android.view.ViewGroup;
/*
* author: I065873
@@ -7,6 +9,5 @@ package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
* Data Type for displaying the Race list in the left part of the second activity
*/
public interface RaceListDataType {
View getView(ViewGroup parent);
}
@@ -1,26 +1,29 @@
package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.SeriesBase;
import com.sap.sailing.domain.base.racegroup.IsFleetFragment;
import com.sap.sailing.domain.base.racegroup.RaceGroup;
import com.sap.sailing.racecommittee.app.domain.impl.RaceGroupSeriesFleet;
import com.sap.sailing.domain.base.racegroup.RaceGroupSeries;
import com.sap.sailing.racecommittee.app.R;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class RaceListDataTypeHeader implements RaceListDataType, IsFleetFragment {
private RaceGroupSeries data;
private final LayoutInflater mInflater;
private RaceGroupSeriesFleet data;
private boolean isFleetVisible;
public RaceListDataTypeHeader(RaceGroupSeriesFleet data) {
this(data, true);
public RaceListDataTypeHeader(RaceGroupSeries data, LayoutInflater layoutInflater) {
this(data, true, layoutInflater);
}
public RaceListDataTypeHeader(RaceGroupSeriesFleet data, boolean isFleetVisible) {
public RaceListDataTypeHeader(RaceGroupSeries data, boolean isFleetVisible, LayoutInflater layoutInflater) {
this.data = data;
this.isFleetVisible = isFleetVisible;
this.mInflater = layoutInflater;
}
public RaceGroupSeriesFleet getRegattaSeriesFleet() {
public RaceGroupSeries getRegattaSeries() {
return data;
}
@@ -32,14 +35,14 @@ public class RaceListDataTypeHeader implements RaceListDataType, IsFleetFragment
return data.getSeries();
}
public Fleet getFleet() {
return data.getFleet();
}
public boolean isFleetVisible() { return isFleetVisible; }
@Override
public String toString() {
return data.getDisplayName();
}
@Override
public View getView(ViewGroup parent) {
return mInflater.inflate(R.layout.race_list_area_header, parent, false);
}
}
@@ -5,6 +5,9 @@ import java.text.SimpleDateFormat;
import java.util.Locale;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.racecommittee.app.R;
@@ -23,10 +26,11 @@ public class RaceListDataTypeRace implements RaceListDataType {
private static String finishedTemplate;
private static String unknownTemplate;
private final ManagedRace race;
private final RaceGroupSeriesFleet fleet;
private final LayoutInflater mInflater;
private boolean updateIndicatorVisible = false;
private RaceLogRaceStatus currentStatus = RaceLogRaceStatus.UNKNOWN;
private ManagedRace race;
private RaceGroupSeriesFleet fleet;
private Format scheduleFormatter = new SimpleDateFormat("HH:mm", Locale.US);
@@ -41,14 +45,15 @@ public class RaceListDataTypeRace implements RaceListDataType {
unknownTemplate = fragment.getString(R.string.racelist_unknown);
}
public RaceListDataTypeRace(ManagedRace race) {
this(race, null);
public RaceListDataTypeRace(ManagedRace race, LayoutInflater layoutInflater) {
this(race, null, layoutInflater);
}
public RaceListDataTypeRace(ManagedRace race, RaceGroupSeriesFleet fleet) {
public RaceListDataTypeRace(ManagedRace race, RaceGroupSeriesFleet fleet, LayoutInflater layoutInflater) {
this.race = race;
this.fleet = fleet;
this.currentStatus = race.getStatus();
this.mInflater = layoutInflater;
}
public void onStatusChanged(RaceLogRaceStatus status, boolean allowUpdateIndicator) {
@@ -114,4 +119,9 @@ public class RaceListDataTypeRace implements RaceListDataType {
return scheduleFormatter.format(startTime.asDate());
}
@Override
public View getView(ViewGroup parent) {
return mInflater.inflate(R.layout.race_list_area_item, parent, false);
}
}
@@ -1,14 +1,38 @@
package com.sap.sailing.racecommittee.app.ui.fragments;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
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.domain.abstractlog.race.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.BaseRaceStateChangedListener;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.AppPreferences;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.RaceApplication;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.domain.impl.RaceGroupSeriesFleet;
import com.sap.sailing.racecommittee.app.ui.activities.SessionActivity;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.ManagedRaceListAdapter;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataType;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataTypeRace;
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.ProtestTimeDialogFragment;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
import com.sap.sailing.racecommittee.app.utils.StringHelper;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TickListener;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.BroadcastReceiver;
@@ -41,34 +65,6 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
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.state.ReadonlyRaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.BaseRaceStateChangedListener;
import com.sap.sailing.domain.base.SeriesBase;
import com.sap.sailing.racecommittee.app.AppConstants;
import com.sap.sailing.racecommittee.app.AppPreferences;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.RaceApplication;
import com.sap.sailing.racecommittee.app.data.DataManager;
import com.sap.sailing.racecommittee.app.data.ReadonlyDataManager;
import com.sap.sailing.racecommittee.app.domain.ManagedRace;
import com.sap.sailing.racecommittee.app.domain.impl.RaceGroupSeriesFleet;
import com.sap.sailing.racecommittee.app.ui.activities.SessionActivity;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.ManagedRaceListAdapter;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataType;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataTypeHeader;
import com.sap.sailing.racecommittee.app.ui.adapters.racelist.RaceListDataTypeRace;
import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.ProtestTimeDialogFragment;
import com.sap.sailing.racecommittee.app.utils.RaceHelper;
import com.sap.sailing.racecommittee.app.utils.StringHelper;
import com.sap.sailing.racecommittee.app.utils.ThemeHelper;
import com.sap.sailing.racecommittee.app.utils.TickListener;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
import com.sap.sse.common.TimePoint;
public class RaceListFragment extends LoggableFragment implements OnItemClickListener, OnItemSelectedListener, TickListener, OnScrollListener {
private final static String TAG = RaceListFragment.class.getName();
@@ -88,8 +84,8 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
private ManagedRace mSelectedRace;
private IntentReceiver mReceiver;
private boolean mUpdateList = true;
private ArrayList<RaceListDataType> mViewItems;
private View mProgress;
private final Set<ManagedRace> mAllRaces;
private BaseRaceStateChangedListener stateListener = new BaseRaceStateChangedListener() {
@Override
@@ -107,13 +103,12 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
filterChanged();
}
};
public RaceListFragment() {
mFilterMode = FilterMode.ACTIVE;
mSelectedRace = null;
mManagedRacesById = new LinkedHashMap<>();
mRacesByGroup = new LinkedHashMap<>();
mViewItems = new ArrayList<>();
mAllRaces = new HashSet<>();
}
public static RaceListFragment newInstance(int layout) {
@@ -202,7 +197,7 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
super.onActivityCreated(savedInstanceState);
RaceListDataTypeRace.initializeTemplates(this);
if (mListView != null) {
mAdapter = new ManagedRaceListAdapter(getActivity(), mViewItems);
mAdapter = new ManagedRaceListAdapter(getActivity(), mAllRaces);
mListView.setAdapter(mAdapter);
mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
mListView.setOnItemClickListener(this);
@@ -404,98 +399,16 @@ public class RaceListFragment extends LoggableFragment implements OnItemClickLis
}
}
private void initializeRacesByGroup() {
mRacesByGroup.clear();
for (ManagedRace race : mManagedRacesById.values()) {
RaceGroupSeriesFleet container = new RaceGroupSeriesFleet(race);
if (!mRacesByGroup.containsKey(container)) {
mRacesByGroup.put(container, new LinkedList<ManagedRace>());
}
mRacesByGroup.get(container).add(race);
}
}
private void initializeViewElements() {
// 1. Group races by <boat class, series, fleet>
initializeRacesByGroup();
// 2. Remove previous view items
mViewItems.clear();
// 3. Group active fleets from tree by series
Map<SeriesBase, List<RaceGroupSeriesFleet>> seriesWithFleets = getFleetsGroupedBySeries(mRacesByGroup.keySet());
// 4. Create view elements from series with fleets
for (SeriesBase series : seriesWithFleets.keySet()) {
List<RaceGroupSeriesFleet> fleets = seriesWithFleets.get(series);
if (fleets.size() == 1) { // Default fleet
// ... add the header view for default fleet...
RaceGroupSeriesFleet fleet = fleets.get(0);
mViewItems.add(new RaceListDataTypeHeader(fleet));
List<ManagedRace> races = mRacesByGroup.get(fleet);
for (ManagedRace race : races) {
// ... and add the race view!
mViewItems.add(new RaceListDataTypeRace(race));
}
} else if (fleets.size() > 1) {
// ... add the header view for all following fleets...
mViewItems.add(new RaceListDataTypeHeader(fleets.get(0), false));
// ... and add all the sorted race views!
List<RaceListDataTypeRace> raceListDataTypeRaces = getRaceListDataTypeRaces(mRacesByGroup, fleets);
raceListDataTypeRaces = sortRaceList(raceListDataTypeRaces, fleets.size());
for (RaceListDataTypeRace raceListDataTypeRace : raceListDataTypeRaces) {
mViewItems.add(raceListDataTypeRace);
}
}
}
}
private List<RaceListDataTypeRace> sortRaceList(List<RaceListDataTypeRace> raceList, int fleetSize) {
int racePerFleet = raceList.size() / fleetSize;
List<RaceListDataTypeRace> sortedList = new ArrayList<>();
for (int race = 0; race < racePerFleet; race++) {
for (int fleet = 0; fleet < fleetSize; fleet++) {
sortedList.add(raceList.get(race + (fleet * racePerFleet)));
}
}
return sortedList;
}
private static LinkedHashMap<SeriesBase, List<RaceGroupSeriesFleet>> getFleetsGroupedBySeries(Set<RaceGroupSeriesFleet> raceGroupSeriesFleets) {
LinkedHashMap<SeriesBase, List<RaceGroupSeriesFleet>> seriesWithFleets = new LinkedHashMap<>();
for (RaceGroupSeriesFleet key : raceGroupSeriesFleets) {
SeriesBase series = key.getSeries();
List<RaceGroupSeriesFleet> fleets = seriesWithFleets.get(series);
if (fleets == null) {
fleets = new ArrayList<>();
}
fleets.add(key);
seriesWithFleets.put(series, fleets);
}
return seriesWithFleets;
}
private static List<RaceListDataTypeRace> getRaceListDataTypeRaces(LinkedHashMap<RaceGroupSeriesFleet, List<ManagedRace>> racesByGroup,
List<RaceGroupSeriesFleet> fleets) {
List<RaceListDataTypeRace> races = new ArrayList<>();
for (RaceGroupSeriesFleet fleet : fleets) {
for (ManagedRace race : racesByGroup.get(fleet)) {
races.add(new RaceListDataTypeRace(race, fleet));
}
}
return races;
}
public void setupOn(Collection<ManagedRace> races) {
ExLog.i(getActivity(), TAG, String.format("Setting up %s with %d races.", this.getClass().getSimpleName(), races.size()));
public void setupOn(Iterable<ManagedRace> races) {
ExLog.i(getActivity(), TAG, String.format("Setting up %s with %d races.", this.getClass().getSimpleName(), Util.size(races)));
unregisterOnAllRaces();
mManagedRacesById.clear();
for (ManagedRace managedRace : races) {
mManagedRacesById.put(managedRace.getId(), managedRace);
}
mAllRaces.clear();
Util.addAll(races, mAllRaces);
registerOnAllRaces();
initializeViewElements();
// prepare views and do initial filtering
filterChanged();
mAdapter.notifyDataSetChanged();