Skip to content

Commit

Permalink
Merge pull request #261 from rubensousa/dpadclickable
Browse files Browse the repository at this point in the history
Improve dpadClickable to work properly with key events
  • Loading branch information
rubensousa authored Aug 30, 2024
2 parents e1a0ea5 + 0296977 commit cdfe4e5
Show file tree
Hide file tree
Showing 18 changed files with 471 additions and 101 deletions.
4 changes: 2 additions & 2 deletions dpadrecyclerview-compose/api/dpadrecyclerview-compose.api
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ public final class com/rubensousa/dpadrecyclerview/compose/ComposableSingletons$
public final fun getLambda-1$dpadrecyclerview_compose_release ()Lkotlin/jvm/functions/Function4;
}

public final class com/rubensousa/dpadrecyclerview/compose/DpadComposeExtensionsKt {
public static final fun dpadClickable (Landroidx/compose/ui/Modifier;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;I)Landroidx/compose/ui/Modifier;
public final class com/rubensousa/dpadrecyclerview/compose/DpadClickableKt {
public static final fun dpadClickable (Landroidx/compose/ui/Modifier;ZLandroidx/compose/foundation/interaction/MutableInteractionSource;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;II)Landroidx/compose/ui/Modifier;
}

public final class com/rubensousa/dpadrecyclerview/compose/DpadComposeFocusViewHolder : androidx/recyclerview/widget/RecyclerView$ViewHolder {
Expand Down
4 changes: 2 additions & 2 deletions dpadrecyclerview-compose/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

<application tools:ignore="MissingTvBanner">
<activity
android:name="com.rubensousa.dpadrecyclerview.compose.test.ComposeFocusTestActivity"
android:name="com.rubensousa.dpadrecyclerview.compose.ComposeFocusTestActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:exported="true">
<intent-filter>
Expand All @@ -38,7 +38,7 @@
</intent-filter>
</activity>
<activity
android:name="com.rubensousa.dpadrecyclerview.compose.test.ViewFocusTestActivity"
android:name="com.rubensousa.dpadrecyclerview.compose.ViewFocusTestActivity"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:exported="true">
<intent-filter>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
* limitations under the License.
*/

package com.rubensousa.dpadrecyclerview.compose.test
package com.rubensousa.dpadrecyclerview.compose

import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
Expand All @@ -28,15 +29,15 @@ import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.OnViewFocusedListener
import com.rubensousa.dpadrecyclerview.compose.DpadComposeFocusViewHolder
import com.rubensousa.dpadrecyclerview.compose.TestComposableFocus
import com.rubensousa.dpadrecyclerview.compose.test.R
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent

class ComposeFocusTestActivity : AppCompatActivity() {

private lateinit var recyclerView: DpadRecyclerView
private val focusEvents = arrayListOf<DpadFocusEvent>()
private val clicks = ArrayList<Int>()
private val longClicks = ArrayList<Int>()
private val disposals = ArrayList<Int>()

override fun onCreate(savedInstanceState: Bundle?) {
Expand All @@ -55,6 +56,11 @@ class ComposeFocusTestActivity : AppCompatActivity() {
}
)
recyclerView.requestFocus()
onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
clearFocus()
}
})
}

