Use a ListAdapter for SessionControl
parent
2fd91daa5b
commit
207a8d6772
|
@ -205,8 +205,10 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
BrowsingModeManager.Mode.Private -> BrowsingModeManager.Mode.Normal
|
BrowsingModeManager.Mode.Private -> BrowsingModeManager.Mode.Normal
|
||||||
}
|
}
|
||||||
|
|
||||||
val mode = if (newMode == BrowsingModeManager.Mode.Private) Mode.Private else Mode.Normal
|
if (onboarding.userHasBeenOnboarded()) {
|
||||||
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.ModeChange(mode))
|
val mode = if (newMode == BrowsingModeManager.Mode.Private) Mode.Private else Mode.Normal
|
||||||
|
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.ModeChange(mode))
|
||||||
|
}
|
||||||
|
|
||||||
browsingModeManager.mode = newMode
|
browsingModeManager.mode = newMode
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,22 @@ package org.mozilla.fenix.home.sessioncontrol
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.reactivex.Observer
|
import io.reactivex.Observer
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.SaveTabGroupViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoTabMessageViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionMessageViewHolder
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.SaveTabGroupViewHolder
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFirefoxAccountViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFirefoxAccountViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
|
||||||
|
@ -28,69 +32,69 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSe
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
|
||||||
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||||
import java.lang.IllegalStateException
|
|
||||||
|
|
||||||
sealed class AdapterItem {
|
sealed class AdapterItem(@LayoutRes val viewType: Int) {
|
||||||
data class TabHeader(val isPrivate: Boolean, val hasTabs: Boolean) : AdapterItem()
|
data class TabHeader(val isPrivate: Boolean, val hasTabs: Boolean) : AdapterItem(TabHeaderViewHolder.LAYOUT_ID)
|
||||||
object NoTabMessage : AdapterItem()
|
data class TabItem(val tab: Tab) : AdapterItem(TabViewHolder.LAYOUT_ID) {
|
||||||
data class TabItem(val tab: Tab) : AdapterItem()
|
override fun sameAs(other: AdapterItem) = other is TabItem && tab.sessionId == other.tab.sessionId
|
||||||
object SaveTabGroup : AdapterItem()
|
}
|
||||||
|
object SaveTabGroup : AdapterItem(SaveTabGroupViewHolder.LAYOUT_ID)
|
||||||
|
|
||||||
object PrivateBrowsingDescription : AdapterItem()
|
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
||||||
|
data class NoContentMessage(
|
||||||
|
@DrawableRes val icon: Int,
|
||||||
|
@StringRes val header: Int,
|
||||||
|
@StringRes val description: Int
|
||||||
|
) : AdapterItem(NoContentMessageViewHolder.LAYOUT_ID)
|
||||||
|
|
||||||
object CollectionHeader : AdapterItem()
|
object CollectionHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID)
|
||||||
object NoCollectionMessage : AdapterItem()
|
data class CollectionItem(
|
||||||
data class CollectionItem(val collection: TabCollection) : AdapterItem()
|
val collection: TabCollection,
|
||||||
|
val expanded: Boolean
|
||||||
|
) : AdapterItem(CollectionViewHolder.LAYOUT_ID) {
|
||||||
|
override fun sameAs(other: AdapterItem) = other is CollectionItem && collection.id == other.collection.id
|
||||||
|
}
|
||||||
data class TabInCollectionItem(
|
data class TabInCollectionItem(
|
||||||
val collection: TabCollection,
|
val collection: TabCollection,
|
||||||
val tab: ComponentTab,
|
val tab: ComponentTab,
|
||||||
val isLastTab: Boolean
|
val isLastTab: Boolean
|
||||||
) : AdapterItem()
|
) : AdapterItem(TabInCollectionViewHolder.LAYOUT_ID) {
|
||||||
|
override fun sameAs(other: AdapterItem) = other is TabInCollectionItem && tab.id == other.tab.id
|
||||||
|
}
|
||||||
|
|
||||||
object OnboardingHeader : AdapterItem()
|
object OnboardingHeader : AdapterItem(OnboardingHeaderViewHolder.LAYOUT_ID)
|
||||||
data class OnboardingSectionHeader(val labelBuilder: (Context) -> String) : AdapterItem()
|
data class OnboardingSectionHeader(
|
||||||
data class OnboardingFirefoxAccount(val state: OnboardingState) : AdapterItem()
|
val labelBuilder: (Context) -> String
|
||||||
object OnboardingThemePicker : AdapterItem()
|
) : AdapterItem(OnboardingSectionHeaderViewHolder.LAYOUT_ID) {
|
||||||
object OnboardingTrackingProtection : AdapterItem()
|
override fun sameAs(other: AdapterItem) = other is OnboardingSectionHeader && labelBuilder == other.labelBuilder
|
||||||
object OnboardingPrivateBrowsing : AdapterItem()
|
}
|
||||||
object OnboardingPrivacyNotice : AdapterItem()
|
data class OnboardingFirefoxAccount(
|
||||||
object OnboardingFinish : AdapterItem()
|
val state: OnboardingState
|
||||||
|
) : AdapterItem(OnboardingFirefoxAccountViewHolder.LAYOUT_ID)
|
||||||
|
object OnboardingThemePicker : AdapterItem(OnboardingThemePickerViewHolder.LAYOUT_ID)
|
||||||
|
object OnboardingTrackingProtection : AdapterItem(OnboardingTrackingProtectionViewHolder.LAYOUT_ID)
|
||||||
|
object OnboardingPrivateBrowsing : AdapterItem(OnboardingPrivateBrowsingViewHolder.LAYOUT_ID)
|
||||||
|
object OnboardingPrivacyNotice : AdapterItem(OnboardingPrivacyNoticeViewHolder.LAYOUT_ID)
|
||||||
|
object OnboardingFinish : AdapterItem(OnboardingFinishViewHolder.LAYOUT_ID)
|
||||||
|
|
||||||
val viewType: Int
|
/**
|
||||||
get() = when (this) {
|
* True if this item represents the same value as other. Used by [AdapterItemDiffCallback].
|
||||||
is TabHeader -> TabHeaderViewHolder.LAYOUT_ID
|
*/
|
||||||
NoTabMessage -> NoTabMessageViewHolder.LAYOUT_ID
|
open fun sameAs(other: AdapterItem) = this::class == other::class
|
||||||
is TabItem -> TabViewHolder.LAYOUT_ID
|
}
|
||||||
SaveTabGroup -> SaveTabGroupViewHolder.LAYOUT_ID
|
|
||||||
PrivateBrowsingDescription -> PrivateBrowsingDescriptionViewHolder.LAYOUT_ID
|
class AdapterItemDiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
|
||||||
CollectionHeader -> CollectionHeaderViewHolder.LAYOUT_ID
|
override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) = oldItem.sameAs(newItem)
|
||||||
NoCollectionMessage -> NoCollectionMessageViewHolder.LAYOUT_ID
|
|
||||||
is CollectionItem -> CollectionViewHolder.LAYOUT_ID
|
@Suppress("DiffUtilEquals")
|
||||||
is TabInCollectionItem -> TabInCollectionViewHolder.LAYOUT_ID
|
override fun areContentsTheSame(oldItem: AdapterItem, newItem: AdapterItem) = oldItem == newItem
|
||||||
OnboardingHeader -> OnboardingHeaderViewHolder.LAYOUT_ID
|
|
||||||
is OnboardingSectionHeader -> OnboardingSectionHeaderViewHolder.LAYOUT_ID
|
|
||||||
is OnboardingFirefoxAccount -> OnboardingFirefoxAccountViewHolder.LAYOUT_ID
|
|
||||||
OnboardingThemePicker -> OnboardingThemePickerViewHolder.LAYOUT_ID
|
|
||||||
OnboardingTrackingProtection -> OnboardingTrackingProtectionViewHolder.LAYOUT_ID
|
|
||||||
OnboardingPrivateBrowsing -> OnboardingPrivateBrowsingViewHolder.LAYOUT_ID
|
|
||||||
OnboardingPrivacyNotice -> OnboardingPrivacyNoticeViewHolder.LAYOUT_ID
|
|
||||||
OnboardingFinish -> OnboardingFinishViewHolder.LAYOUT_ID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SessionControlAdapter(
|
class SessionControlAdapter(
|
||||||
private val actionEmitter: Observer<SessionControlAction>
|
private val actionEmitter: Observer<SessionControlAction>
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
|
||||||
|
|
||||||
private var items: List<AdapterItem> = listOf()
|
|
||||||
private lateinit var job: Job
|
private lateinit var job: Job
|
||||||
private lateinit var expandedCollections: Set<Long>
|
|
||||||
|
|
||||||
fun reloadData(items: List<AdapterItem>, expandedCollections: Set<Long>) {
|
|
||||||
this.items = items
|
|
||||||
this.expandedCollections = expandedCollections
|
|
||||||
notifyDataSetChanged()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method triggers the ComplexMethod lint error when in fact it's quite simple.
|
// This method triggers the ComplexMethod lint error when in fact it's quite simple.
|
||||||
@SuppressWarnings("ComplexMethod")
|
@SuppressWarnings("ComplexMethod")
|
||||||
|
@ -98,12 +102,11 @@ class SessionControlAdapter(
|
||||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, actionEmitter)
|
TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, actionEmitter)
|
||||||
NoTabMessageViewHolder.LAYOUT_ID -> NoTabMessageViewHolder(view)
|
|
||||||
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, job)
|
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, job)
|
||||||
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, actionEmitter)
|
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, actionEmitter)
|
||||||
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, actionEmitter)
|
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, actionEmitter)
|
||||||
|
NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view)
|
||||||
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
|
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
|
||||||
NoCollectionMessageViewHolder.LAYOUT_ID -> NoCollectionMessageViewHolder(view)
|
|
||||||
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, job)
|
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, job)
|
||||||
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, job)
|
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, job)
|
||||||
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
|
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
|
||||||
|
@ -128,32 +131,35 @@ class SessionControlAdapter(
|
||||||
job.cancel()
|
job.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = items[position].viewType
|
override fun getItemViewType(position: Int) = getItem(position).viewType
|
||||||
|
|
||||||
override fun getItemCount(): Int = items.size
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
val item = getItem(position)
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is TabHeaderViewHolder -> {
|
is TabHeaderViewHolder -> {
|
||||||
val tabHeader = items[position] as AdapterItem.TabHeader
|
val tabHeader = item as AdapterItem.TabHeader
|
||||||
holder.bind(tabHeader.isPrivate, tabHeader.hasTabs)
|
holder.bind(tabHeader.isPrivate, tabHeader.hasTabs)
|
||||||
}
|
}
|
||||||
is TabViewHolder -> holder.bindSession(
|
is TabViewHolder -> holder.bindSession(
|
||||||
(items[position] as AdapterItem.TabItem).tab
|
(item as AdapterItem.TabItem).tab
|
||||||
)
|
)
|
||||||
|
is NoContentMessageViewHolder -> {
|
||||||
|
val (icon, header, description) = item as AdapterItem.NoContentMessage
|
||||||
|
holder.bind(icon, header, description)
|
||||||
|
}
|
||||||
is CollectionViewHolder -> {
|
is CollectionViewHolder -> {
|
||||||
val collection = (items[position] as AdapterItem.CollectionItem).collection
|
val (collection, expanded) = item as AdapterItem.CollectionItem
|
||||||
holder.bindSession(collection, expandedCollections.contains(collection.id))
|
holder.bindSession(collection, expanded)
|
||||||
}
|
}
|
||||||
is TabInCollectionViewHolder -> {
|
is TabInCollectionViewHolder -> {
|
||||||
val item = items[position] as AdapterItem.TabInCollectionItem
|
val (collection, tab, isLastTab) = item as AdapterItem.TabInCollectionItem
|
||||||
holder.bindSession(item.collection, item.tab, item.isLastTab)
|
holder.bindSession(collection, tab, isLastTab)
|
||||||
}
|
}
|
||||||
is OnboardingSectionHeaderViewHolder -> holder.bind(
|
is OnboardingSectionHeaderViewHolder -> holder.bind(
|
||||||
(items[position] as AdapterItem.OnboardingSectionHeader).labelBuilder
|
(item as AdapterItem.OnboardingSectionHeader).labelBuilder
|
||||||
)
|
)
|
||||||
is OnboardingFirefoxAccountViewHolder -> holder.bind(
|
is OnboardingFirefoxAccountViewHolder -> holder.bind(
|
||||||
(items[position] as AdapterItem.OnboardingFirefoxAccount).state == OnboardingState.AutoSignedIn
|
(item as AdapterItem.OnboardingFirefoxAccount).state == OnboardingState.AutoSignedIn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ package org.mozilla.fenix.home.sessioncontrol
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
|
@ -13,7 +14,18 @@ import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
|
||||||
|
val noTabMessage = AdapterItem.NoContentMessage(
|
||||||
|
R.drawable.ic_tabs,
|
||||||
|
R.string.no_open_tabs_header,
|
||||||
|
R.string.no_open_tabs_description
|
||||||
|
)
|
||||||
|
|
||||||
|
val noCollectionMessage = AdapterItem.NoContentMessage(
|
||||||
|
R.drawable.ic_tab_collection,
|
||||||
|
R.string.no_collections_header,
|
||||||
|
R.string.no_collections_description
|
||||||
|
)
|
||||||
|
|
||||||
private fun normalModeAdapterItems(
|
private fun normalModeAdapterItems(
|
||||||
tabs: List<Tab>,
|
tabs: List<Tab>,
|
||||||
|
@ -27,21 +39,23 @@ private fun normalModeAdapterItems(
|
||||||
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
|
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
|
||||||
items.add(AdapterItem.SaveTabGroup)
|
items.add(AdapterItem.SaveTabGroup)
|
||||||
} else {
|
} else {
|
||||||
items.add(AdapterItem.NoTabMessage)
|
items.add(noTabMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
items.add(AdapterItem.CollectionHeader)
|
items.add(AdapterItem.CollectionHeader)
|
||||||
if (collections.isNotEmpty()) {
|
if (collections.isNotEmpty()) {
|
||||||
|
|
||||||
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
|
// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
|
||||||
collections.map(AdapterItem::CollectionItem).forEach {
|
collections.map {
|
||||||
|
AdapterItem.CollectionItem(it, expandedCollections.contains(it.id))
|
||||||
|
}.forEach {
|
||||||
items.add(it)
|
items.add(it)
|
||||||
if (it.collection.isExpanded(expandedCollections)) {
|
if (it.expanded) {
|
||||||
items.addAll(collectionTabItems(it.collection))
|
items.addAll(collectionTabItems(it.collection))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
items.add(AdapterItem.NoCollectionMessage)
|
items.add(noCollectionMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
return items
|
return items
|
||||||
|
@ -104,10 +118,6 @@ private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapI
|
||||||
AdapterItem.TabInCollectionItem(collection, tab, index == collection.tabs.lastIndex)
|
AdapterItem.TabInCollectionItem(collection, tab, index == collection.tabs.lastIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun TabCollection.isExpanded(expandedCollections: Set<Long>): Boolean {
|
|
||||||
return expandedCollections.contains(this.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SessionControlUIView(
|
class SessionControlUIView(
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
actionEmitter: Observer<SessionControlAction>,
|
actionEmitter: Observer<SessionControlAction>,
|
||||||
|
@ -129,6 +139,7 @@ class SessionControlUIView(
|
||||||
view.apply {
|
view.apply {
|
||||||
adapter = sessionControlAdapter
|
adapter = sessionControlAdapter
|
||||||
layoutManager = LinearLayoutManager(container.context)
|
layoutManager = LinearLayoutManager(container.context)
|
||||||
|
itemAnimator = null // TODO #2785: Remove this line
|
||||||
val itemTouchHelper =
|
val itemTouchHelper =
|
||||||
ItemTouchHelper(
|
ItemTouchHelper(
|
||||||
SwipeToDeleteCallback(
|
SwipeToDeleteCallback(
|
||||||
|
@ -140,7 +151,7 @@ class SessionControlUIView(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateView() = Consumer<SessionControlState> {
|
override fun updateView() = Consumer<SessionControlState> {
|
||||||
sessionControlAdapter.reloadData(it.toAdapterList(), it.expandedCollections)
|
sessionControlAdapter.submitList(it.toAdapterList())
|
||||||
actionEmitter.onNext(SessionControlAction.ReloadData)
|
actionEmitter.onNext(SessionControlAction.ReloadData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,11 +84,7 @@ class CollectionViewHolder(
|
||||||
private fun updateCollectionUI() {
|
private fun updateCollectionUI() {
|
||||||
view.collection_title.text = collection.title
|
view.collection_title.text = collection.title
|
||||||
|
|
||||||
var hostNameList = listOf<String>()
|
val hostNameList = collection.tabs.map { it.url.urlToTrimmedHost().capitalize() }
|
||||||
|
|
||||||
collection.tabs.forEach {
|
|
||||||
hostNameList += it.url.urlToTrimmedHost().capitalize()
|
|
||||||
}
|
|
||||||
|
|
||||||
var tabsDisplayed = 0
|
var tabsDisplayed = 0
|
||||||
val tabTitlesList = hostNameList.joinToString(", ") {
|
val tabTitlesList = hostNameList.joinToString(", ") {
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
/* 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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
|
|
||||||
class NoCollectionMessageViewHolder(
|
|
||||||
view: View
|
|
||||||
) : RecyclerView.ViewHolder(view) {
|
|
||||||
companion object {
|
|
||||||
const val LAYOUT_ID = R.layout.no_collection_message
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/* 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.home.sessioncontrol.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kotlinx.android.synthetic.main.no_content_message.view.*
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class NoContentMessageViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
|
||||||
|
|
||||||
|
fun bind(
|
||||||
|
@DrawableRes icon: Int,
|
||||||
|
@StringRes header: Int,
|
||||||
|
@StringRes description: Int
|
||||||
|
) {
|
||||||
|
with(view.context) {
|
||||||
|
view.no_content_header.setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, icon, 0)
|
||||||
|
view.no_content_header.text = getString(header)
|
||||||
|
view.no_content_description.text = getString(description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LAYOUT_ID = R.layout.no_content_message
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,17 +0,0 @@
|
||||||
/* 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.home.sessioncontrol.viewholders
|
|
||||||
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
|
|
||||||
class NoTabMessageViewHolder(
|
|
||||||
view: View
|
|
||||||
) : RecyclerView.ViewHolder(view) {
|
|
||||||
companion object {
|
|
||||||
const val LAYOUT_ID = R.layout.no_tab_message
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/no_tabs_wrapper"
|
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/no_content_wrapper"
|
||||||
android:background="@drawable/empty_session_control_background"
|
android:background="@drawable/empty_session_control_background"
|
||||||
android:layout_marginBottom="12dp"
|
android:layout_marginBottom="12dp"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
|
@ -13,23 +13,23 @@
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/no_collection_header"
|
android:id="@+id/no_content_header"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:drawableEnd="@drawable/ic_tab_collection"
|
|
||||||
android:drawableTint="?primaryText"
|
android:drawableTint="?primaryText"
|
||||||
android:drawablePadding="8dp"
|
android:drawablePadding="8dp"
|
||||||
android:text="@string/no_collections_header"
|
tools:text="@tools:sample/lorem"
|
||||||
android:textAppearance="@style/HeaderTextStyle"
|
android:textAppearance="@style/HeaderTextStyle"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/no_collection_description"
|
android:id="@+id/no_content_description"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="4dp"
|
android:layout_marginTop="4dp"
|
||||||
android:text="@string/no_collections_description"
|
tools:text="@tools:sample/lorem"
|
||||||
android:textColor="?primaryText"
|
android:textColor="?primaryText"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp"
|
||||||
android:textStyle="normal" />
|
android:textStyle="normal" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
|
@ -1,35 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!-- 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/. -->
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:id="@+id/no_tabs_wrapper"
|
|
||||||
android:background="@drawable/empty_session_control_background"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_tab_header"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:drawableEnd="@drawable/ic_tabs"
|
|
||||||
android:drawablePadding="8dp"
|
|
||||||
android:text="@string/no_open_tabs_header"
|
|
||||||
android:textAppearance="@style/HeaderTextStyle"
|
|
||||||
android:textSize="16sp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_tab_description"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:text="@string/no_open_tabs_description"
|
|
||||||
android:textColor="?primaryText"
|
|
||||||
android:textSize="14sp"
|
|
||||||
android:textStyle="normal" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -4,13 +4,13 @@
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/onboarding_header"
|
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/onboarding_header"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginBottom="16dp">
|
android:layout_marginBottom="16dp">
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/section_header_text"
|
android:id="@+id/section_header_text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/HeaderTextStyle" />
|
android:textAppearance="@style/HeaderTextStyle" tools:text="@tools:sample/lorem"/>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
Loading…
Reference in New Issue