From 77d30c879ae54ee207b5f17953995a49f65f78e7 Mon Sep 17 00:00:00 2001 From: DreierF Date: Tue, 10 Jan 2017 11:13:33 +0100 Subject: [PATCH] Enhanced summary in input activity (#226) * Closed #221 --- .../settings/SettingsActivityTest.java | 40 +++--- .../settings/SettingsManagerTest.java | 19 ++- .../test/utils/matchers/MatcherUtils.java | 21 ++- .../utils/matchers/RecyclerViewMatcher.java | 47 ++++--- .../base/fragments/ListFragmentBase.java | 2 +- .../settings/InputSettingsFragment.java | 17 +++ .../features/settings/SettingsManager.java | 39 +++++- .../statistics/StatisticsActivity.java | 6 +- .../{EShowMode.java => ETrainingScope.java} | 14 +- .../training/input/InputActivity.java | 100 ++++++++++---- .../training/input/SummaryConfiguration.java | 53 +++++++ .../mytargets/utils/ContentChangingTask.java | 32 ----- .../dreier/mytargets/utils/ToolbarUtils.java | 2 +- .../OnItemClickListener.java | 4 +- .../multiselector/SelectableViewHolder.java | 2 - app/src/main/res/layout/activity_input.xml | 59 +++++++- app/src/main/res/values/arrays.xml | 10 ++ app/src/main/res/values/strings.xml | 8 +- app/src/main/res/xml/preferences.xml | 129 +++++++++++------- .../dreier/mytargets/shared/models/Score.java | 58 +++++--- .../targets/scoringstyle/ScoringStyle.java | 3 + 21 files changed, 466 insertions(+), 199 deletions(-) rename app/src/main/java/de/dreier/mytargets/features/training/input/{EShowMode.java => ETrainingScope.java} (67%) create mode 100644 app/src/main/java/de/dreier/mytargets/features/training/input/SummaryConfiguration.java delete mode 100644 app/src/main/java/de/dreier/mytargets/utils/ContentChangingTask.java rename app/src/main/java/de/dreier/mytargets/utils/{ => multiselector}/OnItemClickListener.java (86%) diff --git a/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsActivityTest.java b/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsActivityTest.java index 0c71a23fe..73de2d67d 100644 --- a/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsActivityTest.java +++ b/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsActivityTest.java @@ -32,23 +32,25 @@ import de.dreier.mytargets.test.base.UITestBase; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.support.test.espresso.Espresso.onData; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.pressBack; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.closeSoftKeyboard; import static android.support.test.espresso.action.ViewActions.replaceText; -import static android.support.test.espresso.action.ViewActions.scrollTo; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; +import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.withId; -import static android.support.test.espresso.matcher.ViewMatchers.withParent; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static de.dreier.mytargets.test.utils.PermissionGranter.allowPermissionsIfNeeded; import static de.dreier.mytargets.test.utils.matchers.MatcherUtils.matchToolbarTitle; import static de.dreier.mytargets.test.utils.matchers.MatcherUtils.withRecyclerView; import static junit.framework.Assert.assertEquals; import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.hasToString; +import static org.hamcrest.Matchers.startsWith; @RunWith(AndroidJUnit4.class) public class SettingsActivityTest extends UITestBase { @@ -77,16 +79,16 @@ public void settingsActivityTest() { matchToolbarTitle(getActivity().getString(R.string.input)); - matchPreferenceSummary(0, "3.0x"); - clickOnPreference(0); + matchPreferenceSummary(7, "3.0x"); + clickOnPreference(7); selectFromList("5.0x"); - matchPreferenceSummary(0, "5.0x"); + matchPreferenceSummary(7, "5.0x"); assertEquals(SettingsManager.getInputTargetZoom(), 5.0f); - matchPreferenceSummary(1, "1.0x"); - clickOnPreference(1); + matchPreferenceSummary(8, "1.0x"); + clickOnPreference(8); selectFromList("3.5x"); - matchPreferenceSummary(1, "3.5x"); + matchPreferenceSummary(8, "3.5x"); assertEquals(SettingsManager.getInputArrowDiameterScale(), 3.5f); pressBack(); @@ -165,24 +167,30 @@ private SettingsActivity getActivity() { private void enterText(String text) { onView(withId(android.R.id.edit)) - .perform(scrollTo(), replaceText(text), closeSoftKeyboard()); + .perform(replaceText(text), closeSoftKeyboard()); onView(allOf(withId(android.R.id.button1), withText(android.R.string.ok), isDisplayed())).perform(click()); } - private void selectFromList(String text1) { - onView(allOf(withText(text1), withParent(withId(R.id.select_dialog_listview)), - isDisplayed())).perform(click()); + private void selectFromList(String text) { + onData(hasToString(startsWith(text))) + .inAdapterView(withId(R.id.select_dialog_listview)) + .perform(click()); } - private void matchPreferenceSummary(int index, String expectedSummary) { - onView(allOf(withRecyclerView(R.id.list).atPositionOnView(index, android.R.id.summary), - isDisplayed())).check(matches(withText(expectedSummary))); + private void matchPreferenceSummary(int position, String expectedSummary) { + onView(allOf(withId(R.id.list), isOnForegroundFragment())) + .perform(scrollToPosition(position)); + onView(withRecyclerView(allOf(withId(R.id.list), + isOnForegroundFragment())).atPositionOnView(position, android.R.id.summary)) + .check(matches(withText(expectedSummary))); } private void clickOnPreference(int position) { - onView(allOf(withId(R.id.list), isOnForegroundFragment(), isDisplayed())) + onView(allOf(withId(R.id.list), isOnForegroundFragment())) + .perform(scrollToPosition(position)); + onView(allOf(withId(R.id.list), isOnForegroundFragment())) .perform(actionOnItemAtPosition(position, click())); } } \ No newline at end of file diff --git a/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsManagerTest.java b/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsManagerTest.java index faa4d81a6..37a632442 100644 --- a/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsManagerTest.java +++ b/app/src/androidTest/java/de/dreier/mytargets/features/settings/SettingsManagerTest.java @@ -32,7 +32,8 @@ import de.dreier.mytargets.app.ApplicationInstance; import de.dreier.mytargets.features.settings.backup.EBackupInterval; import de.dreier.mytargets.features.settings.backup.provider.EBackupLocation; -import de.dreier.mytargets.features.training.input.EShowMode; +import de.dreier.mytargets.features.training.input.ETrainingScope; +import de.dreier.mytargets.features.training.input.SummaryConfiguration; import de.dreier.mytargets.features.training.input.TargetView; import de.dreier.mytargets.shared.analysis.aggregation.EAggregationStrategy; import de.dreier.mytargets.shared.models.Dimension; @@ -147,8 +148,8 @@ public void setDonated() { @Test public void setShowMode() { - SettingsManager.setShowMode(EShowMode.TRAINING); - assertThat(SettingsManager.getShowMode()).isEqualTo(EShowMode.TRAINING); + SettingsManager.setShowMode(ETrainingScope.TRAINING); + assertThat(SettingsManager.getShowMode()).isEqualTo(ETrainingScope.TRAINING); } @Test @@ -281,4 +282,16 @@ public void setShouldShowIntroActivity() { SettingsManager.setShouldShowIntroActivity(false); assertThat(SettingsManager.shouldShowIntroActivity()).isEqualTo(false); } + + @Test + public void setInputSummaryConfiguration() { + SummaryConfiguration config = new SummaryConfiguration(); + config.showEnd = false; + config.showRound = true; + config.showTraining = true; + config.showAverage = true; + config.averageScope = ETrainingScope.TRAINING; + SettingsManager.setInputSummaryConfiguration(config); + assertThat(SettingsManager.getInputSummaryConfiguration()).isEqualTo(config); + } } \ No newline at end of file diff --git a/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/MatcherUtils.java b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/MatcherUtils.java index 43505daa8..94db7b8d7 100644 --- a/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/MatcherUtils.java +++ b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/MatcherUtils.java @@ -27,6 +27,7 @@ import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; +import static android.support.test.espresso.matcher.ViewMatchers.withId; import static org.hamcrest.CoreMatchers.is; public class MatcherUtils { @@ -69,7 +70,23 @@ public void describeTo(Description description) { }; } - public static RecyclerViewMatcher withRecyclerView(final int recyclerViewId) { - return new RecyclerViewMatcher(recyclerViewId); + public static RecyclerViewMatcher withRecyclerView(Matcher recyclerViewMatcher) { + return new RecyclerViewMatcher(recyclerViewMatcher); + } + + public static RecyclerViewMatcher withRecyclerView(int recyclerViewId) { + return new RecyclerViewMatcher(withId(recyclerViewId)); + } + + public static View getMatchingParent(View view, Matcher matcher) { + if (view == null) { + return null; + } + if (matcher.matches(view)) { + return view; + } else if (view.getParent() != null && view.getParent() instanceof ViewGroup) { + return getMatchingParent((View) view.getParent(), matcher); + } + return null; } } diff --git a/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/RecyclerViewMatcher.java b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/RecyclerViewMatcher.java index 6eff17b72..2ada9788a 100644 --- a/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/RecyclerViewMatcher.java +++ b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/RecyclerViewMatcher.java @@ -24,10 +24,10 @@ import org.hamcrest.TypeSafeMatcher; public class RecyclerViewMatcher { - private final int recyclerViewId; + private final Matcher recyclerViewMatcher; - public RecyclerViewMatcher(int recyclerViewId) { - this.recyclerViewId = recyclerViewId; + public RecyclerViewMatcher(Matcher recyclerViewMatcher) { + this.recyclerViewMatcher = recyclerViewMatcher; } public Matcher atPosition(final int position) { @@ -35,33 +35,42 @@ public Matcher atPosition(final int position) { } public Matcher atPositionOnView(final int position, final int targetViewId) { - return new TypeSafeMatcher() { Resources resources = null; + View childView; public void describeTo(Description description) { - String idDescription = Integer.toString(recyclerViewId); - if (resources != null) { - try { - idDescription = resources.getResourceName(recyclerViewId); - } catch (Resources.NotFoundException var4) { - idDescription = recyclerViewId + " (resource name not found)"; + recyclerViewMatcher.describeTo(description); + description.appendText(" at position " + position); + if (targetViewId != -1) { + String idDescription = Integer.toString(targetViewId); + if (resources != null) { + try { + idDescription = resources.getResourceName(targetViewId); + } catch (Resources.NotFoundException var4) { + idDescription = targetViewId + " (resource name not found)"; + } } + description.appendText(" on view with id " + idDescription); } - - description.appendText("with id: " + idDescription); } public boolean matchesSafely(View view) { resources = view.getResources(); - RecyclerView recyclerView = (RecyclerView) MatcherUtils - .getParentViewById(view, recyclerViewId); - if (recyclerView == null || recyclerView.getId() != recyclerViewId) { - return false; + if (childView == null) { + View parent = MatcherUtils.getMatchingParent(view, recyclerViewMatcher); + if (parent == null || !(parent instanceof RecyclerView)) { + return false; + } + RecyclerView recyclerView = (RecyclerView) parent; + RecyclerView.ViewHolder viewHolder = recyclerView + .findViewHolderForAdapterPosition(position); + if (viewHolder == null) { + return false; + } + childView = viewHolder.itemView; } - View childView = recyclerView - .findViewHolderForAdapterPosition(position).itemView; if (targetViewId == -1) { return view == childView; @@ -73,6 +82,4 @@ public boolean matchesSafely(View view) { } }; } - - } \ No newline at end of file diff --git a/app/src/main/java/de/dreier/mytargets/base/fragments/ListFragmentBase.java b/app/src/main/java/de/dreier/mytargets/base/fragments/ListFragmentBase.java index 42c835b05..fa825c86f 100644 --- a/app/src/main/java/de/dreier/mytargets/base/fragments/ListFragmentBase.java +++ b/app/src/main/java/de/dreier/mytargets/base/fragments/ListFragmentBase.java @@ -17,7 +17,7 @@ import android.content.Context; import android.os.Parcelable; -import de.dreier.mytargets.utils.OnItemClickListener; +import de.dreier.mytargets.utils.multiselector.OnItemClickListener; public abstract class ListFragmentBase extends FragmentBase implements OnItemClickListener { diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/InputSettingsFragment.java b/app/src/main/java/de/dreier/mytargets/features/settings/InputSettingsFragment.java index 057b52cfc..4d3f682e5 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/InputSettingsFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/settings/InputSettingsFragment.java @@ -16,9 +16,11 @@ package de.dreier.mytargets.features.settings; import de.dreier.mytargets.R; +import de.dreier.mytargets.features.training.input.SummaryConfiguration; import static de.dreier.mytargets.features.settings.SettingsManager.KEY_INPUT_ARROW_DIAMETER_SCALE; import static de.dreier.mytargets.features.settings.SettingsManager.KEY_INPUT_KEYBOARD_TYPE; +import static de.dreier.mytargets.features.settings.SettingsManager.KEY_INPUT_SUMMARY_AVERAGE_OF; import static de.dreier.mytargets.features.settings.SettingsManager.KEY_INPUT_TARGET_ZOOM; import static de.dreier.mytargets.features.training.input.TargetView.EKeyboardType.LEFT; @@ -26,10 +28,25 @@ public class InputSettingsFragment extends SettingsFragmentBase { @Override protected void updateItemSummaries() { + setSummary(KEY_INPUT_SUMMARY_AVERAGE_OF, getAverageOf()); setSummary(KEY_INPUT_ARROW_DIAMETER_SCALE, SettingsManager.getInputArrowDiameterScale() + "x"); setSummary(KEY_INPUT_TARGET_ZOOM, SettingsManager.getInputTargetZoom() + "x"); setSummary(KEY_INPUT_KEYBOARD_TYPE, SettingsManager.getInputKeyboardType() == LEFT ? getString(R.string.left_handed) : getString(R.string.right_handed)); } + + private String getAverageOf() { + final SummaryConfiguration configuration = SettingsManager + .getInputSummaryConfiguration(); + switch (configuration.averageScope) { + case END: + return getString(R.string.end); + case TRAINING: + return getString(R.string.training); + case ROUND: + default: + return getString(R.string.round); + } + } } diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.java b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.java index b78598359..2a63804f9 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.java +++ b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsManager.java @@ -31,7 +31,8 @@ import de.dreier.mytargets.app.ApplicationInstance; import de.dreier.mytargets.features.settings.backup.EBackupInterval; import de.dreier.mytargets.features.settings.backup.provider.EBackupLocation; -import de.dreier.mytargets.features.training.input.EShowMode; +import de.dreier.mytargets.features.training.input.ETrainingScope; +import de.dreier.mytargets.features.training.input.SummaryConfiguration; import de.dreier.mytargets.features.training.input.TargetView.EKeyboardType; import de.dreier.mytargets.shared.analysis.aggregation.EAggregationStrategy; import de.dreier.mytargets.shared.models.Dimension; @@ -48,10 +49,15 @@ public class SettingsManager { public static final String KEY_PROFILE_LAST_NAME = "profile_last_name"; public static final String KEY_PROFILE_BIRTHDAY = "profile_birthday"; public static final String KEY_PROFILE_CLUB = "profile_club"; + private static final String KEY_INPUT_SUMMARY_SHOW_END = "input_summary_show_end"; + private static final String KEY_INPUT_SUMMARY_SHOW_ROUND = "input_summary_show_round"; + private static final String KEY_INPUT_SUMMARY_SHOW_TRAINING = "input_summary_show_training"; + private static final String KEY_INPUT_SUMMARY_SHOW_AVERAGE = "input_summary_show_average"; + public static final String KEY_INPUT_SUMMARY_AVERAGE_OF = "input_summary_average_of"; public static final String KEY_INPUT_ARROW_DIAMETER_SCALE = "input_arrow_diameter_scale"; public static final String KEY_INPUT_TARGET_ZOOM = "input_target_zoom"; public static final String KEY_INPUT_KEYBOARD_TYPE = "input_keyboard_type"; - public static final String KEY_FIRST_TRAINING_SHOWN = "first_training_shown"; + private static final String KEY_FIRST_TRAINING_SHOWN = "first_training_shown"; private static final String KEY_BACKUP_INTERVAL = "backup_interval"; private static final String KEY_DONATED = "donated"; private static final String KEY_TIMER_VIBRATE = "timer_vibrate"; @@ -238,12 +244,12 @@ public static void setDonated(boolean donated) { .apply(); } - public static EShowMode getShowMode() { - return EShowMode.valueOf(preferences - .getString(KEY_SHOW_MODE, EShowMode.END.toString())); + public static ETrainingScope getShowMode() { + return ETrainingScope.valueOf(preferences + .getString(KEY_SHOW_MODE, ETrainingScope.END.toString())); } - public static void setShowMode(EShowMode showMode) { + public static void setShowMode(ETrainingScope showMode) { preferences .edit() .putString(KEY_SHOW_MODE, showMode.toString()) @@ -503,4 +509,25 @@ public static void setShouldShowIntroActivity(boolean shouldShow) { .putBoolean(KEY_INTRO_SHOWED, shouldShow) .apply(); } + + public static SummaryConfiguration getInputSummaryConfiguration() { + SummaryConfiguration config = new SummaryConfiguration(); + config.showEnd = preferences.getBoolean(KEY_INPUT_SUMMARY_SHOW_END, true); + config.showRound = preferences.getBoolean(KEY_INPUT_SUMMARY_SHOW_ROUND, true); + config.showTraining = preferences.getBoolean(KEY_INPUT_SUMMARY_SHOW_TRAINING, false); + config.showAverage = preferences.getBoolean(KEY_INPUT_SUMMARY_SHOW_AVERAGE, true); + config.averageScope = ETrainingScope + .valueOf(preferences.getString(KEY_INPUT_SUMMARY_AVERAGE_OF, "ROUND")); + return config; + } + + public static void setInputSummaryConfiguration(SummaryConfiguration configuration) { + preferences.edit() + .putBoolean(KEY_INPUT_SUMMARY_SHOW_END, configuration.showEnd) + .putBoolean(KEY_INPUT_SUMMARY_SHOW_ROUND, configuration.showRound) + .putBoolean(KEY_INPUT_SUMMARY_SHOW_TRAINING, configuration.showTraining) + .putBoolean(KEY_INPUT_SUMMARY_SHOW_AVERAGE, configuration.showAverage) + .putString(KEY_INPUT_SUMMARY_AVERAGE_OF, configuration.averageScope.name()) + .apply(); + } } diff --git a/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.java b/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.java index 6fa8602d7..86ec20b68 100644 --- a/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.java +++ b/app/src/main/java/de/dreier/mytargets/features/statistics/StatisticsActivity.java @@ -163,7 +163,11 @@ public boolean onPrepareOptionsMenu(Menu menu) { filter.setIcon(showFilter ? R.drawable.ic_clear_filter_white_24dp : R.drawable.ic_filter_white_24dp); - filter.setVisible(rounds != null); + // only show filter if we have at least one category to filter by + boolean filterAvailable = binding.distanceTags.getTags().size() > 1 + || binding.bowTags.getTags().size() > 1 + || binding.arrowTags.getTags().size() > 1; + filter.setVisible(rounds != null && filterAvailable); export.setVisible(rounds != null); return true; } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/input/EShowMode.java b/app/src/main/java/de/dreier/mytargets/features/training/input/ETrainingScope.java similarity index 67% rename from app/src/main/java/de/dreier/mytargets/features/training/input/EShowMode.java rename to app/src/main/java/de/dreier/mytargets/features/training/input/ETrainingScope.java index 7cfea6411..e9224dc6e 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/input/EShowMode.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/input/ETrainingScope.java @@ -15,16 +15,6 @@ package de.dreier.mytargets.features.training.input; -import de.dreier.mytargets.R; - -public enum EShowMode { - END(R.id.action_show_end), - ROUND(R.id.action_show_round), - TRAINING(R.id.action_show_training); - - public final int actionItemId; - - EShowMode(int actionItemId) { - this.actionItemId = actionItemId; - } +public enum ETrainingScope { + END, ROUND, TRAINING } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/input/InputActivity.java b/app/src/main/java/de/dreier/mytargets/features/training/input/InputActivity.java index 9440424b0..6da7042fa 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/input/InputActivity.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/input/InputActivity.java @@ -64,6 +64,9 @@ import icepick.Icepick; import icepick.State; +import static android.view.View.GONE; +import static android.view.View.VISIBLE; + public class InputActivity extends ChildActivityBase implements TargetViewBase.OnEndFinishedListener, TargetView.OnEndUpdatedListener, LoaderManager.LoaderCallbacks { @@ -78,7 +81,8 @@ public class InputActivity extends ChildActivityBase private WearMessageManager manager; private ActivityInputBinding binding; private boolean transitionFinished = true; - private EShowMode showMode = EShowMode.END; + private ETrainingScope shotShowScope = ETrainingScope.END; + private ETrainingScope summaryShowScope = null; private TargetView targetView; @NonNull @@ -110,7 +114,9 @@ protected void onCreate(Bundle savedInstanceState) { setupTransitionListener(); } - showMode = SettingsManager.getShowMode(); + shotShowScope = SettingsManager.getShowMode(); + + updateSummaryVisibility(); Icepick.restoreInstanceState(this, savedInstanceState); if (data != null) { @@ -121,6 +127,15 @@ protected void onCreate(Bundle savedInstanceState) { } } + private void updateSummaryVisibility() { + SummaryConfiguration config = SettingsManager.getInputSummaryConfiguration(); + binding.endSummary.setVisibility(config.showEnd ? VISIBLE : GONE); + binding.roundSummary.setVisibility(config.showRound ? VISIBLE : GONE); + binding.trainingSummary.setVisibility(config.showTraining ? VISIBLE : GONE); + binding.averageSummary.setVisibility(config.showAverage ? VISIBLE : GONE); + summaryShowScope = config.showAverage ? config.averageScope : null; + } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void setupTransitionListener() { final Transition sharedElementEnterTransition = getWindow() @@ -158,11 +173,23 @@ public boolean onPrepareOptionsMenu(Menu menu) { grouping.setVisible(plotting); showSidebar.setIcon( plotting ? R.drawable.ic_keyboard_white_24dp : R.drawable.ic_keyboard_white_off_24dp); - showSidebar - .setVisible(getCurrentEnd().getId() == null); + showSidebar.setVisible(getCurrentEnd().getId() == null); } - menu.findItem(SettingsManager.getShowMode().actionItemId).setChecked(true); + switch (SettingsManager.getShowMode()) { + case END: + menu.findItem(R.id.action_show_end).setChecked(true); + break; + case ROUND: + menu.findItem(R.id.action_show_round).setChecked(true); + break; + case TRAINING: + menu.findItem(R.id.action_show_training).setChecked(true); + break; + default: + // Never called: All enum values are checked + break; + } switch (SettingsManager.getAggregationStrategy()) { case NONE: menu.findItem(R.id.action_grouping_none).setChecked(true); @@ -193,13 +220,13 @@ public boolean onOptionsItemSelected(MenuItem item) { targetView.setAggregationStrategy(EAggregationStrategy.CLUSTER); break; case R.id.action_show_end: - setShowMode(EShowMode.END); + setShotShowScope(ETrainingScope.END); break; case R.id.action_show_round: - setShowMode(EShowMode.ROUND); + setShotShowScope(ETrainingScope.ROUND); break; case R.id.action_show_training: - setShowMode(EShowMode.TRAINING); + setShotShowScope(ETrainingScope.TRAINING); break; case R.id.action_show_sidebar: final EInputMethod inputMethod = targetView.getInputMode() == EInputMethod.KEYBOARD @@ -296,8 +323,9 @@ public void updateOldShoots() { } private boolean shouldShowRound(Round r) { - return showMode != EShowMode.END - && (showMode == EShowMode.TRAINING || r.getId().equals(getCurrentEnd().roundId)); + return shotShowScope != ETrainingScope.END + && (shotShowScope == ETrainingScope.TRAINING || r.getId() + .equals(getCurrentEnd().roundId)); } private boolean shouldShowEnd(End end) { @@ -306,8 +334,11 @@ private boolean shouldShowEnd(End end) { private void updateEnd() { targetView.setEnd(getCurrentEnd()); - binding.endTitle.setText(getString(R.string.passe) + " " + (data.endIndex + 1)); - binding.roundTitle.setText(getString(R.string.round) + " " + (getCurrentRound().index + 1)); + binding.endTitle.setText( + getString(R.string.passe) + " " + (data.endIndex + 1) + "/" + getEnds().size()); + binding.roundTitle.setText(getString( + R.string.round) + " " + (getCurrentRound().index + 1) + "/" + data.training + .getRounds().size()); updateNavigationButtons(); // Send message to wearable app, that we are starting an end @@ -320,9 +351,9 @@ private void updateNavigationButtons() { (getCurrentRound().maxEndCount == null || data.endIndex + 1 < getCurrentRound().maxEndCount)); } - public void setShowMode(EShowMode showMode) { - this.showMode = showMode; - SettingsManager.setShowMode(showMode); + public void setShotShowScope(ETrainingScope shotShowScope) { + this.shotShowScope = shotShowScope; + SettingsManager.setShowMode(shotShowScope); updateOldShoots(); } @@ -349,25 +380,40 @@ public void onTransitionEnd(Transition transition) { }); } - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - Icepick.saveInstanceState(this, outState); - } - @Override public void onEndUpdated(List changedEnd) { getCurrentEnd().setShots(changedEnd); // Set current end score - Score score = getCurrentRound().getTarget().getReachedScore(getCurrentEnd()); - binding.scoreEnd.setText(score.toString()); + Score reachedEndScore = getCurrentRound().getTarget().getReachedScore(getCurrentEnd()); + binding.endScore.setText(reachedEndScore.toString()); // Set current round score Score reachedRoundScore = Stream.of(getEnds()) .map(end -> getCurrentRound().getTarget().getReachedScore(end)) .collect(Score.sum()); - binding.scoreRound.setText(reachedRoundScore.toString()); + binding.roundScore.setText(reachedRoundScore.toString()); + + // Set current training score + Score reachedTrainingScore = Stream.of(data.training.getRounds()) + .flatMap(r -> Stream.of(r.getEnds()) + .map(end -> r.getTarget().getReachedScore(end))) + .collect(Score.sum()); + binding.trainingScore.setText(reachedTrainingScore.toString()); + + switch (summaryShowScope) { + case END: + binding.averageScore.setText(reachedEndScore.getShotAverageFormatted()); + break; + case ROUND: + binding.averageScore.setText(reachedRoundScore.getShotAverageFormatted()); + break; + case TRAINING: + binding.averageScore.setText(reachedTrainingScore.getShotAverageFormatted()); + break; + default: + break; + } } @Override @@ -430,6 +476,12 @@ private End getCurrentEnd() { return getEnds().get(data.endIndex); } + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Icepick.saveInstanceState(this, outState); + } + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private static abstract class TransitionAdapter implements Transition.TransitionListener { @Override diff --git a/app/src/main/java/de/dreier/mytargets/features/training/input/SummaryConfiguration.java b/app/src/main/java/de/dreier/mytargets/features/training/input/SummaryConfiguration.java new file mode 100644 index 000000000..718540ee9 --- /dev/null +++ b/app/src/main/java/de/dreier/mytargets/features/training/input/SummaryConfiguration.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2017 Florian Dreier + * + * This file is part of MyTargets. + * + * MyTargets is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * MyTargets is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +package de.dreier.mytargets.features.training.input; + +public class SummaryConfiguration { + public boolean showEnd; + public boolean showRound; + public boolean showTraining; + public boolean showAverage; + public ETrainingScope averageScope = ETrainingScope.ROUND; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + SummaryConfiguration that = (SummaryConfiguration) o; + + return showEnd == that.showEnd + && showRound == that.showRound + && showTraining == that.showTraining + && showAverage == that.showAverage + && averageScope == that.averageScope; + + } + + @Override + public int hashCode() { + int result = (showEnd ? 1 : 0); + result = 31 * result + (showRound ? 1 : 0); + result = 31 * result + (showTraining ? 1 : 0); + result = 31 * result + (showAverage ? 1 : 0); + result = 31 * result + averageScope.hashCode(); + return result; + } +} diff --git a/app/src/main/java/de/dreier/mytargets/utils/ContentChangingTask.java b/app/src/main/java/de/dreier/mytargets/utils/ContentChangingTask.java deleted file mode 100644 index 92ad9c2f8..000000000 --- a/app/src/main/java/de/dreier/mytargets/utils/ContentChangingTask.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2017 Florian Dreier - * - * This file is part of MyTargets. - * - * MyTargets is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * MyTargets is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -package de.dreier.mytargets.utils; - -import android.os.AsyncTask; -import android.support.v4.content.Loader; - -abstract class ContentChangingTask extends AsyncTask { - private Loader loader = null; - - ContentChangingTask(Loader loader) { - this.loader = loader; - } - - @Override - protected void onPostExecute(T3 param) { - loader.onContentChanged(); - } -} diff --git a/app/src/main/java/de/dreier/mytargets/utils/ToolbarUtils.java b/app/src/main/java/de/dreier/mytargets/utils/ToolbarUtils.java index 5d4cd918e..2e0a03ca1 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/ToolbarUtils.java +++ b/app/src/main/java/de/dreier/mytargets/utils/ToolbarUtils.java @@ -33,7 +33,7 @@ public static void showUpAsX(Fragment fragment) { showUpAsX((AppCompatActivity) fragment.getActivity()); } - public static void showUpAsX(AppCompatActivity activity) { + private static void showUpAsX(AppCompatActivity activity) { ActionBar supportActionBar = activity.getSupportActionBar(); assert supportActionBar != null; supportActionBar.setDisplayHomeAsUpEnabled(true); diff --git a/app/src/main/java/de/dreier/mytargets/utils/OnItemClickListener.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/OnItemClickListener.java similarity index 86% rename from app/src/main/java/de/dreier/mytargets/utils/OnItemClickListener.java rename to app/src/main/java/de/dreier/mytargets/utils/multiselector/OnItemClickListener.java index 1750b58a6..75e2bfa23 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/OnItemClickListener.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/OnItemClickListener.java @@ -13,9 +13,7 @@ * GNU General Public License for more details. */ -package de.dreier.mytargets.utils; - -import de.dreier.mytargets.utils.multiselector.SelectableViewHolder; +package de.dreier.mytargets.utils.multiselector; public interface OnItemClickListener { void onClick(SelectableViewHolder holder, T item); diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableViewHolder.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableViewHolder.java index 19b53f6f0..b87649ae6 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableViewHolder.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableViewHolder.java @@ -17,8 +17,6 @@ import android.view.View; -import de.dreier.mytargets.utils.OnItemClickListener; - /** * A holder extended to support having a selectable mode with a different * background and state list animator. diff --git a/app/src/main/res/layout/activity_input.xml b/app/src/main/res/layout/activity_input.xml index 39ad76d22..376e67421 100644 --- a/app/src/main/res/layout/activity_input.xml +++ b/app/src/main/res/layout/activity_input.xml @@ -50,10 +50,10 @@ android:layout_marginRight="10dp" android:layout_marginStart="72dp" android:baselineAligned="false" - android:orientation="horizontal" - android:weightSum="2"> + android:orientation="horizontal"> + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 47e04acfb..2d6840c00 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -65,4 +65,14 @@ LEFT RIGHT + + @string/end + @string/round + @string/training + + + END + ROUND + TRAINING + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a3d3ab1a5..b8cc84686 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -155,7 +155,7 @@ Backup Import - Exports saved data as *.csv + Exports as csv Open Source-Licences Legal notes to licences Version %s @@ -332,4 +332,10 @@ Everything you need\nin one place Including bow-, arrow-\nand sightmark-management,\narchery timer, statistics \nand much moreā€¦ Average arrow score per end + Show end + Show round + Show training + Summary + End + Average of diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 564713ad5..c54b4c11a 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -20,24 +20,51 @@ android:icon="@drawable/ic_input_grey600_24dp" android:key="input" android:title="@string/input"> - - - + + + + + + + + + + + + + android:title="@string/first_name" /> + android:title="@string/last_name" /> + android:title="@string/birthday" /> + android:title="@string/club" /> + android:title="@string/title" /> + android:title="@string/properties" /> + android:title="@string/table" /> + android:title="@string/statistic" /> + android:title="@string/comments" /> + android:title="@string/show_points_colored" /> + android:title="@string/show_signature" /> + android:title="@string/title" /> + android:title="@string/properties" /> + android:title="@string/table" /> + android:title="@string/statistic" /> + android:title="@string/comments" /> + android:title="@string/show_points_colored" /> + android:title="@string/show_signature" /> + android:title="@string/title" /> + android:title="@string/properties" /> + android:title="@string/table" /> + android:title="@string/statistic" /> + android:title="@string/comments" /> + android:title="@string/show_points_colored" /> + android:title="@string/show_signature" /> + android:title="@string/timer_waiting_time" /> + android:title="@string/timer_shooting_time" /> + android:title="@string/timer_warning_time" /> + android:title="@string/timer_sound" /> + android:title="@string/timer_vibrate" /> + android:title="@string/automatic_backup" /> + android:title="@string/about" /> + android:title="@string/licences" /> \ No newline at end of file diff --git a/shared/src/main/java/de/dreier/mytargets/shared/models/Score.java b/shared/src/main/java/de/dreier/mytargets/shared/models/Score.java index a04e212fa..42b1f5bfc 100644 --- a/shared/src/main/java/de/dreier/mytargets/shared/models/Score.java +++ b/shared/src/main/java/de/dreier/mytargets/shared/models/Score.java @@ -20,6 +20,8 @@ import com.annimon.stream.function.Function; import com.annimon.stream.function.Supplier; +import java.util.Locale; + public class Score { public int reachedScore; public int totalScore; @@ -37,10 +39,35 @@ public Score(int reachedScore, int totalScore) { this.shotCount = 1; } + public Score(int totalScore) { + this.reachedScore = 0; + this.totalScore = totalScore; + this.shotCount = 0; + } + + public static Collector sum() { + return new Collector() { + @Override + public Supplier supplier() { + return Score::new; + } + + @Override + public BiConsumer accumulator() { + return Score::add; + } + + @Override + public Function finisher() { + return score -> score; + } + }; + } + public Score add(Score other) { reachedScore += other.reachedScore; totalScore += other.totalScore; - shotCount += other.shotCount + 1; + shotCount += other.shotCount; return this; } @@ -58,29 +85,20 @@ public String format(boolean appendPercent) { } public float getShotAverage() { + if (shotCount == 0) { + return -1; + } return reachedScore / (float) shotCount; } - private int getPercent() { - return reachedScore * 100 / totalScore; + public String getShotAverageFormatted() { + if (shotCount == 0) { + return "-"; + } + return String.format(Locale.getDefault(), "%.2f", getShotAverage()); } - public static Collector sum() { - return new Collector() { - @Override - public Supplier supplier() { - return Score::new; - } - - @Override - public BiConsumer accumulator() { - return Score::add; - } - - @Override - public Function finisher() { - return score -> score; - } - }; + private int getPercent() { + return reachedScore * 100 / totalScore; } } diff --git a/shared/src/main/java/de/dreier/mytargets/shared/targets/scoringstyle/ScoringStyle.java b/shared/src/main/java/de/dreier/mytargets/shared/targets/scoringstyle/ScoringStyle.java index f871e3cc3..8fb9439fe 100644 --- a/shared/src/main/java/de/dreier/mytargets/shared/targets/scoringstyle/ScoringStyle.java +++ b/shared/src/main/java/de/dreier/mytargets/shared/targets/scoringstyle/ScoringStyle.java @@ -123,6 +123,9 @@ private boolean isOutOfRange(int zone) { } public Score getReachedScore(Shot shot) { + if(shot.scoringRing == Shot.NOTHING_SELECTED) { + return new Score(maxScorePerShot); + } int reachedScore = getScoreByScoringRing(shot.scoringRing, shot.index); return new Score(reachedScore, maxScorePerShot); }