Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump to 1.3.0-beta01 #226

Merged
merged 5 commits into from
Jun 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 36 additions & 20 deletions README.MD
Original file line number Diff line number Diff line change
@@ -1,12 +1,44 @@
# DpadRecyclerView

A RecyclerView built for Android TV as a replacement for Leanback's BaseGridView.
A RecyclerView built for Android TV as a replacement for [Leanback's](https://developer.android.com/jetpack/androidx/releases/leanback) BaseGridView.

See the project website for more information: https://rubensousa.github.io/DpadRecyclerView

Motivation for this library: https://rubensousa.com/2022/11/08/dpadrecyclerview/
Why should you use this library?

1. Leanback hasn't received any significant update for years
2. Compose support for TV is still in its early stages
3. RecyclerView is stable and works well with Compose
4. You need to maintain an existing TV app and wish to introduce Compose in an incremental way
5. Contains useful Espresso testing helpers for your TV UI tests
6. More feature complete:

| Feature | DpadRecyclerView | Leanback | Compose TV |
|----------------------------------|------------------|----------|------------|
| Custom scrolling speeds | ✅ | ✅ | ❌ |
| Edge alignment preference | ✅ | ✅ | ❌ |
| Sub position selections | ✅ | ✅ | ❌ |
| Fading edges | ✅ | ✅ | ❌ |
| Alignment listener | ✅ | ✅ | ❌ |
| Grids with uneven span sizes | ✅ | ❌ | ✅ |
| Extra layout space | ✅ | ❌ | ✅ |
| Prefetching upcoming items | ✅ | ❌ | ✅ |
| Reverse layout | ✅ | ❌ | ✅ |
| Testing library | ✅ | ❌ | ✅ |
| Drag and Drop | ✅ | ❌ | ❌ |
| Infinite layout with loop | ✅ | ❌ | ❌ |
| Smooth alignment changes | ✅ | ❌ | ❌ |
| Child focus observer | ✅ | ❌ | ❌ |
| Circular and continuous focus | ✅ | ❌ | ❌ |
| Throttling scroll events | ✅ | ❌ | ❌ |
| Scrolling without animation | ✅ | ❌ | ❌ |
| Scrolling in secondary directory | ❌ | ✅ | ❌ |


Background story for this library is available in my [blog](https://rubensousa.com/2022/11/08/dpadrecyclerview/) in case you're interested.

Check the sample app for a complete example of integration of this library

Check the sample app for a complete example of integration of this library:

![sample](https://github.com/rubensousa/DpadRecyclerView/blob/master/assets/sample_cover.png?raw=true)

Expand All @@ -26,23 +58,7 @@ androidTestImplementation "com.rubensousa.dpadrecyclerview:dpadrecyclerview-test

Check the official website for more information and recipes: https://rubensousa.github.io/DpadRecyclerView

## New Features compared to Leanback's `BaseGridView`

### Layout

- Supports grids with different span sizes
- Supports infinite/endless scrolling
- Supports reverse layout
- XML attributes for easier configuration

### Scrolling and focus

- Supports changing the alignment configuration smoothly
- Supports limiting the number of pending alignments
- Supports non smooth scroll changes
- Supports continuous and circular grid focus

### Easier Compose Integration
## Easier Compose Integration

Documentation: https://rubensousa.github.io/DpadRecyclerView/compose/

Expand Down
19 changes: 19 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,25 @@

## Version 1.3.0

### 1.3.0-beta01

2024-06-17

#### Dependency updates

- Updated library to Kotlin 2.0
- Updated Compose ui libraries to `1.7.0-beta03`

#### New Features

- Added `DpadDragHelper` for drag and drop support ([#216](https://github.com/rubensousa/DpadRecyclerView/pull/216)). Documentation available [here](recipes/dragdrop.md).
- Now `recyclerView.setFocusableDirection(FocusableDirection.CIRCULAR)` can also be used in linear layouts that don't fill the entire space. ([#225](https://github.com/rubensousa/DpadRecyclerView/pull/225)

#### Improvements

- Now `focusOutFront` and `focusOutBack` are enabled by default due to feedback from library users ([#223](https://github.com/rubensousa/DpadRecyclerView/pull/223))
- Improved focus behavior for grids with uneven spans that have incomplete rows ([#224](https://github.com/rubensousa/DpadRecyclerView/pull/224))

### 1.3.0-alpha04

2024-06-04
Expand Down
2 changes: 1 addition & 1 deletion docs/compose.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fun ItemComposable(
.onFocusChanged { focusState ->
isFocused = focusState.hasFocus
}
.focusTarget()
.focusable()
.dpadClickable {
onClick()
},
Expand Down
2 changes: 1 addition & 1 deletion docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ fun ItemComposable(
.onFocusChanged { focusState ->
isFocused = focusState.hasFocus
}
.focusTarget()
.focusable()
.dpadClickable {
onClick()
},
Expand Down
53 changes: 35 additions & 18 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
# DpadRecyclerView

A RecyclerView built for Android TV as a replacement for [Leanback's](https://developer.android.com/jetpack/androidx/releases/leanback) BaseGridView.
A RecyclerView built for Android TV as a replacement
for [Leanback's](https://developer.android.com/jetpack/androidx/releases/leanback) BaseGridView.

Proceed to [Getting started](getting_started.md) to start adding `DpadRecyclerView`
to your application.

Motivation for this library is available in my [blog](https://rubensousa.com/2022/11/08/dpadrecyclerview/) in case you're interested.

## New Features compared to Leanback's `BaseGridView`

### Layout

- Grids with different span sizes
- Infinite loop
- Reverse layout
- XML attributes for easier configuration

### Scrolling and focus

- Changing the alignment configuration smoothly
- Limiting the number of pending alignments
- Non smooth scroll changes
- Continuous and circular grid focus
Why should you use this library?

1. Leanback hasn't received any significant update for years
2. Compose support for TV is still in its early stages
3. RecyclerView is stable and works well with Compose
4. You need to maintain an existing TV app and wish to introduce Compose in an incremental way
5. Contains useful Espresso testing helpers for your TV UI tests
6. More feature complete:

| Feature | DpadRecyclerView | Leanback | Compose TV |
|-----------------------------------|------------------|----------|------------|
| Custom scrolling speeds | ✅ | ✅ | ❌ |
| Edge alignment preference | ✅ | ✅ | ❌ |
| Sub position selections | ✅ | ✅ | ❌ |
| Fading edges | ✅ | ✅ | ❌ |
| Alignment listener | ✅ | ✅ | ❌ |
| Grids with uneven span sizes | ✅ | ❌ | ✅ |
| Extra layout space | ✅ | ❌ | ✅ |
| Prefetching upcoming items | ✅ | ❌ | ✅ |
| Reverse layout | ✅ | ❌ | ✅ |
| Testing library | ✅ | ❌ | ✅ |
| Drag and Drop | ✅ | ❌ | ❌ |
| Infinite layout with loop | ✅ | ❌ | ❌ |
| Smooth alignment changes | ✅ | ❌ | ❌ |
| Discrete scrolling for text pages | ✅ | ❌ | ❌ |
| Child focus observer | ✅ | ❌ | ❌ |
| Circular and continuous focus | ✅ | ❌ | ❌ |
| Throttling scroll events | ✅ | ❌ | ❌ |
| Scrolling without animation | ✅ | ❌ | ❌ |
| Scrolling in secondary directory | ❌ | ✅ | ❌ |


Background story for this library is available in my [blog](https://rubensousa.com/2022/11/08/dpadrecyclerview/) in case you're interested.

## License

Expand Down
74 changes: 74 additions & 0 deletions docs/recipes/dragdrop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Drag and Drop Recipe

Sometimes, users need to arrange the order of some collection.
The APIs mentioned here should assist you in developing such a feature.

## Make your adapter mutable

`DpadDragHelper` requires a `DpadDragHelper.DragAdapter<T>` that exposes the mutable collection backing the adapter contents.
This allows `DpadDragHelper` to change the order of the elements for you automatically.

You just need to implement `DpadDragHelper.DragAdapter<T>` for this step:


```kotlin linenums="1" hl_lines="8"
class ExampleAdapter(
private val adapterConfig: AdapterConfig
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(),
DpadDragHelper.DragAdapter<Int> {

private val items = ArrayList<Int>()

override fun getMutableItems(): MutableList<Int> = items

```

## Create a `DpadDragHelper`

Now that you have a `DragAdapter` setup, just create a `DpadDragHelper` like so:

```kotlin linenums="1"
private val adapter = ExampleAdapter()
private val dragHelper = DpadDragHelper(
adapter = dragAdapter,
callback = object : DpadDragHelper.DragCallback {
override fun onDragStarted(viewHolder: RecyclerView.ViewHolder) {
// ViewHolder is now being dragged
}
override fun onDragStopped() {
// Dragging was cancelled either by user or programmatically
}
}
)

```

Then attach it to your `DpadRecyclerView`:

```kotlin
dragHelper.attachToRecyclerView(dpadRecyclerView)
```

!!! note
This only supports drag and drop for linear and grid layouts with the same number of spans.


## Start and stop dragging

Now that `DpadDragHelper` is setup, you can start dragging by using:

```kotlin
dragHelper.startDrag(position = 0)
```

If the position passed in the method above is not currently selected, a selection will be triggered.

To cancel dragging for any reason, use:

```kotlin
dragHelper.stopDrag()
```

!!! note
Users can also stop dragging by pressing the following keys: `KeyEvent.KEYCODE_DPAD_CENTER`,
`KeyEvent.KEYCODE_ENTER`, `KeyEvent.KEYCODE_BACK`. These are customizable in the constructor of `DpadDragHelper`
17 changes: 14 additions & 3 deletions docs/recipes/scrolling.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,23 @@ The code above translates to this behavior:

In the right scenario, there's just one next focusable view since the focused view still isn't aligned to the keyline.

## Disabling layout during scrolling events
## Enabling layout during scrolling events

If you want to postpone layout changes until the scroll state is idle, use this:
If you want to enable layout changes while `DpadRecyclerView` is still scrolling, use:

```kotlin
recyclerView.setLayoutWhileScrollingEnabled(false)
recyclerView.setLayoutWhileScrollingEnabled(true)
```

## Long text scrolling

In some cases, you might need to show pages with text that should be scrollable (e.g terms & conditions).

For this use case, you can use `DpadScroller`:

```kotlin
val scroller = DpadScroller()
scroller.attach(dpadRecyclerView)
```

`DpadScroller` will scroll the page for you on key event presses without any alignment so that the user can read the entire content
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package com.rubensousa.dpadrecyclerview.compose

import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
Expand All @@ -32,7 +33,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusTarget
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.SemanticsPropertyKey
Expand Down Expand Up @@ -98,7 +98,7 @@ fun TestComposableFocus(
.onFocusChanged { focusState ->
isFocused = focusState.isFocused
}
.focusTarget()
.focusable()
.background(backgroundColor)
.clickable {
onClick()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class DpadDragHelper<T>(
}
val recyclerView = currentRecyclerView
?: throw IllegalStateException(
"RecyclerView not attached. Please use attachRecyclerView before calling startDrag"
"RecyclerView not attached. Please use attachToRecyclerView before calling startDrag"
)
val adapter = recyclerView.adapter ?: return false
if (position < 0 || position >= adapter.itemCount) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,12 @@ open class DpadRecyclerView @JvmOverloads constructor(
)
layout.setFocusOutSideAllowed(
throughFront = typedArray.getBoolean(
R.styleable.DpadRecyclerView_dpadRecyclerViewFocusOutSideFront, config.focusOutSideFront
R.styleable.DpadRecyclerView_dpadRecyclerViewFocusOutSideFront,
config.focusOutSideFront
),
throughBack = typedArray.getBoolean(
R.styleable.DpadRecyclerView_dpadRecyclerViewFocusOutSideBack, config.focusOutSideBack
R.styleable.DpadRecyclerView_dpadRecyclerViewFocusOutSideBack,
config.focusOutSideBack
)
)
layout.setFocusableDirection(
Expand Down Expand Up @@ -848,7 +850,7 @@ open class DpadRecyclerView @JvmOverloads constructor(
* @see [setReverseLayout]
*/
fun isLayoutReversed(): Boolean {
return requireLayout().getConfig().reverseLayout
return requireLayout().isLayoutReversed
}

/**
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ kotlin.code.style=official
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true
android.enableR8.fullMode=true
LIBRARY_VERSION=1.3.0-alpha04
LIBRARY_VERSION=1.3.0-beta01
3 changes: 2 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ theme:

extra:
dpadrecyclerview:
version: '1.3.0-alpha04'
version: '1.3.0-beta01'
social:
- icon: 'fontawesome/brands/github'
link: 'https://github.com/rubensousa/DpadRecyclerView'
Expand Down Expand Up @@ -65,5 +65,6 @@ nav:
- 'Alignment': recipes/alignment.md
- 'Focus': recipes/focus.md
- 'Scrolling': recipes/scrolling.md
- 'Drag and drop': recipes/dragdrop.md
- 'Changelog': changelog.md
- 'API': api/
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.rubensousa.dpadrecyclerview.sample.ui.screen.drag

import androidx.compose.foundation.background
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
Expand All @@ -36,7 +37,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusTarget
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
Expand Down Expand Up @@ -73,7 +73,7 @@ fun DragButtonItem(
.onFocusChanged { focusState ->
isFocused = focusState.hasFocus
}
.focusTarget()
.focusable()
.dpadClickable {
if (isDragging) {
onStopDragClick()
Expand Down
Loading
Loading