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.
144 lines
5.1 KiB
Kotlin
144 lines
5.1 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.concept.tabstray.Tab as TabsTrayTab
|
|
import mozilla.components.concept.tabstray.Tabs
|
|
import mozilla.components.concept.tabstray.TabsTray
|
|
import mozilla.components.support.base.observer.ObserverRegistry
|
|
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.FooterHolder
|
|
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.HeaderHolder
|
|
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.RecentlyClosedHolder
|
|
import org.mozilla.fenix.tabstray.browser.InactiveTabViewHolder.TabViewHolder
|
|
import org.mozilla.fenix.tabstray.ext.autoCloseInterval
|
|
import mozilla.components.support.base.observer.Observable as ComponentObservable
|
|
|
|
/**
|
|
* A convenience alias for readability.
|
|
*/
|
|
private typealias Adapter = ListAdapter<InactiveTabsAdapter.Item, InactiveTabViewHolder>
|
|
|
|
/**
|
|
* A convenience alias for readability.
|
|
*/
|
|
private typealias Observable = ComponentObservable<TabsTray.Observer>
|
|
|
|
/**
|
|
* The [ListAdapter] for displaying the list of inactive tabs.
|
|
*/
|
|
class InactiveTabsAdapter(
|
|
private val context: Context,
|
|
private val browserTrayInteractor: BrowserTrayInteractor,
|
|
delegate: Observable = ObserverRegistry()
|
|
) : Adapter(DiffCallback), TabsTray, Observable by delegate {
|
|
|
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): InactiveTabViewHolder {
|
|
val view = LayoutInflater.from(parent.context)
|
|
.inflate(viewType, parent, false)
|
|
|
|
return when (viewType) {
|
|
HeaderHolder.LAYOUT_ID -> HeaderHolder(view)
|
|
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, browserTrayInteractor)
|
|
FooterHolder.LAYOUT_ID -> FooterHolder(view)
|
|
RecentlyClosedHolder.LAYOUT_ID -> RecentlyClosedHolder(view, browserTrayInteractor)
|
|
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 -> {
|
|
val item = getItem(position) as Item.Footer
|
|
holder.bind(item.interval)
|
|
}
|
|
is HeaderHolder -> {
|
|
// do nothing.
|
|
}
|
|
is RecentlyClosedHolder -> {
|
|
holder.bind()
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getItemViewType(position: Int): Int {
|
|
return when (position) {
|
|
0 -> HeaderHolder.LAYOUT_ID
|
|
itemCount - 2 -> RecentlyClosedHolder.LAYOUT_ID
|
|
itemCount - 1 -> FooterHolder.LAYOUT_ID
|
|
else -> TabViewHolder.LAYOUT_ID
|
|
}
|
|
}
|
|
|
|
override fun updateTabs(tabs: Tabs) {
|
|
if (tabs.list.isEmpty()) {
|
|
// Early return with an empty list to remove the header/footer items.
|
|
submitList(emptyList())
|
|
return
|
|
}
|
|
|
|
val items = tabs.list.map { Item.Tab(it) }
|
|
val footer = Item.Footer(context.autoCloseInterval)
|
|
|
|
submitList(listOf(Item.Header) + items + listOf(Item.RecentlyClosed, footer))
|
|
}
|
|
|
|
override fun isTabSelected(tabs: Tabs, position: Int): Boolean = false
|
|
override fun onTabsChanged(position: Int, count: Int) = Unit
|
|
override fun onTabsInserted(position: Int, count: Int) = Unit
|
|
override fun onTabsMoved(fromPosition: Int, toPosition: Int) = Unit
|
|
override fun onTabsRemoved(position: Int, count: Int) = Unit
|
|
|
|
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: TabsTrayTab) : Item()
|
|
|
|
/**
|
|
* A button that leads to the Recently Closed section in History.
|
|
*/
|
|
object RecentlyClosed : Item()
|
|
|
|
/**
|
|
* A footer for the inactive tab section. This may be seen only
|
|
* when at least one inactive tab is present.
|
|
*/
|
|
data class Footer(val interval: AutoCloseInterval) : Item()
|
|
}
|
|
}
|