From 771019551db67eb40666415e225cd9cb3886a715 Mon Sep 17 00:00:00 2001 From: Robert Benedikt Date: Thu, 23 Apr 2020 12:03:36 +0200 Subject: [PATCH] fix: issues regarding race list in NavigationDrawer race selection, flags and timers --- .../res/drawable/marker_race.xml | 18 +- .../res/layout/layout_flag_time.xml | 24 + .../res/layout/race_list_area_header.xml | 128 +++--- .../res/layout/race_list_area_item.xml | 203 ++++---- .../res/values/attrs.xml | 4 + .../racelist/ManagedRaceListAdapter.java | 433 +++++++----------- .../app/ui/fragments/RaceListFragment.java | 185 +++----- .../app/ui/views/BaseTimeView.java | 26 -- .../app/ui/views/FlagTimeView.java | 156 ++++++- .../app/ui/views/RaceTimeView.java | 34 +- 10 files changed, 581 insertions(+), 630 deletions(-) create mode 100644 mobile/com.sap.sailing.racecommittee.app/res/layout/layout_flag_time.xml delete mode 100644 mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/BaseTimeView.java diff --git a/mobile/com.sap.sailing.racecommittee.app/res/drawable/marker_race.xml b/mobile/com.sap.sailing.racecommittee.app/res/drawable/marker_race.xml index 86afaf5bd61..49bb37b44d1 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/drawable/marker_race.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/drawable/marker_race.xml @@ -1,11 +1,9 @@ - - - - - - \ No newline at end of file + + + + + + + + diff --git a/mobile/com.sap.sailing.racecommittee.app/res/layout/layout_flag_time.xml b/mobile/com.sap.sailing.racecommittee.app/res/layout/layout_flag_time.xml new file mode 100644 index 00000000000..4d347b4c415 --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/res/layout/layout_flag_time.xml @@ -0,0 +1,24 @@ + + + + + + + diff --git a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_header.xml b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_header.xml index db04a6ac0f7..b27a9b845dc 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_header.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_header.xml @@ -2,78 +2,15 @@ + android:layout_height="@dimen/navigation_drawer_cell_height"> - - - - - - - - - - - - - - - - - - - - @@ -95,4 +32,59 @@ android:textAppearance="?attr/textSmall" tools:text="Day 1\nYellow" /> + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_item.xml b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_item.xml index 3787826943d..2424a284074 100644 --- a/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_item.xml +++ b/mobile/com.sap.sailing.racecommittee.app/res/layout/race_list_area_item.xml @@ -2,92 +2,23 @@ + android:layout_height="@dimen/navigation_drawer_cell_height" + xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - - - - - - - - - - - - - - + android:duplicateParentState="true" + android:background="?attr/marker_race" /> + android:layout_toStartOf="@id/panel_right" + android:layout_toLeftOf="@id/panel_right"> - - - - - - - + tools:visibility="visible" /> + 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" /> + + + + + + + + + + + + + + + + + + - + + + + \ No newline at end of file diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/racelist/ManagedRaceListAdapter.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/racelist/ManagedRaceListAdapter.java index d34df2e47b2..acc8ef22c21 100755 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/racelist/ManagedRaceListAdapter.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/adapters/racelist/ManagedRaceListAdapter.java @@ -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 implements FilterSubscriber { private final static String TAG = ManagedRaceListAdapter.class.getName(); @@ -102,7 +94,10 @@ public class ManagedRaceListAdapter extends ArrayAdapter 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 imple } } + @NonNull @Override public RaceFilter getFilter() { return mFilter; @@ -137,17 +133,17 @@ public class ManagedRaceListAdapter extends ArrayAdapter 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 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 imple }); for (final RaceListDataTypeHeader header : headers) { result.add(header); - final List raceItems = new ArrayList<>(raceItemsByHeader.get(header)); - Collections.sort(raceItems, new Comparator() { - final CurrentRaceComparator c = new CurrentRaceComparator(); + final List items = raceItemsByHeader.get(header); + if (items != null) { + final List raceItems = new ArrayList<>(items); + Collections.sort(raceItems, new Comparator() { + 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 imple final SeriesBase series = race.getSeries(); final RaceListDataTypeHeader seriesHeader = viewItemsSeriesHeaders.get(series); List 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 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 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 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 currentState = poleState.getCurrentState(); - List 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 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 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 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); - } - } - } } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java index 2e941e61732..699f599eb1d 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/RaceListFragment.java @@ -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 mManagedRacesById; private LinkedHashMap> mRacesByGroup; private ManagedRace mSelectedRace; private IntentReceiver mReceiver; - private boolean mUpdateList = true; private View mProgress; private final Set 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 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 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 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, diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/BaseTimeView.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/BaseTimeView.java deleted file mode 100644 index 5a49770ed2d..00000000000 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/BaseTimeView.java +++ /dev/null @@ -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); - } -} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/FlagTimeView.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/FlagTimeView.java index cc480a8e5a7..50c4c7c507b 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/FlagTimeView.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/FlagTimeView.java @@ -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 currentState = poleState.getCurrentState(); + List 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()); } } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/RaceTimeView.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/RaceTimeView.java index 17a48e1f029..48f1cb972d3 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/RaceTimeView.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/views/RaceTimeView.java @@ -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); } }