From bb3fd4eb168132baf05be5f7ecce63f67022e848 Mon Sep 17 00:00:00 2001 From: Tiger Oakes Date: Tue, 25 Aug 2020 14:48:47 -0700 Subject: [PATCH] For #8765: Use shared list widget in exceptions (#14113) * For #8765: Add resource for shared list widget * For #8765: Use shared list widget in exceptions --- .../fenix/exceptions/ExceptionsAdapter.kt | 3 +- .../ExceptionsListItemViewHolder.kt | 20 +++++++------ app/src/main/res/layout/site_list_item.xml | 9 ++++++ app/src/main/res/values-night/colors.xml | 1 + app/src/main/res/values/colors.xml | 4 +++ app/src/main/res/values/styles.xml | 4 +++ .../ExceptionsListItemViewHolderTest.kt | 29 +++++++------------ 7 files changed, 41 insertions(+), 29 deletions(-) create mode 100644 app/src/main/res/layout/site_list_item.xml diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt index b0050ecf8..3581ea988 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt @@ -11,6 +11,7 @@ import androidx.annotation.StringRes import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView +import mozilla.components.ui.widgets.WidgetSiteItemView import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder @@ -67,7 +68,7 @@ abstract class ExceptionsAdapter( ExceptionsHeaderViewHolder.LAYOUT_ID -> ExceptionsHeaderViewHolder(view, headerDescriptionResource) ExceptionsListItemViewHolder.LAYOUT_ID -> - ExceptionsListItemViewHolder(view, interactor) + ExceptionsListItemViewHolder(view as WidgetSiteItemView, interactor) else -> throw IllegalStateException() } } diff --git a/app/src/main/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolder.kt index d3225d34f..d403703e1 100644 --- a/app/src/main/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolder.kt @@ -4,39 +4,41 @@ package org.mozilla.fenix.exceptions.viewholders -import android.view.View -import kotlinx.android.synthetic.main.exception_item.* +import androidx.recyclerview.widget.RecyclerView import mozilla.components.browser.icons.BrowserIcons +import mozilla.components.ui.widgets.WidgetSiteItemView import org.mozilla.fenix.R import org.mozilla.fenix.exceptions.ExceptionsInteractor import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.loadIntoView -import org.mozilla.fenix.utils.view.ViewHolder /** * View holder for a single website that is exempted from Tracking Protection or Logins. */ class ExceptionsListItemViewHolder( - view: View, + private val view: WidgetSiteItemView, private val interactor: ExceptionsInteractor, private val icons: BrowserIcons = view.context.components.core.icons -) : ViewHolder(view) { +) : RecyclerView.ViewHolder(view) { private lateinit var item: T init { - delete_exception.setOnClickListener { + view.setSecondaryButton( + icon = R.drawable.ic_close, + contentDescription = R.string.history_delete_item + ) { interactor.onDeleteOne(item) } } fun bind(item: T, url: String) { this.item = item - webAddressView.text = url - icons.loadIntoView(favicon_image, url) + view.setText(label = url, caption = null) + icons.loadIntoView(view.iconView, url) } companion object { - const val LAYOUT_ID = R.layout.exception_item + const val LAYOUT_ID = R.layout.site_list_item } } diff --git a/app/src/main/res/layout/site_list_item.xml b/app/src/main/res/layout/site_list_item.xml new file mode 100644 index 000000000..0d218d525 --- /dev/null +++ b/app/src/main/res/layout/site_list_item.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml index 2ecd8fbb8..7258beac3 100644 --- a/app/src/main/res/values-night/colors.xml +++ b/app/src/main/res/values-night/colors.xml @@ -7,6 +7,7 @@ @color/primary_text_dark_theme @color/secondary_text_dark_theme @color/contrast_text_dark_theme + @color/caption_text_dark_theme @color/foundation_dark_theme @color/above_dark_theme @color/inset_dark_theme diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index a8938b5a2..5c9c19b04 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -16,6 +16,7 @@ #20123A @color/photonGrey50 @color/primary_text_dark_theme + @color/photonLightGrey90 #F9F9FB #E0E0E6 #FFF @@ -85,6 +86,7 @@ #FBFBFE #A7A2B7 @color/primary_text_dark_theme + @color/photonLightGrey70 #1C1B22 #32313C #32313C @@ -151,6 +153,7 @@ #FBFBFE #A7A2B7 @color/primary_text_private_theme + @color/photonLightGrey70 #261E4B @color/photonInk50 @color/photonInk50 @@ -209,6 +212,7 @@ @color/primary_text_light_theme @color/secondary_text_light_theme @color/contrast_text_light_theme + @color/caption_text_light_theme @color/foundation_light_theme @color/above_light_theme @color/inset_light_theme diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 05dc9426b..25302f51d 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -81,6 +81,8 @@ @color/search_suggestion_indicator_icon_bookmark_color_normal_theme + @color/primary_text_normal_theme + @color/caption_text_normal_theme @color/mozac_widget_favicon_background_normal_theme @color/mozac_widget_favicon_border_normal_theme @@ -221,6 +223,8 @@ @color/search_suggestion_indicator_icon_bookmark_color_dark_theme + @color/primary_text_private_theme + @color/caption_text_private_theme @color/mozac_widget_favicon_background_private_theme @color/mozac_widget_favicon_border_private_theme diff --git a/app/src/test/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolderTest.kt index e0cc1ed94..2779de9a5 100644 --- a/app/src/test/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolderTest.kt +++ b/app/src/test/java/org/mozilla/fenix/exceptions/viewholders/ExceptionsListItemViewHolderTest.kt @@ -5,9 +5,6 @@ package org.mozilla.fenix.exceptions.viewholders import android.view.View -import android.widget.ImageButton -import android.widget.ImageView -import android.widget.TextView import io.mockk.MockKAnnotations import io.mockk.Runs import io.mockk.every @@ -18,17 +15,14 @@ import io.mockk.slot import io.mockk.verify import mozilla.components.browser.icons.BrowserIcons import mozilla.components.browser.icons.IconRequest +import mozilla.components.ui.widgets.WidgetSiteItemView import org.junit.Before import org.junit.Test -import org.mozilla.fenix.R import org.mozilla.fenix.exceptions.ExceptionsInteractor class ExceptionsListItemViewHolderTest { - @MockK private lateinit var view: View - @MockK(relaxUnitFun = true) private lateinit var url: TextView - @MockK(relaxUnitFun = true) private lateinit var deleteButton: ImageButton - @MockK private lateinit var favicon: ImageView + @MockK(relaxed = true) private lateinit var view: WidgetSiteItemView @MockK private lateinit var icons: BrowserIcons @MockK private lateinit var interactor: ExceptionsInteractor @@ -36,37 +30,34 @@ class ExceptionsListItemViewHolderTest { fun setup() { MockKAnnotations.init(this) - every { view.findViewById(R.id.webAddressView) } returns url - every { view.findViewById(R.id.delete_exception) } returns deleteButton - every { view.findViewById(R.id.favicon_image) } returns favicon - every { icons.loadIntoView(favicon, any()) } returns mockk() + every { icons.loadIntoView(view.iconView, any()) } returns mockk() } @Test fun `sets url text and loads favicon - mozilla`() { ExceptionsListItemViewHolder(view, interactor, icons) .bind(Exception(), url = "mozilla.org") - verify { url.text = "mozilla.org" } - verify { icons.loadIntoView(favicon, IconRequest("mozilla.org")) } + verify { view.setText(label = "mozilla.org", caption = null) } + verify { icons.loadIntoView(view.iconView, IconRequest("mozilla.org")) } } @Test fun `sets url text and loads favicon - example`() { ExceptionsListItemViewHolder(view, interactor, icons) .bind(Exception(), url = "https://example.com/icon.svg") - verify { url.text = "https://example.com/icon.svg" } - verify { icons.loadIntoView(favicon, IconRequest("https://example.com/icon.svg")) } + verify { view.setText(label = "https://example.com/icon.svg", caption = null) } + verify { icons.loadIntoView(view.iconView, IconRequest("https://example.com/icon.svg")) } } @Test fun `delete button calls interactor`() { - val slot = slot() + val slot = slot<(View) -> Unit>() val exception = Exception() - every { deleteButton.setOnClickListener(capture(slot)) } just Runs + every { view.setSecondaryButton(any(), any(), capture(slot)) } just Runs ExceptionsListItemViewHolder(view, interactor, icons).bind(exception, url = "mozilla.org") every { interactor.onDeleteOne(exception) } just Runs - slot.captured.onClick(mockk()) + slot.captured.invoke(mockk()) verify { interactor.onDeleteOne(exception) } }