diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/StartProcedure.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/StartProcedure.java index 2f2942b0aed..8ddb6b3a588 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/StartProcedure.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/StartProcedure.java @@ -2,9 +2,14 @@ package com.sap.sailing.racecommittee.app.domain.startprocedure; import java.util.List; +import android.content.Context; + import com.sap.sailing.domain.base.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.EssStartPhaseEventListener; +import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; public interface StartProcedure { @@ -39,5 +44,10 @@ public interface StartProcedure { void dispatchFiredIndividualRecallRemovalEvent(TimePoint individualRecallDisplayedTime, TimePoint eventTime); void setIndividualRecallRemoval(TimePoint eventTime); - + + Class getStartphaseFragment(); + + void setEssStartPhaseEventListener(EssStartPhaseEventListener listener); + + Pair getNextFlagCountdownUiLabel(Context context, long millisecondsTillStart); } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/EssStartPhaseEventListener.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/EssStartPhaseEventListener.java new file mode 100644 index 00000000000..f3532901bb4 --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/EssStartPhaseEventListener.java @@ -0,0 +1,12 @@ +package com.sap.sailing.racecommittee.app.domain.startprocedure.impl; + +public interface EssStartPhaseEventListener { + + void onAPDown(); + + void onEssThreeUp(); + + void onEssTwoUp(); + + void onEssOneUp(); +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/ExtremeSailingSeriesStartProcedure.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/ExtremeSailingSeriesStartProcedure.java index eef4e92c6ea..273cab5eb0a 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/ExtremeSailingSeriesStartProcedure.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/domain/startprocedure/impl/ExtremeSailingSeriesStartProcedure.java @@ -5,15 +5,21 @@ import java.util.Collections; import java.util.List; import java.util.UUID; +import android.content.Context; + import com.sap.sailing.domain.base.Competitor; import com.sap.sailing.domain.base.impl.MillisecondsTimePoint; import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.Util.Pair; import com.sap.sailing.domain.common.racelog.Flags; import com.sap.sailing.domain.racelog.PassAwareRaceLog; import com.sap.sailing.domain.racelog.RaceLogEvent; import com.sap.sailing.domain.racelog.RaceLogEventFactory; +import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedure; import com.sap.sailing.racecommittee.app.domain.startprocedure.StartProcedureRaceStateChangedListener; +import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase.EssStartPhaseFragment; public class ExtremeSailingSeriesStartProcedure implements StartProcedure { @@ -28,11 +34,13 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure { private List startProcedureEventIntervals; private PassAwareRaceLog raceLog; private StartProcedureRaceStateChangedListener raceStateChangedListener; + private EssStartPhaseEventListener startPhaseEventListener; public ExtremeSailingSeriesStartProcedure(PassAwareRaceLog raceLog) { this.raceLog = raceLog; startProcedureEventIntervals = new ArrayList(); raceStateChangedListener = null; + startPhaseEventListener = null; startProcedureEventIntervals.add(startPhaseAPDownInterval); startProcedureEventIntervals.add(startPhaseESSThreeUpInterval); @@ -83,12 +91,20 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure { RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.emptyList(), raceLog.getCurrentPassId(), Flags.AP, Flags.NONE, /*isDisplayed*/false); raceLog.add(event); + + if (startPhaseEventListener != null) { + startPhaseEventListener.onAPDown(); + } } private void handleEssThreeUp(TimePoint eventTime) { RaceLogEvent event = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.emptyList(), raceLog.getCurrentPassId(), Flags.ESSTHREE, Flags.NONE, /*isDisplayed*/true); raceLog.add(event); + + if (startPhaseEventListener != null) { + startPhaseEventListener.onEssThreeUp(); + } } private void handleEssTwoUpAndEssThreeDown(TimePoint eventTime) { @@ -101,6 +117,10 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure { RaceLogEvent essTwoUpEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.emptyList(), raceLog.getCurrentPassId(), Flags.ESSTWO, Flags.NONE, /*isDisplayed*/true); raceLog.add(essTwoUpEvent); + + if (startPhaseEventListener != null) { + startPhaseEventListener.onEssTwoUp(); + } } private void handleEssOneUpAndEssTwoDown(TimePoint eventTime) { @@ -113,6 +133,10 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure { RaceLogEvent essOneUpEvent = RaceLogEventFactory.INSTANCE.createFlagEvent(eventTime, UUID.randomUUID(), Collections.emptyList(), raceLog.getCurrentPassId(), Flags.ESSONE, Flags.NONE, /*isDisplayed*/true); raceLog.add(essOneUpEvent); + + if (startPhaseEventListener != null) { + startPhaseEventListener.onEssOneUp(); + } } private void handleEssOneDown(TimePoint eventTime) { @@ -266,4 +290,31 @@ public class ExtremeSailingSeriesStartProcedure implements StartProcedure { } } + @Override + public Class getStartphaseFragment() { + return EssStartPhaseFragment.class; + } + + @Override + public void setEssStartPhaseEventListener(EssStartPhaseEventListener listener) { + startPhaseEventListener = listener; + } + + @Override + public Pair getNextFlagCountdownUiLabel(Context context, long millisecondsTillStart) { + Pair result; + if (millisecondsTillStart < startPhaseESSOneUpInterval) { + result = new Pair(context.getResources().getString(R.string.race_startphase_ess_countdown_one_flag_remove), millisecondsTillStart); + } else if (millisecondsTillStart < startPhaseESSTwoUpInterval) { + result = new Pair(context.getResources().getString(R.string.race_startphase_ess_countdown_one_flag_display), millisecondsTillStart - startPhaseESSOneUpInterval); + } else if (millisecondsTillStart < startPhaseESSThreeUpInterval) { + result = new Pair(context.getResources().getString(R.string.race_startphase_ess_countdown_two_flag_display), millisecondsTillStart - startPhaseESSTwoUpInterval); + } else if (millisecondsTillStart < startPhaseAPDownInterval) { + result = new Pair(context.getResources().getString(R.string.race_startphase_ess_countdown_three_flag_display), millisecondsTillStart - startPhaseESSThreeUpInterval); + } else { + result = new Pair(context.getResources().getString(R.string.race_startphase_ess_countdown_ap_flag_removed), millisecondsTillStart - startPhaseAPDownInterval); + } + return result; + } + } diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/chooser/RaceInfoFragmentChooser.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/chooser/RaceInfoFragmentChooser.java index 856f821c360..14d4bcd6834 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/chooser/RaceInfoFragmentChooser.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/chooser/RaceInfoFragmentChooser.java @@ -1,45 +1,44 @@ -package com.sap.sailing.racecommittee.app.ui.fragments.chooser; - -import com.sap.sailing.racecommittee.app.domain.ManagedRace; -import com.sap.sailing.racecommittee.app.logging.ExLog; -import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.ErrorRaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.FinishedRaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.FinishingRaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RunningRaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.SetStartTimeRaceFragment; -import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.StartphaseRaceFragment; - -public class RaceInfoFragmentChooser { - private static final String TAG = RaceInfoFragmentChooser.class.getName(); - - public RaceFragment choose(ManagedRace managedRace) { - switch (managedRace.getStatus()) { - case UNSCHEDULED: - return createInfoFragment(SetStartTimeRaceFragment.class, managedRace); - case SCHEDULED: - case STARTPHASE: - return createInfoFragment(StartphaseRaceFragment.class, managedRace); - case RUNNING: - return createInfoFragment(RunningRaceFragment.class, managedRace); - case FINISHING: - return createInfoFragment(FinishingRaceFragment.class, managedRace); - case FINISHED: - return createInfoFragment(FinishedRaceFragment.class, managedRace); - default: - return createInfoFragment(ErrorRaceFragment.class, managedRace); - } - } - - private RaceFragment createInfoFragment(Class fragmentClass, ManagedRace managedRace) { - try { - RaceFragment fragment = fragmentClass.newInstance(); - fragment.setArguments(RaceFragment.createArguments(managedRace)); - return fragment; - } catch (Exception e) { - ExLog.e(TAG, String.format("Exception while instantiating race info fragment:\n%s", e.toString())); - return new ErrorRaceFragment(); - } - } - -} +package com.sap.sailing.racecommittee.app.ui.fragments.chooser; + +import com.sap.sailing.racecommittee.app.domain.ManagedRace; +import com.sap.sailing.racecommittee.app.logging.ExLog; +import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.ErrorRaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.FinishedRaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.FinishingRaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RunningRaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.SetStartTimeRaceFragment; + +public class RaceInfoFragmentChooser { + private static final String TAG = RaceInfoFragmentChooser.class.getName(); + + public RaceFragment choose(ManagedRace managedRace) { + switch (managedRace.getStatus()) { + case UNSCHEDULED: + return createInfoFragment(SetStartTimeRaceFragment.class, managedRace); + case SCHEDULED: + case STARTPHASE: + return createInfoFragment(managedRace.getState().getStartProcedure().getStartphaseFragment(), managedRace); + case RUNNING: + return createInfoFragment(RunningRaceFragment.class, managedRace); + case FINISHING: + return createInfoFragment(FinishingRaceFragment.class, managedRace); + case FINISHED: + return createInfoFragment(FinishedRaceFragment.class, managedRace); + default: + return createInfoFragment(ErrorRaceFragment.class, managedRace); + } + } + + private RaceFragment createInfoFragment(Class fragmentClass, ManagedRace managedRace) { + try { + RaceFragment fragment = fragmentClass.newInstance(); + fragment.setArguments(RaceFragment.createArguments(managedRace)); + return fragment; + } catch (Exception e) { + ExLog.e(TAG, String.format("Exception while instantiating race info fragment:\n%s", e.toString())); + return new ErrorRaceFragment(); + } + } + +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/EssStartPhaseFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/EssStartPhaseFragment.java new file mode 100644 index 00000000000..ea56a74d099 --- /dev/null +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/EssStartPhaseFragment.java @@ -0,0 +1,169 @@ +package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase; + +import android.app.Activity; +import android.app.FragmentManager; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import com.sap.sailing.domain.common.TimePoint; +import com.sap.sailing.domain.common.impl.Util.Pair; +import com.sap.sailing.domain.common.racelog.Flags; +import com.sap.sailing.racecommittee.app.AppConstants; +import com.sap.sailing.racecommittee.app.R; +import com.sap.sailing.racecommittee.app.domain.startprocedure.impl.EssStartPhaseEventListener; +import com.sap.sailing.racecommittee.app.logging.ExLog; +import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.AbortModeSelectionDialog; +import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.RaceDialogFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceInfoListener; +import com.sap.sailing.racecommittee.app.utils.TimeUtils; + +public class EssStartPhaseFragment extends RaceFragment implements EssStartPhaseEventListener { + + private RaceInfoListener infoListener; + + TextView raceCountdown; + TextView nextFlagCountdown; + ImageButton abortingFlagButton; + ImageView displayedFlag; + ImageView nextToBeDisplayedFlag; + Button resetTimeButton; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + if (activity instanceof RaceInfoListener) { + this.infoListener = (RaceInfoListener) activity; + } else { + throw new UnsupportedOperationException(String.format( + "%s must implement %s", + activity, + RaceInfoListener.class.getName())); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.race_startphase_ess_view, container, false); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + raceCountdown = (TextView) getView().findViewById(R.id.raceCountdown); + nextFlagCountdown = (TextView) getView().findViewById(R.id.nextFlagCountdown); + displayedFlag = (ImageView) getView().findViewById(R.id.currentlyDisplayedFlag); + nextToBeDisplayedFlag = (ImageView) getView().findViewById(R.id.nextFlagToBeDisplayed); + + ExLog.i("STARTPHASE", "" + getRace().getId() + " " + getRace().getStatus().toString()); + + abortingFlagButton = (ImageButton) getView().findViewById(R.id.abortingFlagButton); + abortingFlagButton.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + showAPModeDialog(); + } + }); + + Button resetTimeButton = (Button) getView().findViewById(R.id.resetTimeButton); + resetTimeButton.setOnClickListener(new OnClickListener() { + public void onClick(View v) { + infoListener.onResetTime(); + } + }); + } + + @Override + public void onStart() { + super.onStart(); + + getRace().getState().getStartProcedure().setEssStartPhaseEventListener(this); + } + + @Override + public void onStop() { + super.onStop(); + + getRace().getState().getStartProcedure().setEssStartPhaseEventListener(null); + } + + @Override + public void notifyTick() { + TimePoint startTime = getRace().getState().getStartTime(); + if (startTime != null) { + setCountdownLabels(TimeUtils.timeUntil(startTime)); + } + } + + private void setCountdownLabels(long millisecondsTillStart) { + setStarttimeCountdownLabel(millisecondsTillStart); + setNextFlagCountdownLabel(millisecondsTillStart); + } + + private void setStarttimeCountdownLabel(long millisecondsTillStart) { + raceCountdown.setText(String.format( + getString(R.string.race_startphase_countdown_start), + TimeUtils.prettyString(millisecondsTillStart), getRace().getName())); + } + + private void setNextFlagCountdownLabel(long millisecondsTillStart) { + Pair countDownPair = getRace().getState().getStartProcedure().getNextFlagCountdownUiLabel(getActivity(), millisecondsTillStart); + nextFlagCountdown.setText(String.format(countDownPair.getA(), + TimeUtils.prettyString(countDownPair.getB().longValue()))); + } + + protected void showAPModeDialog() { + FragmentManager fragmentManager = getFragmentManager(); + + RaceDialogFragment fragment = new AbortModeSelectionDialog(); + + Bundle args = getParameterBundle(); + args.putString(AppConstants.FLAG_KEY, Flags.AP.name()); + fragment.setArguments(args); + + fragment.show(fragmentManager, "dialogAPMode"); + } + + @Override + public void onAPDown() { + displayedFlag.setVisibility(View.INVISIBLE); + + resetTimeButton.setEnabled(false); + resetTimeButton.setVisibility(View.GONE); + } + + @Override + public void onEssThreeUp() { + displayedFlag.setVisibility(View.VISIBLE); + displayedFlag.setImageResource(R.drawable.three_min_flag); + + nextToBeDisplayedFlag.setImageResource(R.drawable.two_min_flag); + } + + @Override + public void onEssTwoUp() { + displayedFlag.setImageResource(R.drawable.two_min_flag); + + nextToBeDisplayedFlag.setImageResource(R.drawable.one_min_flag); + } + + @Override + public void onEssOneUp() { + displayedFlag.setImageResource(R.drawable.one_min_flag); + + nextToBeDisplayedFlag.setVisibility(View.INVISIBLE); + } + + + +} diff --git a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/StartphaseRaceFragment.java b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/StartphaseRaceFragment.java similarity index 93% rename from mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/StartphaseRaceFragment.java rename to mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/StartphaseRaceFragment.java index 9a7fd6b7f47..158bca38ab0 100644 --- a/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/StartphaseRaceFragment.java +++ b/mobile/com.sap.sailing.racecommittee.app/src/com/sap/sailing/racecommittee/app/ui/fragments/raceinfo/startphase/StartphaseRaceFragment.java @@ -1,4 +1,4 @@ -package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo; +package com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.startphase; import android.app.Activity; import android.app.FragmentManager; @@ -18,6 +18,7 @@ import com.sap.sailing.racecommittee.app.R; import com.sap.sailing.racecommittee.app.ui.fragments.RaceFragment; import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.AbortModeSelectionDialog; import com.sap.sailing.racecommittee.app.ui.fragments.dialogs.RaceDialogFragment; +import com.sap.sailing.racecommittee.app.ui.fragments.raceinfo.RaceInfoListener; import com.sap.sailing.racecommittee.app.utils.TimeUtils; public class StartphaseRaceFragment extends RaceFragment {