Skip to content

Commit f4fc155

Browse files
committed
tv: hack gridlayoutmanager to fill columns before row if we're not scrolling
If we're horizontally scrolling, it makes sense to fill rows before columns. But if it all fits in one page and we don't need to scroll horizontally, it looks ridiculous. So, in this case, rearrange the tiles so that it appears to fill columns before rows. But we don't want things suddenly jumping around, so actually, keep the same ordering as rows-before-columns, but add invisible spaces after certain items, so that the fill area makes it look as though it's columns-before-rows. This winds up being much more visually pleasing. We do this by figuring out this kind of transformation: If we convert this matrix: 0 3 6 1 4 _ 2 5 _ To this one: 0 2 4 6 1 3 5 _ _ _ _ _ For a given index, how many spaces are under it? This changes depending on how many total are in a grid. Going from 3x3 to 4x3, for example, we have: count == 12, index = count == 11, index = 10 count == 10, index = 7,9 count == 9, index = 4,6,8 count == 8, index = 1,3,5,7 count == 7, index = 1,3,5,6! count == 6, index = 1,3,4!,5! count == 5, index = 1,2!,3!,4! count == 4, index = 0!,1!,2!,3! count == 3, index = 0!,1!,2! count == 2, index = 0!,1! count == 1, index = 0! count == 0, index = The '!' means two blanks below, no '!' means one blank below, and no mention means no blanks below. This commit adds code to compute such a table on the fly. Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent 938399d commit f4fc155

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed

ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import androidx.databinding.DataBindingUtil
2525
import androidx.databinding.ObservableBoolean
2626
import androidx.databinding.ObservableField
2727
import androidx.lifecycle.lifecycleScope
28+
import androidx.recyclerview.widget.GridLayoutManager
29+
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
2830
import com.wireguard.android.Application
2931
import com.wireguard.android.R
3032
import com.wireguard.android.backend.GoBackend
@@ -94,6 +96,8 @@ class TvMainActivity : AppCompatActivity() {
9496
binding.isDeleting = isDeleting
9597
binding.files = files
9698
binding.filesRoot = filesRoot
99+
val gridManager = binding.tunnelList.layoutManager as GridLayoutManager
100+
gridManager.spanSizeLookup = SlatedSpanSizeLookup(gridManager)
97101
binding.tunnelRowConfigurationHandler = object : ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TvTunnelListItemBinding, ObservableTunnel> {
98102
override fun onConfigureRow(binding: TvTunnelListItemBinding, item: ObservableTunnel, position: Int) {
99103
binding.isDeleting = isDeleting
@@ -339,6 +343,48 @@ class TvMainActivity : AppCompatActivity() {
339343
get() = forcedKey ?: if (file.isDirectory) "${file.name}/" else file.name
340344
}
341345

346+
private class SlatedSpanSizeLookup(private val gridManager: GridLayoutManager) : SpanSizeLookup() {
347+
private val originalHeight = gridManager.spanCount
348+
private var newWidth = 0
349+
private lateinit var sizeMap: Array<IntArray?>
350+
351+
private fun emptyUnderIndex(index: Int, size: Int): Int {
352+
sizeMap[size - 1]?.let { return it[index] }
353+
val sizes = IntArray(size)
354+
val oh = originalHeight
355+
val nw = newWidth
356+
var empties = 0
357+
for (i in 0 until size) {
358+
val ox = (i + empties) / oh
359+
val oy = (i + empties) % oh
360+
var empty = 0
361+
for (j in oy + 1 until oh) {
362+
val ni = nw * j + ox
363+
if (ni < size)
364+
break
365+
empty++
366+
}
367+
empties += empty
368+
sizes[i] = empty
369+
}
370+
sizeMap[size - 1] = sizes
371+
return sizes[index]
372+
}
373+
374+
override fun getSpanSize(position: Int): Int {
375+
if (newWidth == 0) {
376+
val child = gridManager.getChildAt(0) ?: return 1
377+
if (child.width == 0) return 1
378+
newWidth = gridManager.width / child.width
379+
sizeMap = Array(originalHeight * newWidth - 1) { null }
380+
}
381+
val total = gridManager.itemCount
382+
if (total >= originalHeight * newWidth || total == 0)
383+
return 1
384+
return emptyUnderIndex(position, total) + 1
385+
}
386+
}
387+
342388
companion object {
343389
private const val TAG = "WireGuard/TvMainActivity"
344390
}

0 commit comments

Comments
 (0)