Skip to content

Commit ef40ba4

Browse files
committed
fix: avoid anchoring reviewer snackbar to hidden answer buttons
1 parent 9e745d6 commit ef40ba4

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

AnkiDroid/src/main/java/com/ichi2/anki/AbstractFlashcardViewer.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,9 +1827,11 @@ abstract class AbstractFlashcardViewer :
18271827
}
18281828

18291829
override val baseSnackbarBuilder: SnackbarBuilder = {
1830-
// Configure the snackbar to avoid the bottom answer buttons
1830+
// Configure the snackbar to avoid the bottom answer buttons.
1831+
// The answer buttons are animated to GONE in fullscreen mode (see Reviewer.hideViewWithAnimation),
1832+
// so check visibility to avoid anchoring the snackbar to a hidden view (#20946).
18311833
if (answerButtonsPosition == "bottom") {
1832-
anchorView = findViewById(R.id.answer_options_layout)
1834+
anchorView = findViewById<View>(R.id.answer_options_layout)?.takeIf { it.isVisible }
18331835
}
18341836
}
18351837

AnkiDroid/src/test/java/com/ichi2/anki/ReviewerTest.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.ichi2.anki
1818
import android.app.Application
1919
import android.content.Intent
2020
import android.view.Menu
21+
import android.view.View
2122
import androidx.annotation.CheckResult
2223
import androidx.core.content.edit
2324
import androidx.core.os.BundleCompat
@@ -52,6 +53,7 @@ import com.ichi2.anki.observability.undoableOp
5253
import com.ichi2.anki.preferences.PreferenceTestUtils
5354
import com.ichi2.anki.preferences.sharedPrefs
5455
import com.ichi2.anki.reviewer.ActionButtonStatus
56+
import com.ichi2.anki.snackbar.showSnackbar
5557
import com.ichi2.testutils.common.Flaky
5658
import com.ichi2.testutils.common.OS
5759
import junit.framework.TestCase.assertEquals
@@ -62,6 +64,7 @@ import org.hamcrest.Matchers.containsString
6264
import org.hamcrest.Matchers.empty
6365
import org.hamcrest.Matchers.equalTo
6466
import org.hamcrest.Matchers.not
67+
import org.hamcrest.Matchers.nullValue
6568
import org.json.JSONArray
6669
import org.junit.Assume.assumeTrue
6770
import org.junit.Ignore
@@ -154,6 +157,38 @@ class ReviewerTest : RobolectricTest() {
154157
assertEquals("Animation from swipe should be inverse to the finishing one", expectedAnimation, actualAnimation)
155158
}
156159

160+
@Test
161+
fun `baseSnackbarBuilder has no anchor when answer buttons are hidden`() {
162+
addBasicNote()
163+
val reviewer = startReviewer()
164+
val answerButtons = reviewer.findViewById<View>(R.id.answer_options_layout)
165+
answerButtons.visibility = View.GONE
166+
167+
val snackbar = reviewer.showSnackbar("test")
168+
169+
assertThat(
170+
"anchorView must be null when answer buttons layout is not visible",
171+
snackbar?.anchorView,
172+
nullValue(),
173+
)
174+
}
175+
176+
@Test
177+
fun `baseSnackbarBuilder anchors to answer buttons when visible`() {
178+
addBasicNote()
179+
val reviewer = startReviewer()
180+
val answerButtons = reviewer.findViewById<View>(R.id.answer_options_layout)
181+
answerButtons.visibility = View.VISIBLE
182+
183+
val snackbar = reviewer.showSnackbar("test")
184+
185+
assertThat(
186+
"anchorView is the answer buttons layout when visible",
187+
snackbar?.anchorView,
188+
equalTo(answerButtons),
189+
)
190+
}
191+
157192
@Test
158193
fun noErrorShouldOccurIfSoundFileNotPresent() {
159194
addBasicNote("[[sound:not_on_file_system.mp3]]", "World")

0 commit comments

Comments
 (0)