You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/main/java/org/mozilla/fenix/tabstray/browser/InactiveTabsAdapter.kt

153 lines
5.6 KiB
Kotlin

/* 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.browser
import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import mozilla.components.browser.state.state.TabPartition
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.tabstray.TabsTray
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.tabstray.TabsTrayInteractor
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.AutoCloseDialogHolder
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.FooterHolder
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.HeaderHolder
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.TabViewHolder
import org.mozilla.fenix.utils.Settings
/**
* A convenience alias for readability.
*/
private typealias Adapter = ListAdapter<InactiveTabsAdapter.Item, InactiveTabViewHolder>
/**
* The [ListAdapter] for displaying the list of inactive tabs.
*
* @param context [Context] used for various platform interactions or accessing [Components]
* @param browserTrayInteractor [BrowserTrayInteractor] handling tabs interactions in a tab tray.
* @param featureName [String] representing the name of the feature displaying tabs. Used in telemetry reporting.
*/
class InactiveTabsAdapter(
private val context: Context,
private val browserTrayInteractor: BrowserTrayInteractor,
private val tabsTrayInteractor: TabsTrayInteractor,
override val featureName: String,
private val settings: Settings,
) : Adapter(DiffCallback), TabsTray, FeatureNameHolder {
internal lateinit var inactiveTabsInteractor: InactiveTabsInteractor
private var inActiveTabsCount: Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InactiveTabViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(viewType, parent, false)
return when (viewType) {
AutoCloseDialogHolder.LAYOUT_ID -> AutoCloseDialogHolder(view, inactiveTabsInteractor)
HeaderHolder.LAYOUT_ID -> HeaderHolder(view, inactiveTabsInteractor, tabsTrayInteractor)
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, browserTrayInteractor, featureName)
FooterHolder.LAYOUT_ID -> FooterHolder(view)
else -> throw IllegalStateException("Unknown viewType: $viewType")
}
}
override fun onBindViewHolder(holder: InactiveTabViewHolder, position: Int) {
when (holder) {
is TabViewHolder -> {
val item = getItem(position) as Item.Tab
holder.bind(item.tab)
}
is FooterHolder, is HeaderHolder, is AutoCloseDialogHolder -> {
// do nothing.
}
}
}
override fun getItemViewType(position: Int): Int {
return when (position) {
0 -> HeaderHolder.LAYOUT_ID
1 -> if (settings.shouldShowInactiveTabsAutoCloseDialog(inActiveTabsCount)) {
AutoCloseDialogHolder.LAYOUT_ID
} else {
TabViewHolder.LAYOUT_ID
}
itemCount - 1 -> FooterHolder.LAYOUT_ID
else -> TabViewHolder.LAYOUT_ID
}
}
override fun updateTabs(tabs: List<TabSessionState>, tabPartition: TabPartition?, selectedTabId: String?) {
inActiveTabsCount = tabs.size
// Early return with an empty list to remove the header/footer items.
if (tabs.isEmpty()) {
submitList(emptyList())
return
}
// If we have items, but we should be in a collapsed state.
if (!context.components.appStore.state.inactiveTabsExpanded) {
submitList(listOf(Item.Header))
return
}
val items = tabs.map { Item.Tab(it) }
val footer = Item.Footer
val headerItems = if (settings.shouldShowInactiveTabsAutoCloseDialog(items.size)) {
listOf(Item.Header, Item.AutoCloseMessage)
} else {
listOf(Item.Header)
}
submitList(headerItems + items + listOf(footer))
}
private object DiffCallback : DiffUtil.ItemCallback<Item>() {
override fun areItemsTheSame(oldItem: Item, newItem: Item): Boolean {
return if (oldItem is Item.Tab && newItem is Item.Tab) {
oldItem.tab.id == newItem.tab.id
} else {
oldItem == newItem
}
}
override fun areContentsTheSame(oldItem: Item, newItem: Item): Boolean {
return oldItem == newItem
}
}
/**
* The types of different data we can put into the [InactiveTabsAdapter].
*/
sealed class Item {
/**
* A title header for the inactive tab section. This may be seen only
* when at least one inactive tab is present.
*/
object Header : Item()
/**
* A tab that is now considered inactive.
*/
data class Tab(val tab: TabSessionState) : Item()
/**
* A dialog for when the inactive tabs section reach 20 tabs.
*/
object AutoCloseMessage : Item()
/**
* A footer for the inactive tab section. This may be seen only
* when at least one inactive tab is present.
*/
object Footer : Item()
}
}