fix: issues regarding race list in NavigationDrawer

race selection, flags and timers
This commit is contained in:
Robert Benedikt
2020-04-23 12:03:36 +02:00
parent a1737aec54
commit 771019551d
10 changed files with 581 additions and 630 deletions
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@color/light_sap_gray"
android:maxLevel="0" />
<item
android:drawable="@color/constant_sap_yellow_1"
android:maxLevel="1" />
</level-list>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_activated="true">
<color android:color="@color/constant_sap_yellow_1" />
</item>
<item>
<color android:color="@color/light_sap_gray" />
</item>
</selector>
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:parentTag="android.widget.LinearLayout"
android:orientation="vertical">
<ImageView
android:id="@+id/imageView"
android:layout_width="40dp"
android:layout_height="25dp"
android:layout_gravity="center"
android:scaleType="centerInside"
android:src="@drawable/flag_alpha_64dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:drawableLeft="?attr/arrow_down"
android:textAppearance="?attr/textXSmall"
tools:text="01:12'32&quot;" />
</merge>
@@ -2,78 +2,15 @@
<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"
android:background="?attr/sap_gray">
android:layout_height="@dimen/navigation_drawer_cell_height">
<LinearLayout
android:id="@+id/protest_layout"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="@color/white"
android:gravity="center_vertical"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="wrap_content"
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"
tools:visibility="visible" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingTop="3dp"
android:text="@string/protest_time"
android:textAppearance="?attr/textPanelCaption" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/delimiter_line"
android:layout_width="@dimen/thin_line"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/protest_layout"
android:background="?attr/black" />
<ImageView
android:id="@+id/bottom_line"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:background="?attr/black" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/navigation_drawer_text_margin"
android:layout_marginRight="@dimen/navigation_drawer_text_margin"
android:background="?sap_gray"
android:paddingLeft="@dimen/navigation_drawer_text_margin"
android:paddingRight="@dimen/navigation_drawer_text_margin"
android:layout_toLeftOf="@id/delimiter_line"
android:orientation="vertical">
@@ -95,4 +32,59 @@
android:textAppearance="?attr/textSmall"
tools:text="Day 1\nYellow" />
</LinearLayout>
<View
android:id="@+id/delimiter_line"
android:layout_width="@dimen/thin_line"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/protest_layout"
android:background="?attr/black" />
<LinearLayout
android:id="@+id/protest_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:background="?selectableItemBackground"
android:gravity="center"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
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"
tools:visibility="visible" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingTop="3dp"
android:text="@string/protest_time"
android:textAppearance="?attr/textPanelCaption" />
</LinearLayout>
<View
android:id="@+id/bottom_line"
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
android:background="?attr/black" />
</RelativeLayout>
@@ -2,92 +2,23 @@
<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">
android:layout_height="@dimen/navigation_drawer_cell_height"
xmlns:app="http://schemas.android.com/apk/res-auto">
<RelativeLayout
android:id="@+id/panel_right"
android:layout_width="@dimen/navigation_drawer_right_box"
<View
android:id="@+id/race_marker"
android:layout_width="@dimen/obesity_line"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true">
<LinearLayout
android:id="@+id/race_scheduled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="vertical">
<com.sap.sailing.racecommittee.app.ui.views.RaceTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="?attr/textXLarge"
tools:text="13:36" />
<TextView
android:id="@+id/race_started"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_started"
android:textAppearance="?attr/textXSmall" />
<TextView
android:id="@+id/race_finished"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_finished"
android:textAppearance="?attr/textXSmall" />
</LinearLayout>
<TextView
android:id="@+id/race_unscheduled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/race_unscheduled"
android:textColor="?attr/sap_light_gray"
android:textSize="@dimen/textSize_18"
android:visibility="gone" />
<ImageView
android:id="@+id/update_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:contentDescription="@string/updateIndicator"
android:scaleType="matrix"
android:src="@drawable/updated"
android:visibility="gone"
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:layout_margin="2dp"
android:src="@drawable/ic_warning_yellow"
android:visibility="gone"
tools:visibility="visible" />
</RelativeLayout>
android:duplicateParentState="true"
android:background="?attr/marker_race" />
<RelativeLayout
android:id="@+id/panel_left"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/panel_right"
android:layout_toStartOf="@id/panel_right">
android:layout_toStartOf="@id/panel_right"
android:layout_toLeftOf="@id/panel_right">
<ImageView
android:id="@+id/race_marker"
android:layout_width="@dimen/obesity_line"
android:layout_height="match_parent"
android:src="?attr/marker_race" />
<LinearLayout
android:id="@+id/additional_info"
@@ -106,53 +37,35 @@
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
<com.sap.sailing.racecommittee.app.ui.views.FlagTimeView
android:id="@+id/race_flag"
app:flagSize="@integer/flag_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible">
<ImageView
android:id="@+id/current_flag"
android:layout_width="40dp"
android:layout_height="25dp"
android:layout_gravity="center"
android:scaleType="centerInside"
tools:src="@drawable/flag_alpha_64dp" />
<com.sap.sailing.racecommittee.app.ui.views.FlagTimeView
android:id="@+id/flag_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:drawableLeft="?attr/arrow_down"
android:textAppearance="?attr/textXSmall"
tools:text="01:12" />
</LinearLayout>
tools:visibility="visible" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/navigation_drawer_text_margin"
android:layout_toLeftOf="@id/additional_info"
android:layout_toStartOf="@id/additional_info"
android:layout_toLeftOf="@id/additional_info"
android:orientation="vertical">
<TextView
android:id="@+id/race_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:singleLine="true"
android:textAppearance="?attr/textNormal"
tools:text="Race 3" />
android:id="@+id/race_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="middle"
android:singleLine="true"
android:textAppearance="?attr/textNormal"
tools:text="Race 3" />
<TextView
android:id="@+id/depends_on"
@@ -167,6 +80,78 @@
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/panel_right"
android:layout_width="@dimen/navigation_drawer_right_box"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true">
<ImageView
android:id="@+id/update_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:contentDescription="@string/updateIndicator"
android:scaleType="matrix"
android:src="@drawable/updated"
android:visibility="gone"
tools:visibility="visible" />
<ImageView
android:id="@+id/panel_additional_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="2dp"
android:src="@drawable/ic_warning_yellow"
android:visibility="gone"
tools:visibility="visible" />
<LinearLayout
android:id="@+id/race_scheduled"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:orientation="vertical">
<TextView
android:id="@+id/race_started"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_started"
android:textAppearance="?attr/textXSmall" />
<TextView
android:id="@+id/race_finished"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="@string/race_finished"
android:textAppearance="?attr/textXSmall" />
<com.sap.sailing.racecommittee.app.ui.views.RaceTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:textAppearance="?attr/textLarge"
tools:text="13:36" />
</LinearLayout>
<TextView
android:id="@+id/race_unscheduled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/race_unscheduled"
android:textColor="?attr/sap_light_gray"
android:textSize="@dimen/textSize_18"
android:visibility="gone" />
</RelativeLayout>
<TextView
android:id="@+id/explicit_factor"
android:layout_width="wrap_content"
@@ -177,7 +162,7 @@
android:textColor="?attr/white_invert"
tools:text="x 3.5" />
<ImageView
<View
android:layout_width="match_parent"
android:layout_height="@dimen/thin_line"
android:layout_alignParentBottom="true"
@@ -114,4 +114,8 @@
<attr name="flags_postpone" format="reference" />
<attr name="flags_recall" format="reference" />
<declare-styleable name="FlagTimeView">
<attr name="flagSize" format="integer" />
</declare-styleable>
</resources>
@@ -1,51 +1,9 @@
package com.sap.sailing.racecommittee.app.ui.adapters.racelist;
import com.sap.sailing.racecommittee.app.ui.views.FlagTimeView;
import java.text.DecimalFormat;
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.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;
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.domain.common.racelog.RaceLogRaceStatus;
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.ui.views.RaceTimeView;
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;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
@@ -56,6 +14,40 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
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;
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.Flags;
import com.sap.sailing.domain.common.racelog.RaceLogRaceStatus;
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.ui.views.FlagTimeView;
import com.sap.sailing.racecommittee.app.ui.views.RaceTimeView;
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.Util;
import java.text.DecimalFormat;
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;
public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> implements FilterSubscriber {
private final static String TAG = ManagedRaceListAdapter.class.getName();
@@ -102,7 +94,10 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
new RaceListDataTypeHeader(new RaceGroupSeries(race), mInflater, hasConflict));
} else {
if (hasConflict) {
viewItemsSeriesHeaders.get(series).setHasConflict(true);
final RaceListDataTypeHeader header = viewItemsSeriesHeaders.get(series);
if (header != null) {
header.setHasConflict(true);
}
}
}
}
@@ -115,6 +110,7 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
}
}
@NonNull
@Override
public RaceFilter getFilter() {
return mFilter;
@@ -137,17 +133,17 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
: getItem(position) instanceof RaceListDataTypeRace ? ViewType.RACE.index : -1);
}
@NonNull
@Override
public View getView(int position, View convertView, ViewGroup parent) {
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
final RaceListDataType raceListElement = getItem(position);
ViewHolder holder;
int type = getItemViewType(position);
TimePoint now = MillisecondsTimePoint.now();
if (convertView == null) {
convertView = raceListElement.getView(parent);
convertView = raceListElement == null ? mInflater.inflate(R.layout.race_list_area_item, parent, false) : raceListElement.getView(parent);
holder = new ViewHolder();
holder.findViews(convertView);
convertView.setTag(R.id.race_list_holder, holder);
@@ -158,96 +154,93 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
if (type == ViewType.HEADER.index) {
final RaceListDataTypeHeader header = (RaceListDataTypeHeader) raceListElement;
String regatta = header.getRaceGroup().getDisplayName();
String series = RaceHelper.getSeriesName(header.getSeries(), "");
if (header != null) {
String regatta = header.getRaceGroup().getDisplayName();
String series = RaceHelper.getSeriesName(header.getSeries(), "");
if (!(raceListElement).equals(convertView.getTag(R.id.race_list_header))) {
if (TextUtils.isEmpty(regatta)) {
regatta = header.getRaceGroup().getName();
}
holder.boat_class.setText(regatta);
holder.fleet_series.setText(series);
if (holder.fleet_series.getText().length() == 0) {
holder.fleet_series.setVisibility(View.GONE);
} else {
holder.fleet_series.setVisibility(View.VISIBLE);
}
holder.protest_image
.setImageDrawable(FlagsResources.getFlagDrawable(getContext(), Flags.BRAVO.name(), flag_size));
holder.protest_layout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!(raceListElement).equals(convertView.getTag(R.id.race_list_header))) {
if (TextUtils.isEmpty(regatta)) {
regatta = header.getRaceGroup().getName();
}
holder.boat_class.setText(regatta);
holder.fleet_series.setText(series);
if (holder.fleet_series.getText().length() == 0) {
holder.fleet_series.setVisibility(View.GONE);
} else {
holder.fleet_series.setVisibility(View.VISIBLE);
}
holder.protest_image
.setImageDrawable(FlagsResources.getFlagDrawable(getContext(), Flags.BRAVO.name(), flag_size));
holder.protest_layout.setOnClickListener(v -> {
Intent intent = new Intent(AppConstants.INTENT_ACTION_SHOW_PROTEST);
// TODO don't use toString() to convey semantics and perform check; bug 3617
intent.putExtra(AppConstants.INTENT_ACTION_EXTRA,
new RaceGroupSeries(header.getRaceGroup(), header.getSeries()).getDisplayName());
BroadcastManager.getInstance(getContext()).addIntent(intent);
}
});
holder.protest_warning_image.setVisibility(header.hasConflict() ? View.VISIBLE : View.GONE);
convertView.setTag(R.id.race_list_header, raceListElement);
});
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) {
final RaceListDataTypeRace race = (RaceListDataTypeRace) raceListElement;
if (mSelectedRace != null && mSelectedRace.equals(race)) {
holder.setMarker(1);
if (race.isUpdateIndicatorVisible()) {
race.setUpdateIndicatorVisible(false);
}
} else {
holder.setMarker(0);
if (race.isUpdateIndicatorVisible()) {
holder.update_badge.setVisibility(View.VISIBLE);
}
}
holder.race_name.setText(RaceHelper.getReverseRaceFleetName(race.getRace()));
RaceState state = race.getRace().getState();
holder.time.setRaceState(state);
if (state != null) {
CompetitorResults draft = state.getFinishPositioningList();
CompetitorResults confirmed = state.getConfirmedFinishPositioningList().getCompetitorResults();
holder.warning_sign.setVisibility(
((draft != null && draft.hasConflicts()) || confirmed != null && confirmed.hasConflicts())
? View.VISIBLE
: View.GONE);
if (state.getStartTime() != null) {
int startRes = R.string.race_started;
if (state.getFinishedTime() == null) {
startRes = R.string.race_start;
if (race != null) {
if (mSelectedRace != null && mSelectedRace.equals(race)) {
holder.itemView.setSelected(true);
if (race.isUpdateIndicatorVisible()) {
race.setUpdateIndicatorVisible(false);
}
String startTime = mResources.getString(startRes, TimeUtils.formatTime(state.getStartTime(), false));
holder.race_started.setText(startTime);
} else {
holder.itemView.setSelected(false);
if (race.isUpdateIndicatorVisible()) {
holder.update_badge.setVisibility(View.VISIBLE);
}
}
if (state.getFinishedTime() != null) {
holder.time.setVisibility(View.GONE);
holder.race_finished.setVisibility(View.VISIBLE);
holder.race_finished.setText(mResources.getString(R.string.race_finished,
TimeUtils.formatTime(state.getFinishedTime(), false)));
}
setDependingText(holder, race);
if (state.getStartTime() == null && state.getFinishedTime() == null) {
switch (race.getRace().getStatus()) {
case PRESCHEDULED:
holder.panel_right.setVisibility(View.GONE);
holder.race_scheduled.setVisibility(View.GONE);
holder.race_unscheduled.setVisibility(View.GONE);
break;
default:
holder.race_scheduled.setVisibility(View.GONE);
holder.race_unscheduled.setVisibility(View.VISIBLE);
holder.race_name.setText(RaceHelper.getReverseRaceFleetName(race.getRace()));
RaceState state = race.getRace().getState();
holder.race_flag_new.setRaceState(state);
holder.time.setRaceState(state);
if (state != null) {
CompetitorResults draft = state.getFinishPositioningList();
CompetitorResults confirmed = state.getConfirmedFinishPositioningList().getCompetitorResults();
holder.warning_sign.setVisibility(
((draft != null && draft.hasConflicts()) || confirmed != null && confirmed.hasConflicts())
? View.VISIBLE
: View.GONE);
if (state.getStartTime() != null) {
int startRes = R.string.race_started;
if (state.getFinishedTime() == null) {
startRes = R.string.race_start;
}
String startTime = mResources.getString(startRes, TimeUtils.formatTime(state.getStartTime(), false));
holder.race_started.setText(startTime);
}
if (state.getFinishedTime() != null) {
holder.race_flag_new.setVisibility(View.GONE);
holder.time.setVisibility(View.GONE);
holder.race_finished.setVisibility(View.VISIBLE);
holder.race_finished.setText(mResources.getString(R.string.race_finished,
TimeUtils.formatTime(state.getFinishedTime(), false)));
}
setDependingText(holder, race);
if (state.getStartTime() == null && state.getFinishedTime() == null) {
if (race.getRace().getStatus() == RaceLogRaceStatus.PRESCHEDULED) {
holder.panel_right.setVisibility(View.GONE);
holder.race_scheduled.setVisibility(View.GONE);
holder.race_unscheduled.setVisibility(View.GONE);
} else {
holder.race_scheduled.setVisibility(View.GONE);
holder.race_unscheduled.setVisibility(View.VISIBLE);
}
}
}
}
Double factor = race.getRace().getExplicitFactor();
if (factor != null) {
holder.explicit_factor.setText(factor_format.format(factor));
holder.explicit_factor.setVisibility(View.VISIBLE);
Double factor = race.getRace().getExplicitFactor();
if (factor != null) {
holder.explicit_factor.setText(factor_format.format(factor));
holder.explicit_factor.setVisibility(View.VISIBLE);
}
}
updateFlag(holder, race.getRace(), now);
}
return convertView;
}
@@ -311,24 +304,25 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
});
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();
final List<RaceListDataTypeRace> items = raceItemsByHeader.get(header);
if (items != null) {
final List<RaceListDataTypeRace> raceItems = new ArrayList<>(items);
Collections.sort(raceItems, new Comparator<RaceListDataTypeRace>() {
final CurrentRaceComparator c = new CurrentRaceComparator();
@Override
public int compare(RaceListDataTypeRace lhs, RaceListDataTypeRace rhs) {
final int result;
if (lhs != null && rhs != null) {
result = c.compare(lhs.getRace(), rhs.getRace());
} else {
Log.e(TAG, "Internal error; found null for NavDrawer item while sorting");
result = 0;
@Override
public int compare(RaceListDataTypeRace lhs, RaceListDataTypeRace rhs) {
final int result;
if (lhs != null && rhs != null) {
result = c.compare(lhs.getRace(), rhs.getRace());
} else {
Log.e(TAG, "Internal error; found null for NavDrawer item while sorting");
result = 0;
}
return result;
}
return result;
}
});
for (final RaceListDataTypeRace raceItem : raceItems) {
result.add(raceItem);
});
result.addAll(raceItems);
}
}
return result;
@@ -341,12 +335,12 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
final SeriesBase series = race.getSeries();
final RaceListDataTypeHeader seriesHeader = viewItemsSeriesHeaders.get(series);
List<RaceListDataTypeRace> raceItemsInSeries = raceItemsByHeader.get(seriesHeader);
if (raceItemsInSeries == null) {
if (seriesHeader != null && raceItemsInSeries == null) {
raceItemsInSeries = new ArrayList<>();
raceItemsByHeader.put(seriesHeader, raceItemsInSeries);
}
final RaceListDataTypeRace viewItemForRace = viewItemsRaces.get(race);
if (viewItemForRace != null) {
if (raceItemsInSeries != null && viewItemForRace != null) {
raceItemsInSeries.add(viewItemForRace);
} else {
Log.w(TAG, "A view item for race " + race + " provided by the filter could not be found",
@@ -373,9 +367,6 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
if (holder.race_flag != null) {
holder.race_flag.setVisibility(View.GONE);
}
if (holder.time != null) {
holder.time.setVisibility(View.VISIBLE);
}
if (holder.race_started != null) {
holder.race_started.setText("");
}
@@ -388,9 +379,6 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
if (holder.race_unscheduled != null) {
holder.race_unscheduled.setVisibility(View.GONE);
}
if (holder.race_name != null) {
holder.race_name.setTextColor(ThemeHelper.getColor(getContext(), R.attr.black));
}
if (holder.has_dependent_races != null) {
holder.has_dependent_races.setVisibility(View.GONE);
}
@@ -404,90 +392,6 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
if (holder.warning_sign != null) {
holder.warning_sign.setVisibility(View.GONE);
}
holder.setMarker(0);
}
private void updateFlag(ViewHolder holder, ManagedRace race, TimePoint now) {
RaceState state = race.getState();
if (state == null || state.getStartTime() == null) {
return;
}
RacingProcedure procedure = state.getTypedRacingProcedure();
LayerDrawable flag = null;
Drawable arrow = null;
String timer = null;
if (!procedure.isIndividualRecallDisplayed()) {
FlagPoleState poleState = state.getRacingProcedure().getActiveFlags(state.getStartTime(), now);
List<FlagPole> currentState = poleState.getCurrentState();
List<FlagPole> upcoming = poleState.computeUpcomingChanges();
FlagPole nextPole = FlagPoleState.getMostInterestingFlagPole(upcoming);
TimePoint change = poleState.getNextStateValidFrom();
Flags currentFlag;
if (change != null) {
for (FlagPole pole : currentState) {
int isNext = 0;
currentFlag = pole.getUpperFlag();
if (isNextFlag(currentFlag, nextPole)) {
isNext = 1;
} else {
currentFlag = pole.getLowerFlag();
if (!Flags.NONE.equals(currentFlag)) {
if (isNextFlag(currentFlag, nextPole)) {
isNext = 2;
}
}
}
if (isNext != 0) {
flag = FlagsResources.getFlagDrawable(getContext(), currentFlag.name(), flag_size);
switch (isNext) {
case 1:
if (nextPole.isDisplayed()) {
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_up);
} else {
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_down);
}
break;
case 2:
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_up);
break;
default:
ExLog.i(getContext(), TAG, "unknown flag");
}
timer = TimeUtils.formatDuration(now, poleState.getNextStateValidFrom());
}
}
} else if (state.getStatus() == RaceLogRaceStatus.FINISHING) {
if (!currentState.isEmpty()) {
flag = FlagsResources.getFlagDrawable(getContext(), currentState.get(0).getUpperFlag().name(),
flag_size);
} else {
flag = null;
}
arrow = null;
timer = TimeUtils.formatDurationSince(now.minus(state.getFinishingTime().asMillis()).asMillis(), false);
}
} else {
TimePoint flagDown = procedure.getIndividualRecallRemovalTime();
if (now.before(flagDown)) {
flag = FlagsResources.getFlagDrawable(getContext(), Flags.XRAY.name(), flag_size);
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_down);
timer = TimeUtils.formatDuration(now, flagDown);
}
}
if (timer != null) {
timer = timer.replace("-", "");
}
holder.showFlag(flag, arrow, timer, state);
}
private boolean isNextFlag(Flags flag, FlagPole pole) {
return pole != null && flag.equals(pole.getUpperFlag());
}
public void onRacesChanged() {
@@ -509,35 +413,34 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
private static class ViewHolder {
public ImageView marker;
public RaceTimeView time;
public TextView race_finished;
/* package */ ViewGroup panel_left;
/* package */ ViewGroup panel_right;
/* package */ ImageView current_flag;
/* package */ ImageView update_badge;
/* package */ LinearLayout race_flag;
/* package */ TextView race_name;
/* package */ TextView race_started;
/* package */ LinearLayout race_scheduled;
/* package */ TextView race_unscheduled;
/* package */ FlagTimeView flag_timer;
/* package */ View protest_layout;
/* 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;
private View itemView;
private RaceTimeView time;
private TextView race_finished;
private ViewGroup panel_left;
private ViewGroup panel_right;
private ImageView update_badge;
private FlagTimeView race_flag_new;
private LinearLayout race_flag;
private TextView race_name;
private TextView race_started;
private LinearLayout race_scheduled;
private TextView race_unscheduled;
private View protest_layout;
private ImageView protest_image;
private ImageView protest_warning_image;
private TextView boat_class;
private TextView fleet_series;
private ImageView has_dependent_races;
private TextView depends_on;
private TextView explicit_factor;
private ImageView warning_sign;
/* package */ void findViews(View layout) {
private void findViews(View layout) {
itemView = layout;
panel_left = ViewHelper.get(layout, R.id.panel_left);
panel_right = ViewHelper.get(layout, R.id.panel_right);
marker = ViewHelper.get(layout, R.id.race_marker);
current_flag = ViewHelper.get(layout, R.id.current_flag);
update_badge = ViewHelper.get(layout, R.id.update_badge);
race_flag_new = ViewHelper.get(layout, R.id.race_flag);
race_flag = ViewHelper.get(layout, R.id.race_flag);
time = ViewHelper.get(layout, R.id.time);
race_name = ViewHelper.get(layout, R.id.race_name);
@@ -545,7 +448,6 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
race_started = ViewHelper.get(layout, R.id.race_started);
race_scheduled = ViewHelper.get(layout, R.id.race_scheduled);
race_unscheduled = ViewHelper.get(layout, R.id.race_unscheduled);
flag_timer = ViewHelper.get(layout, R.id.flag_timer);
protest_layout = ViewHelper.get(layout, R.id.protest_layout);
protest_image = ViewHelper.get(layout, R.id.protest_image);
protest_warning_image = ViewHelper.get(layout, R.id.protest_warning_image);
@@ -556,24 +458,5 @@ public class ManagedRaceListAdapter extends ArrayAdapter<RaceListDataType> imple
explicit_factor = ViewHelper.get(layout, R.id.explicit_factor);
warning_sign = ViewHelper.get(layout, R.id.panel_additional_image);
}
/* package */ void showFlag(final LayerDrawable flag, final Drawable arrow, final String timer, final RaceState state) {
if (flag != null && timer != null) {
current_flag.setImageDrawable(flag);
flag_timer.setRaceState(state);
flag_timer.setTimer(timer);
flag_timer.setCompoundDrawablesWithIntrinsicBounds(arrow, null, null, null);
race_flag.setVisibility(View.VISIBLE);
}
}
/* package */ void setMarker(int level) {
if (marker != null) {
Drawable drawable = marker.getDrawable();
if (drawable != null) {
drawable.setLevel(level);
}
}
}
}
}
@@ -1,6 +1,5 @@
package com.sap.sailing.racecommittee.app.ui.fragments;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -8,22 +7,19 @@ import android.content.IntentFilter;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.StyleSpan;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemSelectedListener;
@@ -61,13 +57,14 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Set;
public class RaceListFragment extends LoggableFragment
implements OnItemClickListener, OnItemSelectedListener, OnScrollListener {
public class RaceListFragment extends LoggableFragment implements OnItemClickListener, OnItemSelectedListener {
private final static String TAG = RaceListFragment.class.getName();
private final static String LAYOUT = "layout";
private ManagedRaceListAdapter mAdapter;
private RaceListCallbacks mCallbacks;
private Button mCurrentRacesButton;
@@ -77,21 +74,21 @@ public class RaceListFragment extends LoggableFragment
private ImageView mRefresh;
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private Runnable mRunnable;
private FilterMode mFilterMode;
private ListView mListView;
private LinkedHashMap<String, ManagedRace> mManagedRacesById;
private LinkedHashMap<RaceGroupSeriesFleet, List<ManagedRace>> mRacesByGroup;
private ManagedRace mSelectedRace;
private IntentReceiver mReceiver;
private boolean mUpdateList = true;
private View mProgress;
private final Set<ManagedRace> mAllRaces;
private BaseRaceStateChangedListener stateListener = new BaseRaceStateChangedListener() {
@Override
public void onFinishingPositioningsChanged(ReadonlyRaceState state) {
super.onFinishingPositioningsChanged(state);
public void onFinishingPositionsChanged(ReadonlyRaceState state) {
super.onFinishingPositionsChanged(state);
update(state);
}
@@ -167,24 +164,20 @@ public class RaceListFragment extends LoggableFragment
mAdapter.notifyDataSetChanged();
if (mCurrentRacesButton != null && mAllRacesButton != null) {
int colorGrey = ThemeHelper.getColor(getActivity(), R.attr.sap_light_gray);
int colorOrange = ThemeHelper.getColor(getActivity(), R.attr.sap_yellow_1);
int colorGrey = ThemeHelper.getColor(requireContext(), R.attr.sap_light_gray);
int colorOrange = ThemeHelper.getColor(requireContext(), R.attr.sap_yellow_1);
mCurrentRacesButton.setTextColor(colorGrey);
mAllRacesButton.setTextColor(colorGrey);
BitmapHelper.setBackground(mCurrentRacesButton, null);
BitmapHelper.setBackground(mAllRacesButton, null);
Drawable drawable = ContextCompat.getDrawable(getActivity(), R.drawable.nav_drawer_tab_button);
switch (getFilterMode()) {
case ALL:
Drawable drawable = ContextCompat.getDrawable(requireContext(), R.drawable.nav_drawer_tab_button);
if (getFilterMode() == FilterMode.ALL) {
mAllRacesButton.setTextColor(colorOrange);
BitmapHelper.setBackground(mAllRacesButton, drawable);
break;
default:
} else {
mCurrentRacesButton.setTextColor(colorOrange);
BitmapHelper.setBackground(mCurrentRacesButton, drawable);
break;
}
}
}
@@ -212,18 +205,18 @@ public class RaceListFragment extends LoggableFragment
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallbacks = (RaceListCallbacks) activity;
mCallbacks = (RaceListCallbacks) context;
} catch (ClassCastException ex) {
ExLog.ex(getActivity(), TAG, ex);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
int layout = R.layout.race_list_vertical;
if (getArguments() != null && getArguments().getInt(LAYOUT) != 0) {
layout = getArguments().getInt(LAYOUT);
@@ -231,48 +224,29 @@ public class RaceListFragment extends LoggableFragment
View view = inflater.inflate(layout, container, false);
mReceiver = new IntentReceiver();
mListView = (ListView) view.findViewById(R.id.listView);
mListView.setOnScrollListener(this);
mListView = view.findViewById(R.id.listView);
mProgress = view.findViewById(R.id.progress);
mCurrentRacesButton = (Button) view.findViewById(R.id.races_current);
mCurrentRacesButton = view.findViewById(R.id.races_current);
if (mCurrentRacesButton != null) {
mCurrentRacesButton.setTypeface(Typeface.DEFAULT_BOLD);
mCurrentRacesButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setFilterMode(FilterMode.ACTIVE);
}
});
mCurrentRacesButton.setOnClickListener(v -> setFilterMode(FilterMode.ACTIVE));
}
mAllRacesButton = (Button) view.findViewById(R.id.races_all);
mAllRacesButton = view.findViewById(R.id.races_all);
if (mAllRacesButton != null) {
mAllRacesButton.setTypeface(Typeface.DEFAULT_BOLD);
mAllRacesButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
setFilterMode(FilterMode.ALL);
}
});
mAllRacesButton.setOnClickListener(v -> setFilterMode(FilterMode.ALL));
}
mCourse = (TextView) view.findViewById(R.id.regatta_course);
mData = (TextView) view.findViewById(R.id.regatta_data);
mCourse = view.findViewById(R.id.regatta_course);
mData = view.findViewById(R.id.regatta_data);
mRefresh = (ImageView) view.findViewById(R.id.nav_button);
mRefresh = view.findViewById(R.id.nav_button);
if (mRefresh != null) {
mRefresh.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
BroadcastManager.getInstance(getActivity())
.addIntent(new Intent(AppConstants.INTENT_ACTION_RELOAD_RACES));
}
});
mRefresh.setOnClickListener(v -> BroadcastManager.getInstance(getActivity())
.addIntent(new Intent(AppConstants.INTENT_ACTION_RELOAD_RACES)));
}
view.setClickable(true);
@@ -289,11 +263,15 @@ public class RaceListFragment extends LoggableFragment
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
ExLog.i(getActivity(), TAG, "Touched " + mAdapter.getItem(position).toString());
final RaceListDataType item = mAdapter.getItem(position);
if (item != null) {
ExLog.i(getActivity(), TAG, "Touched " + item.toString());
mAdapter.setSelectedRace(item);
mAdapter.notifyDataSetChanged();
mRunnable = () -> mCallbacks.onRaceListItemSelected(mAdapter.getItem(position));
}
mDrawerLayout.closeDrawers();
mAdapter.setSelectedRace(mAdapter.getItem(position));
mCallbacks.onRaceListItemSelected(mAdapter.getItem(position));
}
@Override
@@ -310,7 +288,7 @@ public class RaceListFragment extends LoggableFragment
public void onPause() {
super.onPause();
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mReceiver);
}
@Override
@@ -319,26 +297,7 @@ public class RaceListFragment extends LoggableFragment
IntentFilter filter = new IntentFilter();
filter.addAction(AppConstants.INTENT_ACTION_SHOW_PROTEST);
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mReceiver, filter);
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case SCROLL_STATE_FLING:
case SCROLL_STATE_TOUCH_SCROLL:
mUpdateList = false;
break;
default:
mUpdateList = true;
}
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mReceiver, filter);
}
@Override
@@ -371,30 +330,25 @@ public class RaceListFragment extends LoggableFragment
public void setUp(DrawerLayout drawerLayout, String course, String author) {
mDrawerLayout = drawerLayout;
mDrawerLayout.setStatusBarBackgroundColor(ThemeHelper.getColor(getActivity(), R.attr.colorPrimaryDark));
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout,
(Toolbar) getActivity().findViewById(R.id.toolbar), R.string.nav_drawer_open,
mDrawerLayout.setStatusBarBackgroundColor(ThemeHelper.getColor(requireContext(), R.attr.colorPrimaryDark));
mDrawerToggle = new ActionBarDrawerToggle(requireActivity(), mDrawerLayout,
requireActivity().findViewById(R.id.toolbar), R.string.nav_drawer_open,
R.string.nav_drawer_close) {
@Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
mUpdateList = false;
}
@Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
mUpdateList = true;
if (mRunnable != null) {
drawerLayout.post(() -> {
mRunnable.run();
mRunnable = null;
});
}
}
};
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.post(() -> mDrawerToggle.syncState());
mDrawerLayout.addDrawerListener(mDrawerToggle);
if (mCourse != null) {
SpannableString text = new SpannableString(course);
StyleSpan spanBold = new StyleSpan(Typeface.BOLD);
@@ -407,8 +361,7 @@ public class RaceListFragment extends LoggableFragment
}
public void setupOn(Iterable<ManagedRace> races) {
ExLog.i(getActivity(), TAG,
String.format("Setting up %s with %d races.", this.getClass().getSimpleName(), Util.size(races)));
ExLog.i(getActivity(), TAG, String.format(Locale.getDefault(), "Setting up %s with %d races.", this.getClass().getSimpleName(), Util.size(races)));
unregisterOnAllRaces();
mManagedRacesById.clear();
mRacesByGroup.clear();
@@ -428,7 +381,7 @@ public class RaceListFragment extends LoggableFragment
// prepare views and do initial filtering; update the adapter first, so it can create the new
// view items for the new races; then trigger the filter
mAdapter.onRacesChanged();
mAdapter.notifyDataSetChanged();
resetSelectedRace();
filterChanged();
updateConflictSign();
}
@@ -467,6 +420,8 @@ public class RaceListFragment extends LoggableFragment
public void resetSelectedRace() {
mSelectedRace = null;
final int position = mListView.getCheckedItemPosition();
mListView.setItemChecked(position, false);
mAdapter.setSelectedRace(null);
mAdapter.notifyDataSetChanged();
}
@@ -481,30 +436,37 @@ public class RaceListFragment extends LoggableFragment
// Find the race group for which the
List<ManagedRace> races = new ArrayList<>();
for (RaceGroupSeriesFleet raceGroupSeriesFleet : mRacesByGroup.keySet()) {
Boolean matchingRaceGroup = raceGroupSeriesDisplayName
boolean matchingRaceGroup = raceGroupSeriesDisplayName
.equals(new RaceGroupSeries(raceGroupSeriesFleet.getRaceGroup(), raceGroupSeriesFleet.getSeries())
.getDisplayName());
if (matchingRaceGroup) {
if (!isRaceListDirty(races)) {
if (races != null && !isRaceListDirty(races)) {
// collect all races for a single fragment in case of portrait mode;
// show multiple fragments after one another in case of non-portrait (landscape) mode
View view = getActivity().findViewById(R.id.protest_time_fragment);
View view = requireActivity().findViewById(R.id.protest_time_fragment);
if (AppUtils.with(getActivity()).isPortrait() && view != null) {
races.addAll(mRacesByGroup.get(raceGroupSeriesFleet));
final List<ManagedRace> racesByGroup = mRacesByGroup.get(raceGroupSeriesFleet);
if (racesByGroup != null) {
races.addAll(racesByGroup);
}
} else {
races = mRacesByGroup.get(raceGroupSeriesFleet);
ProtestTimeDialogFragment fragment = ProtestTimeDialogFragment.newInstance(races);
fragment.show(getFragmentManager(), null);
if (races != null) {
ProtestTimeDialogFragment fragment = ProtestTimeDialogFragment.newInstance(races);
fragment.show(requireFragmentManager(), null);
}
}
}
}
}
if (AppUtils.with(getActivity()).isPortrait()
&& (getActivity().findViewById(R.id.protest_time_fragment)) != null) {
ProtestTimeDialogFragment fragment = ProtestTimeDialogFragment.newInstance(races);
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.protest_time_fragment, fragment);
transaction.commit();
&& (requireActivity().findViewById(R.id.protest_time_fragment)) != null) {
if (races != null) {
ProtestTimeDialogFragment fragment = ProtestTimeDialogFragment.newInstance(races);
FragmentTransaction transaction = requireFragmentManager().beginTransaction();
transaction.replace(R.id.protest_time_fragment, fragment);
transaction.commit();
}
}
}
@@ -513,7 +475,7 @@ public class RaceListFragment extends LoggableFragment
for (ManagedRace race : races) {
// check for data consistency if race is still in data store and not only in fragment
if (manager.getDataStore().getRace(race.getId()) == null) {
SessionActivity sessionActivity = (SessionActivity) getActivity();
SessionActivity sessionActivity = (SessionActivity) requireActivity();
sessionActivity.forceLogout();
return true;
}
@@ -527,12 +489,10 @@ public class RaceListFragment extends LoggableFragment
mRefresh.setEnabled(false);
mProgress.setVisibility(View.VISIBLE);
mListView.setVisibility(View.GONE);
mUpdateList = false;
} else {
mRefresh.setEnabled(true);
mProgress.setVisibility(View.GONE);
mListView.setVisibility(View.VISIBLE);
mUpdateList = true;
}
}
}
@@ -546,6 +506,7 @@ public class RaceListFragment extends LoggableFragment
this.displayName = RaceApplication.getStringContext().getString(resId);
}
@NonNull
@Override
public String toString() {
return displayName;
@@ -561,9 +522,9 @@ public class RaceListFragment extends LoggableFragment
@Override
public void onReceive(Context context, Intent intent) {
if (AppConstants.INTENT_ACTION_SHOW_PROTEST.equals(intent.getAction())) {
String raceGroupSeriesDisplayName = intent.getExtras().getString(AppConstants.INTENT_ACTION_EXTRA);
String raceGroupSeriesDisplayName = intent.getStringExtra(AppConstants.INTENT_ACTION_EXTRA);
if (raceGroupSeriesDisplayName != null) {
showProtestTimeDialog(raceGroupSeriesDisplayName);
mRunnable = () -> showProtestTimeDialog(raceGroupSeriesDisplayName);
mDrawerLayout.closeDrawers();
} else {
ExLog.e(getActivity(), TAG,
@@ -1,26 +0,0 @@
package com.sap.sailing.racecommittee.app.ui.views;
import android.content.Context;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import com.sap.sailing.racecommittee.app.utils.TickListener;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
abstract public class BaseTimeView extends android.support.v7.widget.AppCompatTextView implements TickListener {
public BaseTimeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
TickSingleton.INSTANCE.registerListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
TickSingleton.INSTANCE.unregisterListener(this);
}
}
@@ -1,41 +1,163 @@
package com.sap.sailing.racecommittee.app.ui.views;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
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.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.domain.common.racelog.RaceLogRaceStatus;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.ui.utils.FlagsResources;
import com.sap.sailing.racecommittee.app.utils.TickListener;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import java.util.List;
public class FlagTimeView extends LinearLayout implements TickListener {
private static final String TAG = FlagTimeView.class.getSimpleName();
private final ImageView imageView;
private final TextView textView;
private final int flagSize;
public class FlagTimeView extends BaseTimeView {
private RaceState state;
private String timer;
public FlagTimeView(@NonNull final Context context, final @Nullable AttributeSet attrs) {
public FlagTimeView(Context context, AttributeSet attrs) {
super(context, attrs);
setOrientation(LinearLayout.VERTICAL);
inflate(context, R.layout.layout_flag_time, this);
imageView = findViewById(R.id.imageView);
textView = findViewById(R.id.textView);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlagTimeView, 0, 0);
try {
flagSize = a.getInteger(R.styleable.FlagTimeView_flagSize, 0);
} finally {
a.recycle();
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
TickSingleton.INSTANCE.registerListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
TickSingleton.INSTANCE.unregisterListener(this);
}
public void setRaceState(RaceState state) {
this.state = state;
}
public void setTimer(String timer) {
this.timer = timer;
notifyTick(MillisecondsTimePoint.now());
}
@Override
public void notifyTick(TimePoint now) {
if (state == null) { return; }
if (state.getStatus() == RaceLogRaceStatus.FINISHING) {
final String time = TimeUtils.formatDurationSince(now.minus(state.getFinishingTime().asMillis()).asMillis());
setText(time);
} else {
setText(timer);
if (state == null || state.getStartTime() == null || state.getFinishedTime() != null) {
setVisibility(View.GONE);
return;
}
RacingProcedure procedure = state.getTypedRacingProcedure();
LayerDrawable flag = null;
Drawable arrow = null;
String duration = null;
if (!procedure.isIndividualRecallDisplayed()) {
FlagPoleState poleState = state.getRacingProcedure().getActiveFlags(state.getStartTime(), now);
List<FlagPole> currentState = poleState.getCurrentState();
List<FlagPole> upcoming = poleState.computeUpcomingChanges();
FlagPole nextPole = FlagPoleState.getMostInterestingFlagPole(upcoming);
TimePoint change = poleState.getNextStateValidFrom();
Flags currentFlag;
if (change != null) {
for (FlagPole pole : currentState) {
int isNext = 0;
currentFlag = pole.getUpperFlag();
if (isNextFlag(currentFlag, nextPole)) {
isNext = 1;
} else {
currentFlag = pole.getLowerFlag();
if (!Flags.NONE.equals(currentFlag)) {
if (isNextFlag(currentFlag, nextPole)) {
isNext = 2;
}
}
}
if (isNext != 0) {
flag = FlagsResources.getFlagDrawable(getContext(), currentFlag.name(), flagSize);
switch (isNext) {
case 1:
if (nextPole.isDisplayed()) {
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_up);
} else {
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_down);
}
break;
case 2:
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_up);
break;
default:
ExLog.i(getContext(), TAG, "unknown flag");
}
duration = TimeUtils.formatDuration(now, poleState.getNextStateValidFrom());
}
}
} else if (state.getStatus() == RaceLogRaceStatus.FINISHING) {
if (!currentState.isEmpty()) {
flag = FlagsResources.getFlagDrawable(getContext(), currentState.get(0).getUpperFlag().name(),
flagSize);
}
arrow = null;
duration = TimeUtils.formatDurationSince(now.minus(state.getFinishingTime().asMillis()).asMillis(), false);
}
} else {
TimePoint flagDown = procedure.getIndividualRecallRemovalTime();
if (now.before(flagDown)) {
flag = FlagsResources.getFlagDrawable(getContext(), Flags.XRAY.name(), flagSize);
arrow = BitmapHelper.getAttrDrawable(getContext(), R.attr.arrow_down);
duration = TimeUtils.formatDuration(now, flagDown);
}
}
if (duration != null) {
duration = duration.replace("-", "");
}
if (flag == null) {
setVisibility(View.GONE);
return;
}
setVisibility(View.VISIBLE);
imageView.setImageDrawable(flag);
textView.setCompoundDrawablesWithIntrinsicBounds(arrow, null, null, null);
textView.setText(duration);
}
private boolean isNextFlag(Flags flag, FlagPole pole) {
return pole != null && flag.equals(pole.getUpperFlag());
}
}
@@ -2,16 +2,17 @@ package com.sap.sailing.racecommittee.app.ui.views;
import android.content.Context;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.racecommittee.app.R;
import com.sap.sailing.racecommittee.app.utils.TickListener;
import com.sap.sailing.racecommittee.app.utils.TickSingleton;
import com.sap.sailing.racecommittee.app.utils.TimeUtils;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class RaceTimeView extends BaseTimeView {
public class RaceTimeView extends android.support.v7.widget.AppCompatTextView implements TickListener {
private RaceState state;
@@ -19,24 +20,31 @@ public class RaceTimeView extends BaseTimeView {
super(context, attrs);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
TickSingleton.INSTANCE.registerListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
TickSingleton.INSTANCE.unregisterListener(this);
}
public void setRaceState(RaceState state) {
this.state = state;
notifyTick(MillisecondsTimePoint.now());
}
@Override
public void notifyTick(TimePoint now) {
if (state == null) {
return;
}
if (state.getStartTime() == null) {
if (state == null || state.getStartTime() == null) {
setVisibility(View.GONE);
return;
}
setVisibility(View.VISIBLE);
String duration = TimeUtils.formatDuration(now, state.getStartTime());
setText(duration);
float textSize = getContext().getResources().getDimension(R.dimen.textSize_40);
if (!TextUtils.isEmpty(duration) && duration.length() >= 6) {
textSize = getContext().getResources().getDimension(R.dimen.textSize_32);
}
setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
}