From e21a58bc3b9b55f8431bdc70fa303231f1b20469 Mon Sep 17 00:00:00 2001 From: DreierF Date: Wed, 25 Jan 2017 14:53:06 +0100 Subject: [PATCH] Fixes for Beta 5 (#235) * Fixed crash when selecting target for standard round * Refactored MultiSelector and SingleSelector to share a common base class and respect LSP. * Added UI test * Fixed round delete bug * Added additional info on settings crash --- .../training/EditTrainingActivityTest.java | 52 +++++++- .../EditStandardRoundActivityTest.java | 118 ++++++++++++++++++ .../assertions/RecyclerViewAssertions.java | 37 ++++++ .../test/utils/matchers/MatcherUtils.java | 47 +++++++ .../utils/matchers/ParentViewMatcher.java | 37 ++++++ .../v7/widget/RebindReportingHolder.java | 2 +- .../fragments/EditableListFragmentBase.java | 13 +- .../fragments/SelectItemFragmentBase.java | 13 +- .../features/arrows/ArrowListFragment.java | 1 - .../features/bows/BowListFragment.java | 1 - .../settings/SettingsFragmentBase.java | 18 +++ .../features/training/RoundFragment.java | 1 - .../features/training/TrainingFragment.java | 1 - .../training/edit/EditTrainingFragment.java | 20 +-- .../training/overview/TrainingsFragment.java | 1 - .../StandardRoundListFragment.java | 8 +- .../training/target/TargetListFragment.java | 8 +- .../utils/multiselector/MultiSelector.java | 95 ++++---------- .../MultiSelectorBindingHolder.java | 2 +- .../utils/multiselector/SelectableHolder.java | 4 +- .../multiselector/SelectableViewHolder.java | 32 ++--- .../utils/multiselector/SelectorBase.java | 86 +++++++++++++ .../utils/multiselector/SingleSelector.java | 46 ++++--- .../multiselector/WeakHolderTracker.java | 32 ++--- .../views/selector/DistanceSelector.java | 2 +- .../views/selector/ImageSelectorBase.java | 1 - .../views/selector/SelectorBase.java | 2 +- .../layout/fragment_edit_standard_round.xml | 2 + .../mytargets/shared/models/db/Arrow.java | 3 + .../mytargets/shared/models/db/End.java | 6 + .../shared/models/db/StandardRound.java | 6 + .../shared/targets/TargetFactory.java | 2 +- 32 files changed, 528 insertions(+), 171 deletions(-) create mode 100644 app/src/androidTest/java/de/dreier/mytargets/features/training/standardround/EditStandardRoundActivityTest.java create mode 100644 app/src/androidTest/java/de/dreier/mytargets/test/utils/assertions/RecyclerViewAssertions.java create mode 100644 app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/ParentViewMatcher.java create mode 100644 app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectorBase.java diff --git a/app/src/androidTest/java/de/dreier/mytargets/features/training/EditTrainingActivityTest.java b/app/src/androidTest/java/de/dreier/mytargets/features/training/EditTrainingActivityTest.java index 2a0dce8c7..7330c78bc 100644 --- a/app/src/androidTest/java/de/dreier/mytargets/features/training/EditTrainingActivityTest.java +++ b/app/src/androidTest/java/de/dreier/mytargets/features/training/EditTrainingActivityTest.java @@ -43,15 +43,21 @@ import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.action.ViewActions.replaceText; import static android.support.test.espresso.assertion.ViewAssertions.matches; +import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItem; import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; 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.features.training.edit.EditTrainingFragment.CREATE_FREE_TRAINING_ACTION; +import static de.dreier.mytargets.features.training.edit.EditTrainingFragment.CREATE_TRAINING_WITH_STANDARD_ROUND_ACTION; import static de.dreier.mytargets.shared.models.Dimension.Unit.CENTIMETER; import static de.dreier.mytargets.shared.models.Dimension.Unit.METER; import static de.dreier.mytargets.test.utils.PermissionGranter.allowPermissionsIfNeeded; +import static de.dreier.mytargets.test.utils.assertions.RecyclerViewAssertions.itemCount; +import static de.dreier.mytargets.test.utils.matchers.MatcherUtils.containsStringRes; +import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.containsString; @@ -64,6 +70,7 @@ public class EditTrainingActivityTest extends UITestBase { @Before public void setUp() { + SettingsManager.setStandardRound(93L); SettingsManager.setTarget(new Target(WAFull.ID, 0, new Dimension(122, CENTIMETER))); SettingsManager.setDistance(new Dimension(50, METER)); SettingsManager.setIndoor(false); @@ -74,7 +81,7 @@ public void setUp() { } @Test - public void editTrainingActivityTest() { + public void createFreeTraining() { Intent intent = new Intent(); intent.setAction(CREATE_FREE_TRAINING_ACTION); activityTestRule.launchActivity(intent); @@ -135,8 +142,49 @@ public void editTrainingActivityTest() { .format(new LocalDate(2016, 8, 10).toDate()); onView(withId(R.id.trainingDate)).check(matches(withText(formattedDate))); - onView(withId(R.id.action_save)).perform(click()); + clickActionBarItem(R.id.action_save, R.string.save); pressBack(); pressBack(); } + + @Test + public void createTrainingWithStandardRound() { + Intent intent = new Intent(); + intent.setAction(CREATE_TRAINING_WITH_STANDARD_ROUND_ACTION); + activityTestRule.launchActivity(intent); + + allowPermissionsIfNeeded(activityTestRule.getActivity(), ACCESS_FINE_LOCATION); + + // Has last used standard round been restored + onView(withId(R.id.standardRound)) + .check(matches(hasDescendant(withText(R.string.warwick)))); + + // Change standard round + onView(withId(R.id.standardRound)).perform(nestedScrollTo(), click()); + onView(withId(R.id.recyclerView)) + .perform(actionOnItem(hasDescendant(withText(R.string.wa_standard)), click()), + actionOnItem(hasDescendant(withText(R.string.wa_standard)), click())); + onView(withId(R.id.standardRound)) + .check(matches(hasDescendant(withText(R.string.wa_standard)))); + + onView(withText(R.string.change_target_face)).perform(nestedScrollTo(), click()); + + onView(withId(R.id.recyclerView)) + .check(matches(hasDescendant(withText(R.string.wa_full)))) + .check(matches(hasDescendant(withText(R.string.wa_3_ring)))) + .check(itemCount(is(5))); + + onView(allOf(withId(R.id.recyclerView), isDisplayed())) + .perform(actionOnItemAtPosition(4, click())); + navigateUp(); + + clickActionBarItem(R.id.action_save, R.string.save); + + navigateUp(); + navigateUp(); + + onView(withId(R.id.detail_round_info)) + .check(matches(allOf(containsStringRes(R.string.wa_standard), + containsStringRes(R.string.wa_3_ring)))); + } } diff --git a/app/src/androidTest/java/de/dreier/mytargets/features/training/standardround/EditStandardRoundActivityTest.java b/app/src/androidTest/java/de/dreier/mytargets/features/training/standardround/EditStandardRoundActivityTest.java new file mode 100644 index 000000000..9fc9435a9 --- /dev/null +++ b/app/src/androidTest/java/de/dreier/mytargets/features/training/standardround/EditStandardRoundActivityTest.java @@ -0,0 +1,118 @@ +/* + * 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.standardround; + + +import android.content.Intent; +import android.support.test.espresso.intent.rule.IntentsTestRule; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import de.dreier.mytargets.R; +import de.dreier.mytargets.features.settings.SettingsManager; +import de.dreier.mytargets.features.training.edit.EditTrainingActivity; +import de.dreier.mytargets.shared.models.Dimension; +import de.dreier.mytargets.shared.models.Target; +import de.dreier.mytargets.shared.targets.models.WAFull; +import de.dreier.mytargets.test.base.UITestBase; + +import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.support.test.espresso.Espresso.onView; +import static android.support.test.espresso.action.ViewActions.click; +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.actionOnItem; +import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; +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.withText; +import static de.dreier.mytargets.features.training.edit.EditTrainingFragment.CREATE_TRAINING_WITH_STANDARD_ROUND_ACTION; +import static de.dreier.mytargets.shared.models.Dimension.Unit.CENTIMETER; +import static de.dreier.mytargets.shared.models.Dimension.Unit.METER; +import static de.dreier.mytargets.test.utils.PermissionGranter.allowPermissionsIfNeeded; +import static de.dreier.mytargets.test.utils.matchers.MatcherUtils.withRecyclerView; +import static de.dreier.mytargets.test.utils.matchers.ParentViewMatcher.isNestedChildOfView; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.startsWith; + +@RunWith(AndroidJUnit4.class) +public class EditStandardRoundActivityTest extends UITestBase { + + @Rule + public IntentsTestRule activityTestRule = new IntentsTestRule<>( + EditTrainingActivity.class, true, false); + + @Before + public void setUp() { + SettingsManager.setTarget(new Target(WAFull.ID, 0, new Dimension(122, CENTIMETER))); + SettingsManager.setDistance(new Dimension(50, METER)); + SettingsManager.setTimerEnabled(false); + SettingsManager.setShotsPerEnd(3); + SettingsManager.setEndCount(10); + SettingsManager.setDistance(new Dimension(10, METER)); + } + + @Test + public void editStandardRoundActivity() { + Intent intent = new Intent(); + intent.setAction(CREATE_TRAINING_WITH_STANDARD_ROUND_ACTION); + activityTestRule.launchActivity(intent); + + allowPermissionsIfNeeded(activityTestRule.getActivity(), ACCESS_FINE_LOCATION); + + onView(withId(R.id.standardRound)).perform(scrollTo(), click()); + + onView(withId(R.id.fab)).perform(click()); + + onView(withId(R.id.distance)).perform(nestedScrollTo(), click()); + onView(allOf(withId(R.id.recyclerView), isDisplayed())) + .perform(actionOnItem(hasDescendant(withText("20m")), click())); + + onView(withId(R.id.target)).perform(nestedScrollTo(), click()); + onView(withId(R.id.recyclerView)) + .perform(actionOnItem(hasDescendant(withText(R.string.wa_danage_6_spot)), click())); + navigateUp(); + + onView(withId(R.id.addButton)).perform(nestedScrollTo(), click()); + + onView(withRecyclerView(R.id.rounds).atPositionOnView(1, R.id.distance)) + .perform(nestedScrollTo(), click()); + onView(allOf(withId(R.id.recyclerView), isDisplayed())) + .perform(actionOnItem(hasDescendant(withText("15m")), click())); + + onView(allOf(withId(R.id.number_increment), isNestedChildOfView(withId(R.id.shotCount)), + isNestedChildOfView(withRecyclerView(R.id.rounds).atPosition(1)))) + .perform(nestedScrollTo(), click(), click(), click()); + + onView(allOf(withId(R.id.number_decrement), isNestedChildOfView(withId(R.id.endCount)), + isNestedChildOfView(withRecyclerView(R.id.rounds).atPosition(1)))) + .perform(nestedScrollTo(), click(), click(), click(), click(), click()); + + clickActionBarItem(R.id.action_save, R.string.save); + + onView(withId(R.id.standardRound)) + .check(matches(hasDescendant(withText(R.string.custom_round)))); + + onView(withId(R.id.standardRound)) + .check(matches(hasDescendant(withText( + allOf(startsWith("20m: 10 × 3"), containsString("15m: 5 × 6")))))); + } +} diff --git a/app/src/androidTest/java/de/dreier/mytargets/test/utils/assertions/RecyclerViewAssertions.java b/app/src/androidTest/java/de/dreier/mytargets/test/utils/assertions/RecyclerViewAssertions.java new file mode 100644 index 000000000..547bd23b8 --- /dev/null +++ b/app/src/androidTest/java/de/dreier/mytargets/test/utils/assertions/RecyclerViewAssertions.java @@ -0,0 +1,37 @@ +/* + * 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.test.utils.assertions; + +import android.support.test.espresso.ViewAssertion; +import android.support.v7.widget.RecyclerView; + +import org.hamcrest.Matcher; + +import static android.support.test.espresso.matcher.ViewMatchers.assertThat; + +public class RecyclerViewAssertions { + public static ViewAssertion itemCount(Matcher matcher) { + return (view, noViewFoundException) -> { + if (noViewFoundException != null) { + throw noViewFoundException; + } + + RecyclerView recyclerView = (RecyclerView) view; + RecyclerView.Adapter adapter = recyclerView.getAdapter(); + assertThat(adapter.getItemCount(), matcher); + }; + } +} \ 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 94db7b8d7..c664da9a8 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 @@ -15,12 +15,14 @@ package de.dreier.mytargets.test.utils.matchers; +import android.content.res.Resources; import android.support.test.espresso.ViewInteraction; import android.support.test.espresso.assertion.ViewAssertions; import android.support.test.espresso.matcher.BoundedMatcher; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.ViewGroup; +import android.widget.TextView; import org.hamcrest.Description; import org.hamcrest.Matcher; @@ -89,4 +91,49 @@ public static View getMatchingParent(View view, Matcher matcher) { } return null; } + + /** + * Returns a matcher that matches a descendant of {@link TextView} that is displaying the string + * associated with the given resource id. + * + * @param resourceId the string resource the text view is expected to hold. + */ + public static Matcher containsStringRes(final int resourceId) { + return new BoundedMatcher(TextView.class) { + private String resourceName = null; + private String expectedText = null; + + @Override + public void describeTo(Description description) { + description.appendText("contains string from resource id: "); + description.appendValue(resourceId); + if (resourceName != null) { + description.appendText("["); + description.appendText(resourceName); + description.appendText("]"); + } + if (expectedText != null) { + description.appendText(" value: "); + description.appendText(expectedText); + } + } + + @Override + public boolean matchesSafely(TextView textView) { + if (expectedText == null) { + try { + expectedText = textView.getResources().getString(resourceId); + resourceName = textView.getResources().getResourceEntryName(resourceId); + } catch (Resources.NotFoundException ignored) { + /* view could be from a context unaware of the resource id. */ + } + } + CharSequence actualText = textView.getText(); + // FYI: actualText may not be string ... its just a char sequence convert to string. + return expectedText != null && actualText != null && + actualText.toString().contains(expectedText); + } + }; + } + } diff --git a/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/ParentViewMatcher.java b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/ParentViewMatcher.java new file mode 100644 index 000000000..df8765ba9 --- /dev/null +++ b/app/src/androidTest/java/de/dreier/mytargets/test/utils/matchers/ParentViewMatcher.java @@ -0,0 +1,37 @@ +/* + * 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.test.utils.matchers; + +import android.view.View; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +public class ParentViewMatcher { + public static Matcher isNestedChildOfView(Matcher parentViewMatcher) { + return new TypeSafeMatcher() { + public void describeTo(Description description) { + description.appendText("is nested child of view "); + parentViewMatcher.describeTo(description); + } + + public boolean matchesSafely(View view) { + return MatcherUtils.getMatchingParent(view, parentViewMatcher) != null; + } + }; + } +} \ No newline at end of file diff --git a/app/src/main/java/android/support/v7/widget/RebindReportingHolder.java b/app/src/main/java/android/support/v7/widget/RebindReportingHolder.java index e92cb4eb0..2df572766 100644 --- a/app/src/main/java/android/support/v7/widget/RebindReportingHolder.java +++ b/app/src/main/java/android/support/v7/widget/RebindReportingHolder.java @@ -62,7 +62,7 @@ private void checkFlags(int setFlags) { } /** - * check if the view is due for rebiding + * Check if the view is due for rebinding * * @param flag * @return diff --git a/app/src/main/java/de/dreier/mytargets/base/fragments/EditableListFragmentBase.java b/app/src/main/java/de/dreier/mytargets/base/fragments/EditableListFragmentBase.java index e1b2fcbb1..5ce144e55 100644 --- a/app/src/main/java/de/dreier/mytargets/base/fragments/EditableListFragmentBase.java +++ b/app/src/main/java/de/dreier/mytargets/base/fragments/EditableListFragmentBase.java @@ -15,7 +15,6 @@ package de.dreier.mytargets.base.fragments; import android.support.annotation.PluralsRes; -import android.support.annotation.StringRes; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; @@ -50,12 +49,6 @@ public abstract class EditableListFragmentBase holder, T mItem) { - if (mItem == null) { + public void onClick(SelectableViewHolder holder, T item) { + if (item == null) { return; } if (!selector.tapSelection(holder)) { - onSelected(mItem); + onSelected(item); } else { updateTitle(); } diff --git a/app/src/main/java/de/dreier/mytargets/base/fragments/SelectItemFragmentBase.java b/app/src/main/java/de/dreier/mytargets/base/fragments/SelectItemFragmentBase.java index 53aa94cde..8b56f9dfb 100644 --- a/app/src/main/java/de/dreier/mytargets/base/fragments/SelectItemFragmentBase.java +++ b/app/src/main/java/de/dreier/mytargets/base/fragments/SelectItemFragmentBase.java @@ -74,12 +74,12 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { * @param item Currently selected item */ protected void selectItem(RecyclerView recyclerView, T item) { - int position = adapter.getItemPosition(item); - selector.setSelected(position, item.getId(), true); + selector.setSelected(item.getId(), true); recyclerView.post(() -> { LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager(); int first = manager.findFirstCompletelyVisibleItemPosition(); int last = manager.findLastCompletelyVisibleItemPosition(); + int position = adapter.getItemPosition(item); if (first > position || last < position) { recyclerView.scrollToPosition(position); } @@ -112,12 +112,11 @@ public boolean onOptionsItemSelected(MenuItem item) { * {@inheritDoc} */ @Override - public void onClick(SelectableViewHolder holder, T mItem) { - if (mItem == null) { + public void onClick(SelectableViewHolder holder, T item) { + if (item == null) { return; } - int oldSelectedPosition = selector.getSelectedPosition(); - boolean alreadySelected = oldSelectedPosition == holder.getAdapterPosition(); + boolean alreadySelected = selector.isSelected(holder.getItemId()); selector.setSelected(holder, true); if (alreadySelected || !useDoubleClickSelection) { saveItem(); @@ -138,6 +137,6 @@ protected void saveItem() { * @return The selected item */ protected T onSave() { - return adapter.getItem(selector.getSelectedPosition()); + return adapter.getItemById(selector.getSelectedId()); } } diff --git a/app/src/main/java/de/dreier/mytargets/features/arrows/ArrowListFragment.java b/app/src/main/java/de/dreier/mytargets/features/arrows/ArrowListFragment.java index b6748a243..3e2f92227 100644 --- a/app/src/main/java/de/dreier/mytargets/features/arrows/ArrowListFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/arrows/ArrowListFragment.java @@ -43,7 +43,6 @@ public class ArrowListFragment extends EditableListFragment { public ArrowListFragment() { itemTypeSelRes = R.plurals.arrow_selected; itemTypeDelRes = R.plurals.arrow_deleted; - newStringRes = R.string.new_arrow; } @Override diff --git a/app/src/main/java/de/dreier/mytargets/features/bows/BowListFragment.java b/app/src/main/java/de/dreier/mytargets/features/bows/BowListFragment.java index 373dc616b..ece821900 100644 --- a/app/src/main/java/de/dreier/mytargets/features/bows/BowListFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/bows/BowListFragment.java @@ -55,7 +55,6 @@ public class BowListFragment extends EditableListFragment { public BowListFragment() { itemTypeSelRes = R.plurals.bow_selected; itemTypeDelRes = R.plurals.bow_deleted; - newStringRes = R.string.new_bow; } @Override diff --git a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsFragmentBase.java b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsFragmentBase.java index 43e8a7804..0fd5c3854 100644 --- a/app/src/main/java/de/dreier/mytargets/features/settings/SettingsFragmentBase.java +++ b/app/src/main/java/de/dreier/mytargets/features/settings/SettingsFragmentBase.java @@ -19,9 +19,12 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.content.ContextCompat; +import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceFragmentCompat; import android.view.View; +import com.google.firebase.analytics.FirebaseAnalytics; + import de.dreier.mytargets.R; import de.dreier.mytargets.app.ApplicationInstance; import de.dreier.mytargets.utils.ToolbarUtils; @@ -89,6 +92,21 @@ public void onPause() { .unregisterOnSharedPreferenceChangeListener(this); } + @Override + public void onDisplayPreferenceDialog(Preference preference) { + try { + super.onDisplayPreferenceDialog(preference); + } catch (IllegalArgumentException e) { + FirebaseAnalytics.getInstance(getContext()) + .logEvent("key=" + preference.getKey() + " " + + preference.getClass().getCanonicalName() + " toStr" + preference + .toString(), + null); + // TODO remove this when crashes have been fixed + throw e; + } + } + protected void setSummary(String key, String value) { findPreference(key).setSummary(value); } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/RoundFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/RoundFragment.java index dc190abc3..953a78557 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/RoundFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/RoundFragment.java @@ -60,7 +60,6 @@ public class RoundFragment extends EditableListFragment { public RoundFragment() { itemTypeSelRes = R.plurals.passe_selected; itemTypeDelRes = R.plurals.passe_deleted; - newStringRes = R.string.new_end; } @NonNull diff --git a/app/src/main/java/de/dreier/mytargets/features/training/TrainingFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/TrainingFragment.java index 3d7fbc78e..836d71c57 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/TrainingFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/TrainingFragment.java @@ -67,7 +67,6 @@ public class TrainingFragment extends EditableListFragment { public TrainingFragment() { itemTypeSelRes = R.plurals.round_selected; itemTypeDelRes = R.plurals.round_deleted; - newStringRes = R.string.new_round; supportsStatistics = true; } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/edit/EditTrainingFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/edit/EditTrainingFragment.java index 35cfa5f6c..32416258a 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/edit/EditTrainingFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/edit/EditTrainingFragment.java @@ -27,6 +27,8 @@ import android.view.ViewGroup; import android.widget.DatePicker; +import com.annimon.stream.Stream; + import org.adw.library.widgets.discreteseekbar.DiscreteSeekBar; import org.joda.time.LocalDate; import org.parceler.Parcels; @@ -136,12 +138,8 @@ public void onStopTrackingTouch(DiscreteSeekBar seekBar) { binding.bow.setItemId(SettingsManager.getBow()); binding.arrow.setItemId(SettingsManager.getArrow()); binding.standardRound.setItemId(SettingsManager.getStandardRound()); - binding.standardRound.setOnUpdateListener( - item -> roundTarget = item.getRounds().get(0).getTargetTemplate()); binding.numberArrows.setChecked(SettingsManager.getArrowNumbersEnabled()); binding.environment.queryWeather(this, REQUEST_LOCATION_PERMISSION); - final StandardRound item = binding.standardRound.getSelectedItem(); - roundTarget = item.getRounds().get(0).getTargetTemplate(); } else { ToolbarUtils.setTitle(this, R.string.edit_training); Training train = Training.get(trainingId); @@ -173,8 +171,8 @@ public void onStopTrackingTouch(DiscreteSeekBar seekBar) { } private void updateChangeTargetFaceVisibility(StandardRound item) { - Target target = item.getRounds().get(0).getTargetTemplate(); - final boolean canBeChanged = (target.id < 7 || target.id == 10 || target.id == 11) + roundTarget = item.getRounds().get(0).getTargetTemplate(); + final boolean canBeChanged = (roundTarget.id < 7 || roundTarget.id == 10 || roundTarget.id == 11) && trainingType == TRAINING_WITH_STANDARD_ROUND; binding.changeTargetFace.setVisibility(canBeChanged ? View.VISIBLE : View.GONE); } @@ -247,7 +245,9 @@ protected void onSave() { } else { StandardRound standardRound = binding.standardRound.getSelectedItem(); SettingsManager.setStandardRound(standardRound.getId()); - standardRound.save(); + if (standardRound.getId() == null) { + standardRound.save(); + } training.standardRoundId = standardRound.getId(); training.rounds.addAll(createRoundsFromTemplate(standardRound, training)); } @@ -327,7 +327,11 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { binding.environment.onActivityResult(requestCode, resultCode, data); if (resultCode == Activity.RESULT_OK && requestCode == SR_TARGET_REQUEST_CODE) { final Parcelable parcelable = data.getParcelableExtra(ItemSelectActivity.ITEM); - roundTarget = Parcels.unwrap(parcelable); + Target target = Parcels.unwrap(parcelable); + final StandardRound item = binding.standardRound.getSelectedItem(); + Stream.of(item.getRounds()) + .forEach(r -> r.setTargetTemplate(target)); + binding.standardRound.setItem(item); } } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/overview/TrainingsFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/overview/TrainingsFragment.java index d2c84a755..fd9b8b750 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/overview/TrainingsFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/overview/TrainingsFragment.java @@ -60,7 +60,6 @@ public class TrainingsFragment extends ExpandableListFragment { public TrainingsFragment() { itemTypeSelRes = R.plurals.training_selected; itemTypeDelRes = R.plurals.training_deleted; - newStringRes = R.string.new_training; supportsStatistics = true; } diff --git a/app/src/main/java/de/dreier/mytargets/features/training/standardround/StandardRoundListFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/standardround/StandardRoundListFragment.java index d9fc7028b..891431b1b 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/standardround/StandardRoundListFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/standardround/StandardRoundListFragment.java @@ -132,12 +132,12 @@ public void onResume() { } @Override - public void onClick(SelectableViewHolder holder, StandardRound mItem) { - if (mItem == null) { + public void onClick(SelectableViewHolder holder, StandardRound item) { + if (item == null) { return; } - currentSelection = mItem; - super.onClick(holder, mItem); + currentSelection = item; + super.onClick(holder, item); } @Override diff --git a/app/src/main/java/de/dreier/mytargets/features/training/target/TargetListFragment.java b/app/src/main/java/de/dreier/mytargets/features/training/target/TargetListFragment.java index 143e04e61..af539bf9e 100644 --- a/app/src/main/java/de/dreier/mytargets/features/training/target/TargetListFragment.java +++ b/app/src/main/java/de/dreier/mytargets/features/training/target/TargetListFragment.java @@ -144,9 +144,9 @@ protected void selectItem(RecyclerView recyclerView, Target item) { } @Override - public void onClick(SelectableViewHolder holder, Target mItem) { - super.onClick(holder, mItem); - if (mItem == null) { + public void onClick(SelectableViewHolder holder, Target item) { + super.onClick(holder, item); + if (item == null) { return; } updateSettings(); @@ -155,7 +155,7 @@ public void onClick(SelectableViewHolder holder, Target mItem) { private void updateSettings() { // Init scoring styles - Target target = adapter.getItem(selector.getSelectedPosition()); + Target target = adapter.getItemById(selector.getSelectedId()); List styles = target.getModel().getScoringStyles(); updateAdapter(binding.scoringStyle, scoringStyleAdapter, styles); diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelector.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelector.java index 49ad5d45d..2a046fa27 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelector.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelector.java @@ -29,100 +29,51 @@ import de.dreier.mytargets.shared.utils.LongUtils; -public class MultiSelector { +public class MultiSelector extends SelectorBase { private static final String SELECTION_IDS = "ids"; - private static final String SELECTIONS_STATE = "state"; - private Set mSelections = new HashSet<>(); - private WeakHolderTracker mTracker = new WeakHolderTracker(); - private boolean mIsSelectable; + private Set selections = new HashSet<>(); - public void setSelectable(boolean isSelectable) { - this.mIsSelectable = isSelectable; - refreshAllHolders(); - } - - public void setSelected(SelectableHolder holder, boolean isSelected) { - this.setSelected(holder.getAdapterPosition(), holder.getItemId(), isSelected); - } - - public void setSelected(int position, long id, boolean isSelected) { + @Override + public void setSelected(long id, boolean isSelected) { if (isSelected) { - mSelections.add(id); + selections.add(id); } else { - mSelections.remove(id); + selections.remove(id); } - this.refreshHolder(mTracker.getHolder(position)); + refreshHolder(tracker.getHolder(id)); } - private boolean isSelected(long id) { - return mSelections.contains(id); + @Override + protected boolean isSelected(long id) { + return selections.contains(id); } public void clearSelections() { - this.mSelections.clear(); - this.refreshAllHolders(); + selections.clear(); + refreshAllHolders(); } public ArrayList getSelectedIds() { - return new ArrayList<>(mSelections); - } - - public void bindHolder(SelectableHolder holder, int position, long id) { - this.mTracker.bindHolder(holder, position); - this.refreshHolder(holder); - } - - public boolean tapSelection(SelectableHolder holder) { - return tapSelection(holder.getAdapterPosition(), holder.getItemId()); - } - - private boolean tapSelection(int position, long itemId) { - if (mIsSelectable) { - boolean isSelected = isSelected(itemId); - this.setSelected(position, itemId, !isSelected); - return true; - } else { - return false; - } - } - - private void refreshAllHolders() { - for (SelectableHolder holder : mTracker.getTrackedHolders()) { - this.refreshHolder(holder); - } - } - - private void refreshHolder(SelectableHolder holder) { - if (holder != null) { - if (holder instanceof ItemBindingHolder) { - if (((ItemBindingHolder) holder).getItem() != null) { - ((ItemBindingHolder) holder).bindItem(); - } - } - holder.setSelectable(mIsSelectable); - boolean isActivated = mSelections.contains(holder.getItemId()); - holder.setActivated(isActivated); - } + return new ArrayList<>(selections); } - public Bundle saveSelectionStates() { - Bundle information = new Bundle(); - information.putLongArray(SELECTION_IDS, LongUtils.toArray(getSelectedIds())); - information.putBoolean(SELECTIONS_STATE, this.mIsSelectable); - return information; + @Override + protected void saveSelectionStates(Bundle bundle) { + bundle.putLongArray(SELECTION_IDS, LongUtils.toArray(getSelectedIds())); } + @Override public void restoreSelectionStates(Bundle savedStates) { - long[] selectedPositions = savedStates.getLongArray(SELECTION_IDS); - restoreSelections(LongUtils.toList(selectedPositions)); - this.mIsSelectable = savedStates.getBoolean(SELECTIONS_STATE); + super.restoreSelectionStates(savedStates); + long[] selectedIds = savedStates.getLongArray(SELECTION_IDS); + restoreSelections(LongUtils.toList(selectedIds)); } private void restoreSelections(List selected) { if (selected != null) { - mSelections.clear(); - mSelections.addAll(selected); - this.refreshAllHolders(); + selections.clear(); + selections.addAll(selected); + refreshAllHolders(); } } } diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelectorBindingHolder.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelectorBindingHolder.java index 7fa1c42c0..366d61665 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelectorBindingHolder.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/MultiSelectorBindingHolder.java @@ -35,6 +35,6 @@ public MultiSelectorBindingHolder(View itemView, MultiSelector multiSelector) { @Override protected void onRebind() { - mMultiSelector.bindHolder(this, getAdapterPosition(), getItemId()); + mMultiSelector.bindHolder(this, getItemId()); } } \ No newline at end of file diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableHolder.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableHolder.java index 1c53dd966..9f33976e5 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableHolder.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectableHolder.java @@ -50,7 +50,7 @@ public interface SelectableHolder { /** *

Returns the adapter position this item is currently bound to. * This can (and often will) change; if attached to a {@link MultiSelector}, - * {@link MultiSelector#bindHolder(SelectableHolder, int, long)} + * {@link #bindHolder(SelectableHolder, long)} * should be called whenever this value changes.

* * @return Position this holder is currently bound to. @@ -60,7 +60,7 @@ public interface SelectableHolder { /** *

Return the item id this item is currently bound to. * This can (and often will) change; if attached to a {@link MultiSelector}, - * {@link MultiSelector#bindHolder(SelectableHolder, int, long)} + * {@link #bindHolder(SelectableHolder, long)} * should be called whenever this value changes.

* * @return Item id this holder is currently bound to. 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 b87649ae6..4cb60300b 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 @@ -41,37 +41,37 @@ */ public abstract class SelectableViewHolder extends ItemBindingHolder implements View.OnClickListener, View.OnLongClickListener { - private final MultiSelector mMultiSelector; - private OnItemClickListener mListener; - private boolean mIsSelectable = false; + private final SelectorBase multiSelector; + private OnItemClickListener listener; + private boolean isSelectable = false; /** * Construct a new SelectableHolder hooked up to be controlled by a MultiSelector. *

- * If the MultiSelector is not null, the SelectableHolder can be selected by - * calling {@link MultiSelector#setSelected(SelectableHolder, boolean)}. + * If the Selector is not null, the SelectableHolder can be selected by + * calling {@link SelectorBase#setSelected(SelectableHolder, boolean)}. *

* If the MultiSelector is null, the SelectableHolder acts as a standalone * ViewHolder that you can control manually by setting {@link #setSelectable(boolean)} * and {@link #setActivated(boolean)} * * @param itemView Item view for this ViewHolder - * @param multiSelector A selector set to bind this holder to + * @param selector A selector set to bind this holder to */ - public SelectableViewHolder(View itemView, MultiSelector multiSelector, OnItemClickListener listener) { + public SelectableViewHolder(View itemView, SelectorBase selector, OnItemClickListener listener) { super(itemView); - this.mMultiSelector = multiSelector; + this.multiSelector = selector; itemView.setOnClickListener(this); - if (multiSelector != null) { + if (selector != null) { itemView.setLongClickable(true); itemView.setOnLongClickListener(this); - mListener = listener; + this.listener = listener; } } @Override protected void onRebind() { - this.mMultiSelector.bindHolder(this, this.getAdapterPosition(), this.getItemId()); + multiSelector.bindHolder(this, getItemId()); } /** @@ -81,7 +81,7 @@ protected void onRebind() { * @return True if selectable. */ public boolean isSelectable() { - return mIsSelectable; + return isSelectable; } /** @@ -90,7 +90,7 @@ public boolean isSelectable() { * @param isSelectable True if selectable. */ public void setSelectable(boolean isSelectable) { - mIsSelectable = isSelectable; + this.isSelectable = isSelectable; } public T getItem() { @@ -103,14 +103,14 @@ void setItem(T mItem) { @Override public void onClick(View v) { - if (mListener != null) { - mListener.onClick(this, item); + if (listener != null) { + listener.onClick(this, item); } } @Override public boolean onLongClick(View v) { - mListener.onLongClick(this); + listener.onLongClick(this); return true; } diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectorBase.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectorBase.java new file mode 100644 index 000000000..3fb567745 --- /dev/null +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SelectorBase.java @@ -0,0 +1,86 @@ +/* + * 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.multiselector; + +import android.os.Bundle; +import android.support.annotation.CallSuper; + +public abstract class SelectorBase { + private static final String SELECTIONS_STATE = "state"; + protected WeakHolderTracker tracker = new WeakHolderTracker(); + private boolean isSelectable; + + public void setSelectable(boolean isSelectable) { + this.isSelectable = isSelectable; + refreshAllHolders(); + } + + protected void refreshAllHolders() { + for (SelectableHolder holder : tracker.getTrackedHolders()) { + refreshHolder(holder); + } + } + + protected void refreshHolder(SelectableHolder holder) { + if (holder != null) { + if (holder instanceof ItemBindingHolder && + ((ItemBindingHolder) holder).getItem() != null) { + ((ItemBindingHolder) holder).bindItem(); + } + holder.setSelectable(isSelectable); + boolean isActivated = isSelected(holder.getItemId()); + holder.setActivated(isActivated); + } + } + + public void setSelected(SelectableHolder holder, boolean isSelected) { + setSelected(holder.getItemId(), isSelected); + } + + public abstract void setSelected(long id, boolean isSelected); + + protected abstract boolean isSelected(long id); + + public boolean tapSelection(SelectableHolder holder) { + long itemId = holder.getItemId(); + if (isSelectable) { + boolean isSelected = isSelected(itemId); + setSelected(itemId, !isSelected); + return true; + } else { + return false; + } + } + + public final Bundle saveSelectionStates() { + Bundle bundle = new Bundle(); + bundle.putBoolean(SELECTIONS_STATE, isSelectable); + saveSelectionStates(bundle); + return bundle; + } + + public void bindHolder(SelectableHolder holder, long id) { + tracker.bindHolder(holder, id); + refreshHolder(holder); + } + + protected abstract void saveSelectionStates(Bundle bundle); + + @CallSuper + public void restoreSelectionStates(Bundle savedStates) { + isSelectable = savedStates.getBoolean(SELECTIONS_STATE); + } +} diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SingleSelector.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SingleSelector.java index 59e4dd974..3585ea7ab 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/SingleSelector.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/SingleSelector.java @@ -15,30 +15,46 @@ package de.dreier.mytargets.utils.multiselector; +import android.os.Bundle; + /** - *

A MultiSelector that only allows for one position at a time to be selected.

- *

Any time {@link #setSelected(int, long, boolean)} is called, all other selected positions are set to false.

+ *

A Selector that only allows for one position at a time to be selected.

+ *

Any time {@link SelectorBase#setSelected(long, boolean)} is called, all other selected positions are set to false.

*/ -public class SingleSelector extends MultiSelector { +public class SingleSelector extends SelectorBase { - private int selectedPosition = -1; + private static final String SELECTION_ID = "selection_id"; + private long selectedId = -1L; @Override - public void setSelected(int position, long id, boolean isSelected) { + public void setSelected(long id, boolean isSelected) { + long oldId = selectedId; if (isSelected) { - for (Long selectedId : getSelectedIds()) { - if (selectedId != position) { - super.setSelected(selectedPosition, selectedId, false); - } - } - selectedPosition = position; + selectedId = id; } else { - selectedPosition = -1; + selectedId = -1; } - super.setSelected(position, id, isSelected); + refreshHolder(tracker.getHolder(oldId)); + refreshHolder(tracker.getHolder(selectedId)); + } + + @Override + public boolean isSelected(long id) { + return id == selectedId && selectedId != -1; + } + + @Override + protected void saveSelectionStates(Bundle bundle) { + bundle.putLong(SELECTION_ID, selectedId); + } + + @Override + public void restoreSelectionStates(Bundle savedStates) { + super.restoreSelectionStates(savedStates); + selectedId = savedStates.getLong(SELECTION_ID); } - public int getSelectedPosition() { - return selectedPosition; + public Long getSelectedId() { + return selectedId == -1 ? null : selectedId; } } \ No newline at end of file diff --git a/app/src/main/java/de/dreier/mytargets/utils/multiselector/WeakHolderTracker.java b/app/src/main/java/de/dreier/mytargets/utils/multiselector/WeakHolderTracker.java index 7a6092264..e3b28e4e9 100644 --- a/app/src/main/java/de/dreier/mytargets/utils/multiselector/WeakHolderTracker.java +++ b/app/src/main/java/de/dreier/mytargets/utils/multiselector/WeakHolderTracker.java @@ -15,47 +15,39 @@ package de.dreier.mytargets.utils.multiselector; -import android.util.SparseArray; +import android.util.LongSparseArray; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; class WeakHolderTracker { - private SparseArray> mHoldersByPosition = - new SparseArray<>(); + private LongSparseArray> holdersById = + new LongSparseArray<>(); /** - * Returns the holder with a given position. If non-null, the returned - * holder is guaranteed to have getPosition() == position. + * Returns the holder with a given id. * - * @param position + * @param id * @return */ - public SelectableHolder getHolder(int position) { - WeakReference holderRef = mHoldersByPosition.get(position); + public SelectableHolder getHolder(long id) { + WeakReference holderRef = holdersById.get(id); if (holderRef == null) { return null; } - - SelectableHolder holder = holderRef.get(); - if (holder == null || holder.getAdapterPosition() != position) { - mHoldersByPosition.remove(position); - return null; - } - - return holder; + return holderRef.get(); } - public void bindHolder(SelectableHolder holder, int position) { - mHoldersByPosition.put(position, new WeakReference<>(holder)); + public void bindHolder(SelectableHolder holder, long id) { + holdersById.put(id, new WeakReference<>(holder)); } public List getTrackedHolders() { List holders = new ArrayList<>(); - for (int i = 0; i < mHoldersByPosition.size(); i++) { - int key = mHoldersByPosition.keyAt(i); + for (int i = 0; i < holdersById.size(); i++) { + long key = holdersById.keyAt(i); SelectableHolder holder = getHolder(key); if (holder != null) { diff --git a/app/src/main/java/de/dreier/mytargets/views/selector/DistanceSelector.java b/app/src/main/java/de/dreier/mytargets/views/selector/DistanceSelector.java index d58dffeb4..880478b6d 100644 --- a/app/src/main/java/de/dreier/mytargets/views/selector/DistanceSelector.java +++ b/app/src/main/java/de/dreier/mytargets/views/selector/DistanceSelector.java @@ -43,4 +43,4 @@ protected void bindView() { SelectorItemDistanceBinding binding = DataBindingUtil.bind(view); binding.distanceValue.setText(item.toString()); } -} +} \ No newline at end of file diff --git a/app/src/main/java/de/dreier/mytargets/views/selector/ImageSelectorBase.java b/app/src/main/java/de/dreier/mytargets/views/selector/ImageSelectorBase.java index b9fbd2fda..1e1820004 100644 --- a/app/src/main/java/de/dreier/mytargets/views/selector/ImageSelectorBase.java +++ b/app/src/main/java/de/dreier/mytargets/views/selector/ImageSelectorBase.java @@ -51,7 +51,6 @@ protected void bindView() { binding.details.setText(((IDetailProvider) item).getDetails(getContext())); } binding.image.setImageDrawable(item.getDrawable(getContext())); - invalidate(); } protected void setTitle(@StringRes int title) { diff --git a/app/src/main/java/de/dreier/mytargets/views/selector/SelectorBase.java b/app/src/main/java/de/dreier/mytargets/views/selector/SelectorBase.java index 100e4d7d7..0307e2604 100644 --- a/app/src/main/java/de/dreier/mytargets/views/selector/SelectorBase.java +++ b/app/src/main/java/de/dreier/mytargets/views/selector/SelectorBase.java @@ -113,10 +113,10 @@ public T getSelectedItem() { public void setItem(T item) { this.item = item; - updateView(); if (updateListener != null) { updateListener.onUpdate(item); } + updateView(); } public void setOnUpdateListener(OnUpdateListener updateListener) { diff --git a/app/src/main/res/layout/fragment_edit_standard_round.xml b/app/src/main/res/layout/fragment_edit_standard_round.xml index 7ace14b9b..e78196251 100644 --- a/app/src/main/res/layout/fragment_edit_standard_round.xml +++ b/app/src/main/res/layout/fragment_edit_standard_round.xml @@ -96,6 +96,8 @@