summaryrefslogtreecommitdiffhomepage
path: root/ui/src/main/java/com
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2020-09-27 01:56:22 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2020-09-27 13:17:56 +0200
commitf4fc15538d9946a5fe3818eaca3cd96bd2befd15 (patch)
treefe2fc7385544085b059fb7062018e55fe8a03dfc /ui/src/main/java/com
parent938399d881aa6b365be131ffb3a517d64be427bb (diff)
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 <Jason@zx2c4.com>
Diffstat (limited to 'ui/src/main/java/com')
-rw-r--r--ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt46
1 files changed, 46 insertions, 0 deletions
diff --git a/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt b/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt
index 7119bec0..66410979 100644
--- a/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt
+++ b/ui/src/main/java/com/wireguard/android/activity/TvMainActivity.kt
@@ -25,6 +25,8 @@ import androidx.databinding.DataBindingUtil
import androidx.databinding.ObservableBoolean
import androidx.databinding.ObservableField
import androidx.lifecycle.lifecycleScope
+import androidx.recyclerview.widget.GridLayoutManager
+import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import com.wireguard.android.Application
import com.wireguard.android.R
import com.wireguard.android.backend.GoBackend
@@ -94,6 +96,8 @@ class TvMainActivity : AppCompatActivity() {
binding.isDeleting = isDeleting
binding.files = files
binding.filesRoot = filesRoot
+ val gridManager = binding.tunnelList.layoutManager as GridLayoutManager
+ gridManager.spanSizeLookup = SlatedSpanSizeLookup(gridManager)
binding.tunnelRowConfigurationHandler = object : ObservableKeyedRecyclerViewAdapter.RowConfigurationHandler<TvTunnelListItemBinding, ObservableTunnel> {
override fun onConfigureRow(binding: TvTunnelListItemBinding, item: ObservableTunnel, position: Int) {
binding.isDeleting = isDeleting
@@ -339,6 +343,48 @@ class TvMainActivity : AppCompatActivity() {
get() = forcedKey ?: if (file.isDirectory) "${file.name}/" else file.name
}
+ private class SlatedSpanSizeLookup(private val gridManager: GridLayoutManager) : SpanSizeLookup() {
+ private val originalHeight = gridManager.spanCount
+ private var newWidth = 0
+ private lateinit var sizeMap: Array<IntArray?>
+
+ private fun emptyUnderIndex(index: Int, size: Int): Int {
+ sizeMap[size - 1]?.let { return it[index] }
+ val sizes = IntArray(size)
+ val oh = originalHeight
+ val nw = newWidth
+ var empties = 0
+ for (i in 0 until size) {
+ val ox = (i + empties) / oh
+ val oy = (i + empties) % oh
+ var empty = 0
+ for (j in oy + 1 until oh) {
+ val ni = nw * j + ox
+ if (ni < size)
+ break
+ empty++
+ }
+ empties += empty
+ sizes[i] = empty
+ }
+ sizeMap[size - 1] = sizes
+ return sizes[index]
+ }
+
+ override fun getSpanSize(position: Int): Int {
+ if (newWidth == 0) {
+ val child = gridManager.getChildAt(0) ?: return 1
+ if (child.width == 0) return 1
+ newWidth = gridManager.width / child.width
+ sizeMap = Array(originalHeight * newWidth - 1) { null }
+ }
+ val total = gridManager.itemCount
+ if (total >= originalHeight * newWidth || total == 0)
+ return 1
+ return emptyUnderIndex(position, total) + 1
+ }
+ }
+
companion object {
private const val TAG = "WireGuard/TvMainActivity"
}