mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-17 15:26:23 +00:00
[fenix] For https://github.com/mozilla-mobile/fenix/issues/17542 - Removes flash on renaming top site and fixes title not being updated
This commit is contained in:
parent
cd40b8510e
commit
42c74bcd44
@ -703,7 +703,7 @@ private fun assertExistingTopSitesList() =
|
|||||||
|
|
||||||
private fun assertExistingTopSitesTabs(title: String) =
|
private fun assertExistingTopSitesTabs(title: String) =
|
||||||
onView(allOf(withId(R.id.top_sites_list)))
|
onView(allOf(withId(R.id.top_sites_list)))
|
||||||
.check(matches(hasItem(hasDescendant(withText(title)))))
|
.check(matches(hasDescendant(withText(title))))
|
||||||
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun assertNotExistingTopSitesList(title: String) =
|
private fun assertNotExistingTopSitesList(title: String) =
|
||||||
|
@ -43,7 +43,12 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
|
|||||||
ButtonTipViewHolder.LAYOUT_ID
|
ButtonTipViewHolder.LAYOUT_ID
|
||||||
)
|
)
|
||||||
|
|
||||||
data class TopSitePager(val topSites: List<TopSite>) : AdapterItem(TopSitePagerViewHolder.LAYOUT_ID) {
|
data class TopSitePagerPayload(
|
||||||
|
val changed: Set<Pair<Int, TopSite>>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class TopSitePager(val topSites: List<TopSite>) :
|
||||||
|
AdapterItem(TopSitePagerViewHolder.LAYOUT_ID) {
|
||||||
override fun sameAs(other: AdapterItem): Boolean {
|
override fun sameAs(other: AdapterItem): Boolean {
|
||||||
val newTopSites = (other as? TopSitePager) ?: return false
|
val newTopSites = (other as? TopSitePager) ?: return false
|
||||||
return newTopSites.topSites.size == this.topSites.size
|
return newTopSites.topSites.size == this.topSites.size
|
||||||
@ -56,6 +61,19 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
|
|||||||
val oldTopSites = this.topSites.asSequence()
|
val oldTopSites = this.topSites.asSequence()
|
||||||
return newSitesSequence.zip(oldTopSites).all { (new, old) -> new == old }
|
return newSitesSequence.zip(oldTopSites).all { (new, old) -> new == old }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getChangePayload(newItem: AdapterItem): Any? {
|
||||||
|
val newTopSites = (newItem as? TopSitePager) ?: return null
|
||||||
|
val oldTopSites = (this as? TopSitePager) ?: return null
|
||||||
|
|
||||||
|
val changed = mutableSetOf<Pair<Int, TopSite>>()
|
||||||
|
for ((index, item) in newTopSites.topSites.withIndex()) {
|
||||||
|
if (oldTopSites.topSites.getOrNull(index) != item) {
|
||||||
|
changed.add(Pair(index, item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (changed.isNotEmpty()) TopSitePagerPayload(changed) else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
object PrivateBrowsingDescription : AdapterItem(PrivateBrowsingDescriptionViewHolder.LAYOUT_ID)
|
||||||
@ -195,6 +213,25 @@ class SessionControlAdapter(
|
|||||||
|
|
||||||
override fun getItemViewType(position: Int) = getItem(position).viewType
|
override fun getItemViewType(position: Int) = getItem(position).viewType
|
||||||
|
|
||||||
|
override fun onBindViewHolder(
|
||||||
|
holder: RecyclerView.ViewHolder,
|
||||||
|
position: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) {
|
||||||
|
if (payloads.isNullOrEmpty()) {
|
||||||
|
onBindViewHolder(holder, position)
|
||||||
|
} else {
|
||||||
|
when (holder) {
|
||||||
|
is TopSitePagerViewHolder -> {
|
||||||
|
if (payloads[0] is AdapterItem.TopSitePagerPayload) {
|
||||||
|
val payload = payloads[0] as AdapterItem.TopSitePagerPayload
|
||||||
|
holder.update(payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ComplexMethod")
|
@SuppressWarnings("ComplexMethod")
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
|
@ -13,6 +13,7 @@ import mozilla.components.feature.top.sites.TopSite
|
|||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.AdapterItem
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSitesPagerAdapter
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.topsites.TopSitesPagerAdapter
|
||||||
|
|
||||||
@ -28,7 +29,11 @@ class TopSitePagerViewHolder(
|
|||||||
private val topSitesPageChangeCallback = object : ViewPager2.OnPageChangeCallback() {
|
private val topSitesPageChangeCallback = object : ViewPager2.OnPageChangeCallback() {
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
if (currentPage != position) {
|
if (currentPage != position) {
|
||||||
pageIndicator.context.components.analytics.metrics.track(Event.TopSiteSwipeCarousel(position))
|
pageIndicator.context.components.analytics.metrics.track(
|
||||||
|
Event.TopSiteSwipeCarousel(
|
||||||
|
position
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pageIndicator.setSelection(position)
|
pageIndicator.setSelection(position)
|
||||||
@ -43,6 +48,12 @@ class TopSitePagerViewHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update(payload: AdapterItem.TopSitePagerPayload) {
|
||||||
|
for (item in payload.changed) {
|
||||||
|
topSitesPagerAdapter.notifyItemChanged(currentPage, payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun bind(topSites: List<TopSite>) {
|
fun bind(topSites: List<TopSite>) {
|
||||||
val chunkedTopSites = topSites.chunked(TOP_SITES_PER_PAGE)
|
val chunkedTopSites = topSites.chunked(TOP_SITES_PER_PAGE)
|
||||||
topSitesPagerAdapter.submitList(chunkedTopSites)
|
topSitesPagerAdapter.submitList(chunkedTopSites)
|
||||||
|
@ -8,13 +8,14 @@ import android.view.LayoutInflater
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import kotlinx.android.synthetic.main.top_site_item.view.*
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
||||||
import org.mozilla.fenix.perf.StartupTimeline
|
import org.mozilla.fenix.perf.StartupTimeline
|
||||||
|
|
||||||
class TopSitesAdapter(
|
class TopSitesAdapter(
|
||||||
private val interactor: TopSiteInteractor
|
private val interactor: TopSiteInteractor
|
||||||
) : ListAdapter<TopSite, TopSiteItemViewHolder>(DiffCallback) {
|
) : ListAdapter<TopSite, TopSiteItemViewHolder>(TopSitesDiffCallback) {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteItemViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteItemViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context)
|
val view = LayoutInflater.from(parent.context)
|
||||||
.inflate(TopSiteItemViewHolder.LAYOUT_ID, parent, false)
|
.inflate(TopSiteItemViewHolder.LAYOUT_ID, parent, false)
|
||||||
@ -26,11 +27,39 @@ class TopSitesAdapter(
|
|||||||
holder.bind(getItem(position))
|
holder.bind(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DiffCallback : DiffUtil.ItemCallback<TopSite>() {
|
override fun onBindViewHolder(
|
||||||
override fun areItemsTheSame(oldItem: TopSite, newItem: TopSite) =
|
holder: TopSiteItemViewHolder,
|
||||||
oldItem.id == newItem.id || oldItem.title == newItem.title || oldItem.url == newItem.url
|
position: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) {
|
||||||
|
if (payloads.isNullOrEmpty()) {
|
||||||
|
onBindViewHolder(holder, position)
|
||||||
|
} else {
|
||||||
|
when (payloads[0]) {
|
||||||
|
is TopSite -> {
|
||||||
|
holder.bind((payloads[0] as TopSite))
|
||||||
|
}
|
||||||
|
is TopSitePayload -> {
|
||||||
|
holder.itemView.top_site_title.text = (payloads[0] as TopSitePayload).newTitle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TopSitePayload(
|
||||||
|
val newTitle: String?
|
||||||
|
)
|
||||||
|
|
||||||
|
internal object TopSitesDiffCallback : DiffUtil.ItemCallback<TopSite>() {
|
||||||
|
override fun areItemsTheSame(oldItem: TopSite, newItem: TopSite) = oldItem.id == newItem.id
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: TopSite, newItem: TopSite) =
|
override fun areContentsTheSame(oldItem: TopSite, newItem: TopSite) =
|
||||||
oldItem.id == newItem.id || oldItem.title == newItem.title || oldItem.url == newItem.url
|
oldItem.id == newItem.id && oldItem.title == newItem.title && oldItem.url == newItem.url
|
||||||
|
|
||||||
|
override fun getChangePayload(oldItem: TopSite, newItem: TopSite): Any? {
|
||||||
|
return if (oldItem.id == newItem.id && oldItem.url == newItem.url && oldItem.title != newItem.title) {
|
||||||
|
TopSitePayload(newItem.title)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,13 @@ import androidx.recyclerview.widget.DiffUtil
|
|||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
import kotlinx.android.synthetic.main.component_top_sites.view.*
|
import kotlinx.android.synthetic.main.component_top_sites.view.*
|
||||||
import mozilla.components.feature.top.sites.TopSite
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.AdapterItem
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
import org.mozilla.fenix.home.sessioncontrol.TopSiteInteractor
|
||||||
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSiteViewHolder
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.TopSiteViewHolder
|
||||||
|
|
||||||
class TopSitesPagerAdapter(
|
class TopSitesPagerAdapter(
|
||||||
private val interactor: TopSiteInteractor
|
private val interactor: TopSiteInteractor
|
||||||
) : ListAdapter<List<TopSite>, TopSiteViewHolder>(DiffCallback) {
|
) : ListAdapter<List<TopSite>, TopSiteViewHolder>(TopSiteListDiffCallback) {
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TopSiteViewHolder {
|
||||||
val view = LayoutInflater.from(parent.context)
|
val view = LayoutInflater.from(parent.context)
|
||||||
@ -23,12 +24,30 @@ class TopSitesPagerAdapter(
|
|||||||
return TopSiteViewHolder(view, interactor)
|
return TopSiteViewHolder(view, interactor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(
|
||||||
|
holder: TopSiteViewHolder,
|
||||||
|
position: Int,
|
||||||
|
payloads: MutableList<Any>
|
||||||
|
) {
|
||||||
|
if (payloads.isNullOrEmpty()) {
|
||||||
|
onBindViewHolder(holder, position)
|
||||||
|
} else {
|
||||||
|
if (payloads[0] is AdapterItem.TopSitePagerPayload) {
|
||||||
|
val adapter = holder.itemView.top_sites_list.adapter as TopSitesAdapter
|
||||||
|
val payload = payloads[0] as AdapterItem.TopSitePagerPayload
|
||||||
|
for (item in payload.changed) {
|
||||||
|
adapter.notifyItemChanged(item.first, item.second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: TopSiteViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: TopSiteViewHolder, position: Int) {
|
||||||
val adapter = holder.itemView.top_sites_list.adapter as TopSitesAdapter
|
val adapter = holder.itemView.top_sites_list.adapter as TopSitesAdapter
|
||||||
adapter.submitList(getItem(position))
|
adapter.submitList(getItem(position))
|
||||||
}
|
}
|
||||||
|
|
||||||
private object DiffCallback : DiffUtil.ItemCallback<List<TopSite>>() {
|
internal object TopSiteListDiffCallback : DiffUtil.ItemCallback<List<TopSite>>() {
|
||||||
override fun areItemsTheSame(oldItem: List<TopSite>, newItem: List<TopSite>): Boolean {
|
override fun areItemsTheSame(oldItem: List<TopSite>, newItem: List<TopSite>): Boolean {
|
||||||
return oldItem.size == newItem.size
|
return oldItem.size == newItem.size
|
||||||
}
|
}
|
||||||
@ -36,5 +55,15 @@ class TopSitesPagerAdapter(
|
|||||||
override fun areContentsTheSame(oldItem: List<TopSite>, newItem: List<TopSite>): Boolean {
|
override fun areContentsTheSame(oldItem: List<TopSite>, newItem: List<TopSite>): Boolean {
|
||||||
return newItem.zip(oldItem).all { (new, old) -> new == old }
|
return newItem.zip(oldItem).all { (new, old) -> new == old }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getChangePayload(oldItem: List<TopSite>, newItem: List<TopSite>): Any? {
|
||||||
|
val changed = mutableSetOf<Pair<Int, TopSite>>()
|
||||||
|
for ((index, item) in newItem.withIndex()) {
|
||||||
|
if (oldItem.getOrNull(index) != item) {
|
||||||
|
changed.add(Pair(index, item))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (changed.isNotEmpty()) AdapterItem.TopSitePagerPayload(changed) else null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
/* 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.topsites
|
||||||
|
|
||||||
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class TopSitesAdapterTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testDiffCallback() {
|
||||||
|
val topSite = TopSite(
|
||||||
|
id = 1L,
|
||||||
|
title = "Title1",
|
||||||
|
url = "https://mozilla.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
val topSite2 = TopSite(
|
||||||
|
id = 1L,
|
||||||
|
title = "Title2",
|
||||||
|
url = "https://mozilla.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
TopSitesAdapter.TopSitesDiffCallback.getChangePayload(topSite, topSite2),
|
||||||
|
TopSitesAdapter.TopSitePayload("Title2")
|
||||||
|
)
|
||||||
|
|
||||||
|
val topSite3 = TopSite(
|
||||||
|
id = 2L,
|
||||||
|
title = "Title2",
|
||||||
|
url = "https://firefox.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
TopSitesAdapter.TopSitesDiffCallback.getChangePayload(topSite, topSite3),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
/* 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.topsites
|
||||||
|
|
||||||
|
import mozilla.components.feature.top.sites.TopSite
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.AdapterItem
|
||||||
|
|
||||||
|
class TopSitesPagerAdapterTest {
|
||||||
|
@Test
|
||||||
|
fun testDiffCallback() {
|
||||||
|
val topSite = TopSite(
|
||||||
|
id = 1L,
|
||||||
|
title = "Title1",
|
||||||
|
url = "https://mozilla.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
val topSite2 = TopSite(
|
||||||
|
id = 2L,
|
||||||
|
title = "Title2",
|
||||||
|
url = "https://mozilla.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
val topSite3 = TopSite(
|
||||||
|
id = 3L,
|
||||||
|
title = "Title2",
|
||||||
|
url = "https://firefox.org",
|
||||||
|
null,
|
||||||
|
TopSite.Type.DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
TopSitesPagerAdapter.TopSiteListDiffCallback.getChangePayload(
|
||||||
|
listOf(topSite, topSite3),
|
||||||
|
listOf(topSite, topSite2)
|
||||||
|
),
|
||||||
|
AdapterItem.TopSitePagerPayload(setOf(Pair(1, topSite2)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user