forked from mozilla-mobile/fenix
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AbstractBrowserPageViewHolder.kt
110 lines (96 loc) · 3.78 KB
/
AbstractBrowserPageViewHolder.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.tabstray.viewholders
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.widget.TextView
import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.R
import org.mozilla.fenix.tabstray.TabsTrayInteractor
import org.mozilla.fenix.tabstray.TabsTrayStore
import org.mozilla.fenix.tabstray.TrayPagerAdapter
import org.mozilla.fenix.tabstray.browser.AbstractBrowserTrayList
/**
* A shared view holder for browser tabs tray list.
*/
abstract class AbstractBrowserPageViewHolder(
containerView: View,
tabsTrayStore: TabsTrayStore,
interactor: TabsTrayInteractor,
) : AbstractPageViewHolder(containerView) {
private val trayList: AbstractBrowserTrayList = itemView.findViewById(R.id.tray_list_item)
private val emptyList: TextView = itemView.findViewById(R.id.tab_tray_empty_view)
private var adapterObserver: RecyclerView.AdapterDataObserver? = null
private var adapterRef: RecyclerView.Adapter<out RecyclerView.ViewHolder>? = null
abstract val emptyStringText: String
init {
trayList.interactor = interactor
trayList.tabsTrayStore = tabsTrayStore
emptyList.text = emptyStringText
}
/**
* A way for an implementor of [AbstractBrowserPageViewHolder] to define their own scroll-to-tab behaviour.
*/
abstract fun scrollToTab(
adapter: RecyclerView.Adapter<out RecyclerView.ViewHolder>,
layoutManager: RecyclerView.LayoutManager
)
@CallSuper
protected fun bind(
adapter: RecyclerView.Adapter<out RecyclerView.ViewHolder>,
layoutManager: RecyclerView.LayoutManager
) {
adapterRef = adapter
scrollToTab(adapter, layoutManager)
trayList.layoutManager = layoutManager
trayList.adapter = adapter
}
/**
* When the [RecyclerView.Adapter] is attached to the window we register a data observer to
* always check whether to call [updateTrayVisibility].
*
* We keep a constant observer instead of using [RecyclerView.Adapter.observeFirstInsert],
* because some adapters can insert empty lists and trigger the one-shot observer too soon.
*
* See also [AbstractPageViewHolder.attachedToWindow].
*/
override fun attachedToWindow() {
adapterRef?.let { adapter ->
adapterObserver = object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
updateTrayVisibility(adapter.itemCount)
}
override fun onItemRangeRemoved(positionstart: Int, itemcount: Int) {
updateTrayVisibility(adapter.itemCount)
}
}
adapterObserver?.let {
adapter.registerAdapterDataObserver(it)
}
}
}
/**
* [RecyclerView.AdapterDataObserver]s are responsible to be unregistered when they are done,
* so we do that here when our [TrayPagerAdapter] page is detached from the window.
*
* See also [AbstractPageViewHolder.detachedFromWindow].
*/
override fun detachedFromWindow() {
adapterObserver?.let {
adapterRef?.unregisterAdapterDataObserver(it)
adapterObserver = null
}
}
private fun updateTrayVisibility(size: Int) {
if (size == 0) {
trayList.visibility = GONE
emptyList.visibility = VISIBLE
} else {
trayList.visibility = VISIBLE
emptyList.visibility = GONE
}
}
}