fun requestFocus() {
Expand All @@ -69,6 +75,10 @@ class ComposeFocusTestActivity : AppCompatActivity() {
return clicks
}

fun getLongClicks(): List<Int> {
return clicks
}

fun getDisposals(): List<Int> {
return disposals
}
Expand Down Expand Up @@ -96,7 +106,7 @@ class ComposeFocusTestActivity : AppCompatActivity() {

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
viewType: Int,
): DpadComposeFocusViewHolder<Int> {
return DpadComposeFocusViewHolder(parent) { item ->
TestComposableFocus(
Expand All @@ -107,6 +117,9 @@ class ComposeFocusTestActivity : AppCompatActivity() {
onClick = {
clicks.add(item)
},
onLongClick = {
longClicks.add(item)
},
onDispose = {
onDispose(item)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.rubensousa.dpadrecyclerview.compose

import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
import androidx.test.espresso.Espresso
import androidx.test.espresso.matcher.ViewMatchers.withId
import com.google.common.truth.Truth.assertThat
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.assertions.DpadViewAssertions
import org.junit.Before
import org.junit.Rule
import org.junit.Test

class DpadClickableIntegrationTest {

@get:Rule
val composeTestRule = createAndroidComposeRule<ComposeFocusTestActivity>()

@Before
fun setup() {
composeTestRule.waitForIdle()
}

@Test
fun testPressingBackAfterClickingOnItemClearsFocus() {
// given
KeyEvents.click()

// when
KeyEvents.back()

// then
assertFocus(item = 0, isFocused = false)
Espresso.onView(
withId(com.rubensousa.dpadrecyclerview.compose.test.R.id.focusPlaceholder)
).check(DpadViewAssertions.isFocused())
}

@Test
fun testClicksAreDispatched() {
// given
var clicks: List<Int> = emptyList()
composeTestRule.activityRule.scenario.onActivity { activity ->
clicks = activity.getClicks()
}

// when
KeyEvents.click()

// then
assertThat(clicks).isEqualTo(listOf(0))
}

@Test
fun testLongClicksAreDispatched() {
// given
var clicks: List<Int> = emptyList()
composeTestRule.activityRule.scenario.onActivity { activity ->
clicks = activity.getLongClicks()
}

// when
KeyEvents.longClick()

// then
assertThat(clicks).isEqualTo(listOf(0))
}

private fun assertFocus(item: Int, isFocused: Boolean) {
composeTestRule.onNodeWithText(item.toString()).assertIsDisplayed()
.assert(SemanticsMatcher.expectValue(TestComposable.focusedKey, isFocused))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import androidx.test.espresso.matcher.ViewMatchers
import com.google.common.truth.Truth.assertThat
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.ExtraLayoutSpaceStrategy
import com.rubensousa.dpadrecyclerview.compose.test.ComposeFocusTestActivity
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.R
Expand Down Expand Up @@ -79,21 +78,6 @@ class DpadComposeFocusViewHolderTest {
assertFocus(item = 0, isFocused = true)
}

@Test
fun testClicksAreDispatched() {
// given
var clicks: List<Int> = emptyList()
composeTestRule.activityRule.scenario.onActivity { activity ->
clicks = activity.getClicks()
}

// when
KeyEvents.click()

// then
assertThat(clicks).isEqualTo(listOf(0))
}

@Test
fun testCompositionIsClearedWhenClearingAdapter() {
val viewHolders = ArrayList<RecyclerView.ViewHolder>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import androidx.test.espresso.matcher.ViewMatchers
import com.google.common.truth.Truth.assertThat
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.ExtraLayoutSpaceStrategy
import com.rubensousa.dpadrecyclerview.compose.test.ViewFocusTestActivity
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent
import com.rubensousa.dpadrecyclerview.testing.KeyEvents
import com.rubensousa.dpadrecyclerview.testing.R
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ fun TestComposableFocus(
modifier: Modifier = Modifier,
item: Int,
onClick: () -> Unit,
onLongClick: () -> Unit,
onDispose: () -> Unit = {},
) {
var isFocused by remember { mutableStateOf(false) }
Expand All @@ -100,9 +101,14 @@ fun TestComposableFocus(
}
.focusable()
.background(backgroundColor)
.clickable {
onClick()
},
.dpadClickable(
onLongClick = {
onLongClick()
},
onClick = {
onClick()
}
),
contentAlignment = Alignment.Center,
) {
Text(
Expand Down Expand Up @@ -130,7 +136,8 @@ fun TestComposableFocus(
fun TestComposablePreviewNormal() {
TestComposableFocus(
item = 0,
onClick = {}
onClick = {},
onLongClick = {}
)
}

Expand All @@ -141,7 +148,8 @@ fun TestComposablePreviewFocused() {
TestComposableFocus(
item = 0,
modifier = Modifier.focusRequester(focusRequester),
onClick = {}
onClick = {},
onLongClick = {}
)
SideEffect {
focusRequester.requestFocus()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

package com.rubensousa.dpadrecyclerview.compose.test
package com.rubensousa.dpadrecyclerview.compose

import android.os.Bundle
import android.view.View
Expand All @@ -28,8 +28,7 @@ import androidx.core.view.children
import androidx.recyclerview.widget.RecyclerView
import com.rubensousa.dpadrecyclerview.DpadRecyclerView
import com.rubensousa.dpadrecyclerview.OnViewFocusedListener
import com.rubensousa.dpadrecyclerview.compose.DpadComposeViewHolder
import com.rubensousa.dpadrecyclerview.compose.TestComposable
import com.rubensousa.dpadrecyclerview.compose.test.R
import com.rubensousa.dpadrecyclerview.testfixtures.DpadFocusEvent

class ViewFocusTestActivity : AppCompatActivity() {
Expand Down
Loading

0 comments on commit cdfe4e5

Please sign in to comment.