Loading app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt +7 −7 Original line number Diff line number Diff line Loading @@ -14,19 +14,13 @@ import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder sealed class AdapterItem { object DeleteButton : AdapterItem() object Header : AdapterItem() data class Item(val item: TrackingProtectionException) : AdapterItem() } /** * Adapter for a list of sites that are exempted from Tracking Protection, * along with controls to remove the exception. */ class ExceptionsAdapter( private val interactor: ExceptionsInteractor ) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(DiffCallback) { ) : ListAdapter<ExceptionsAdapter.AdapterItem, RecyclerView.ViewHolder>(DiffCallback) { /** * Change the list of items that are displayed. Loading Loading @@ -67,6 +61,12 @@ class ExceptionsAdapter( } } sealed class AdapterItem { object DeleteButton : AdapterItem() object Header : AdapterItem() data class Item(val item: TrackingProtectionException) : AdapterItem() } private object DiffCallback : DiffUtil.ItemCallback<AdapterItem>() { override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) = areContentsTheSame(oldItem, newItem) Loading app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt +2 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import org.mozilla.fenix.settings.SupportUtils * along with controls to remove the exception. */ class ExceptionsFragment : Fragment() { private lateinit var exceptionsStore: ExceptionsFragmentStore private lateinit var exceptionsView: ExceptionsView private lateinit var exceptionsInteractor: ExceptionsInteractor Loading @@ -48,7 +49,7 @@ class ExceptionsFragment : Fragment() { exceptionsStore = StoreProvider.get(this) { ExceptionsFragmentStore( ExceptionsFragmentState( items = listOf() items = emptyList() ) ) } Loading @@ -61,7 +62,6 @@ class ExceptionsFragment : Fragment() { @ExperimentalCoroutinesApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) consumeFrom(exceptionsStore) { exceptionsView.update(it) } Loading app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsView.kt +17 −16 Original line number Diff line number Diff line Loading @@ -4,16 +4,16 @@ package org.mozilla.fenix.exceptions import android.text.SpannableString import android.text.method.LinkMovementMethod import android.text.style.UnderlineSpan import android.view.LayoutInflater import android.view.ViewGroup import android.widget.FrameLayout import androidx.core.text.toSpannable import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.component_exceptions.view.* import kotlinx.android.synthetic.main.component_exceptions.* import mozilla.components.concept.engine.content.blocking.TrackingProtectionException import org.mozilla.fenix.R Loading Loading @@ -42,35 +42,36 @@ interface ExceptionsViewInteractor { * View that contains and configures the Exceptions List */ class ExceptionsView( override val containerView: ViewGroup, val interactor: ExceptionsInteractor container: ViewGroup, interactor: ExceptionsInteractor ) : LayoutContainer { val view: FrameLayout = LayoutInflater.from(containerView.context) .inflate(R.layout.component_exceptions, containerView, true) override val containerView: FrameLayout = LayoutInflater.from(container.context) .inflate(R.layout.component_exceptions, container, true) .findViewById(R.id.exceptions_wrapper) private val exceptionsAdapter = ExceptionsAdapter(interactor) init { view.exceptions_list.apply { exceptions_list.apply { adapter = exceptionsAdapter layoutManager = LinearLayoutManager(containerView.context) layoutManager = LinearLayoutManager(container.context) } val learnMoreText = view.exceptions_learn_more.text.toString() val textWithLink = SpannableString(learnMoreText).apply { with(exceptions_learn_more) { val learnMoreText = text text = learnMoreText.toSpannable().apply { setSpan(UnderlineSpan(), 0, learnMoreText.length, 0) } with(view.exceptions_learn_more) { movementMethod = LinkMovementMethod.getInstance() text = textWithLink setOnClickListener { interactor.onLearnMore() } } } fun update(state: ExceptionsFragmentState) { view.exceptions_empty_view.isVisible = state.items.isEmpty() view.exceptions_list.isVisible = state.items.isNotEmpty() exceptions_empty_view.isVisible = state.items.isEmpty() exceptions_list.isVisible = state.items.isNotEmpty() exceptionsAdapter.updateData(state.items) } } app/src/test/java/org/mozilla/fenix/exceptions/ExceptionsAdapterTest.kt 0 → 100644 +42 −0 Original line number Diff line number Diff line /* 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.exceptions import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runBlockingTest import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class ExceptionsAdapterTest { private lateinit var interactor: ExceptionsInteractor private lateinit var adapter: ExceptionsAdapter @Before fun setup() { interactor = mockk() adapter = ExceptionsAdapter(interactor) } @Test fun `binds header and delete button with other adapter items`() = runBlockingTest { adapter.updateData(listOf(mockk(), mockk())) assertEquals(4, adapter.itemCount) assertEquals(ExceptionsHeaderViewHolder.LAYOUT_ID, adapter.getItemViewType(0)) assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(1)) assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(2)) assertEquals(ExceptionsDeleteButtonViewHolder.LAYOUT_ID, adapter.getItemViewType(3)) } } app/src/test/java/org/mozilla/fenix/exceptions/ExceptionsViewTest.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* 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.exceptions import android.text.Spannable import android.text.method.LinkMovementMethod import android.view.ViewGroup import android.widget.FrameLayout import androidx.core.view.isVisible import io.mockk.Runs import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.mockkConstructor import io.mockk.unmockkConstructor import io.mockk.verify import kotlinx.android.synthetic.main.component_exceptions.* import mozilla.components.concept.engine.content.blocking.TrackingProtectionException import mozilla.components.support.test.robolectric.testContext import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class ExceptionsViewTest { private lateinit var container: ViewGroup private lateinit var interactor: ExceptionsInteractor private lateinit var exceptionsView: ExceptionsView @Before fun setup() { mockkConstructor(ExceptionsAdapter::class) container = FrameLayout(testContext) interactor = mockk() exceptionsView = ExceptionsView(container, interactor) every { anyConstructed<ExceptionsAdapter>().updateData(any()) } just Runs } @After fun teardown() { unmockkConstructor(ExceptionsAdapter::class) } @Test fun `binds exception text`() { assertTrue(exceptionsView.exceptions_learn_more.movementMethod is LinkMovementMethod) assertTrue(exceptionsView.exceptions_learn_more.text is Spannable) assertEquals("Learn more", exceptionsView.exceptions_learn_more.text.toString()) every { interactor.onLearnMore() } just Runs exceptionsView.exceptions_learn_more.performClick() verify { interactor.onLearnMore() } } @Test fun `binds empty list to adapter`() { exceptionsView.update(ExceptionsFragmentState(emptyList())) assertTrue(exceptionsView.exceptions_empty_view.isVisible) assertFalse(exceptionsView.exceptions_list.isVisible) verify { anyConstructed<ExceptionsAdapter>().updateData(emptyList()) } } @Test fun `binds list with items to adapter`() { val items = listOf<TrackingProtectionException>(mockk(), mockk()) exceptionsView.update(ExceptionsFragmentState(items)) assertFalse(exceptionsView.exceptions_empty_view.isVisible) assertTrue(exceptionsView.exceptions_list.isVisible) verify { anyConstructed<ExceptionsAdapter>().updateData(items) } } } Loading
app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsAdapter.kt +7 −7 Original line number Diff line number Diff line Loading @@ -14,19 +14,13 @@ import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder sealed class AdapterItem { object DeleteButton : AdapterItem() object Header : AdapterItem() data class Item(val item: TrackingProtectionException) : AdapterItem() } /** * Adapter for a list of sites that are exempted from Tracking Protection, * along with controls to remove the exception. */ class ExceptionsAdapter( private val interactor: ExceptionsInteractor ) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(DiffCallback) { ) : ListAdapter<ExceptionsAdapter.AdapterItem, RecyclerView.ViewHolder>(DiffCallback) { /** * Change the list of items that are displayed. Loading Loading @@ -67,6 +61,12 @@ class ExceptionsAdapter( } } sealed class AdapterItem { object DeleteButton : AdapterItem() object Header : AdapterItem() data class Item(val item: TrackingProtectionException) : AdapterItem() } private object DiffCallback : DiffUtil.ItemCallback<AdapterItem>() { override fun areItemsTheSame(oldItem: AdapterItem, newItem: AdapterItem) = areContentsTheSame(oldItem, newItem) Loading
app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsFragment.kt +2 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import org.mozilla.fenix.settings.SupportUtils * along with controls to remove the exception. */ class ExceptionsFragment : Fragment() { private lateinit var exceptionsStore: ExceptionsFragmentStore private lateinit var exceptionsView: ExceptionsView private lateinit var exceptionsInteractor: ExceptionsInteractor Loading @@ -48,7 +49,7 @@ class ExceptionsFragment : Fragment() { exceptionsStore = StoreProvider.get(this) { ExceptionsFragmentStore( ExceptionsFragmentState( items = listOf() items = emptyList() ) ) } Loading @@ -61,7 +62,6 @@ class ExceptionsFragment : Fragment() { @ExperimentalCoroutinesApi override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) consumeFrom(exceptionsStore) { exceptionsView.update(it) } Loading
app/src/main/java/org/mozilla/fenix/exceptions/ExceptionsView.kt +17 −16 Original line number Diff line number Diff line Loading @@ -4,16 +4,16 @@ package org.mozilla.fenix.exceptions import android.text.SpannableString import android.text.method.LinkMovementMethod import android.text.style.UnderlineSpan import android.view.LayoutInflater import android.view.ViewGroup import android.widget.FrameLayout import androidx.core.text.toSpannable import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.extensions.LayoutContainer import kotlinx.android.synthetic.main.component_exceptions.view.* import kotlinx.android.synthetic.main.component_exceptions.* import mozilla.components.concept.engine.content.blocking.TrackingProtectionException import org.mozilla.fenix.R Loading Loading @@ -42,35 +42,36 @@ interface ExceptionsViewInteractor { * View that contains and configures the Exceptions List */ class ExceptionsView( override val containerView: ViewGroup, val interactor: ExceptionsInteractor container: ViewGroup, interactor: ExceptionsInteractor ) : LayoutContainer { val view: FrameLayout = LayoutInflater.from(containerView.context) .inflate(R.layout.component_exceptions, containerView, true) override val containerView: FrameLayout = LayoutInflater.from(container.context) .inflate(R.layout.component_exceptions, container, true) .findViewById(R.id.exceptions_wrapper) private val exceptionsAdapter = ExceptionsAdapter(interactor) init { view.exceptions_list.apply { exceptions_list.apply { adapter = exceptionsAdapter layoutManager = LinearLayoutManager(containerView.context) layoutManager = LinearLayoutManager(container.context) } val learnMoreText = view.exceptions_learn_more.text.toString() val textWithLink = SpannableString(learnMoreText).apply { with(exceptions_learn_more) { val learnMoreText = text text = learnMoreText.toSpannable().apply { setSpan(UnderlineSpan(), 0, learnMoreText.length, 0) } with(view.exceptions_learn_more) { movementMethod = LinkMovementMethod.getInstance() text = textWithLink setOnClickListener { interactor.onLearnMore() } } } fun update(state: ExceptionsFragmentState) { view.exceptions_empty_view.isVisible = state.items.isEmpty() view.exceptions_list.isVisible = state.items.isNotEmpty() exceptions_empty_view.isVisible = state.items.isEmpty() exceptions_list.isVisible = state.items.isNotEmpty() exceptionsAdapter.updateData(state.items) } }
app/src/test/java/org/mozilla/fenix/exceptions/ExceptionsAdapterTest.kt 0 → 100644 +42 −0 Original line number Diff line number Diff line /* 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.exceptions import io.mockk.mockk import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.test.runBlockingTest import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @ExperimentalCoroutinesApi @RunWith(FenixRobolectricTestRunner::class) class ExceptionsAdapterTest { private lateinit var interactor: ExceptionsInteractor private lateinit var adapter: ExceptionsAdapter @Before fun setup() { interactor = mockk() adapter = ExceptionsAdapter(interactor) } @Test fun `binds header and delete button with other adapter items`() = runBlockingTest { adapter.updateData(listOf(mockk(), mockk())) assertEquals(4, adapter.itemCount) assertEquals(ExceptionsHeaderViewHolder.LAYOUT_ID, adapter.getItemViewType(0)) assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(1)) assertEquals(ExceptionsListItemViewHolder.LAYOUT_ID, adapter.getItemViewType(2)) assertEquals(ExceptionsDeleteButtonViewHolder.LAYOUT_ID, adapter.getItemViewType(3)) } }
app/src/test/java/org/mozilla/fenix/exceptions/ExceptionsViewTest.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* 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.exceptions import android.text.Spannable import android.text.method.LinkMovementMethod import android.view.ViewGroup import android.widget.FrameLayout import androidx.core.view.isVisible import io.mockk.Runs import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.mockkConstructor import io.mockk.unmockkConstructor import io.mockk.verify import kotlinx.android.synthetic.main.component_exceptions.* import mozilla.components.concept.engine.content.blocking.TrackingProtectionException import mozilla.components.support.test.robolectric.testContext import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mozilla.fenix.helpers.FenixRobolectricTestRunner @RunWith(FenixRobolectricTestRunner::class) class ExceptionsViewTest { private lateinit var container: ViewGroup private lateinit var interactor: ExceptionsInteractor private lateinit var exceptionsView: ExceptionsView @Before fun setup() { mockkConstructor(ExceptionsAdapter::class) container = FrameLayout(testContext) interactor = mockk() exceptionsView = ExceptionsView(container, interactor) every { anyConstructed<ExceptionsAdapter>().updateData(any()) } just Runs } @After fun teardown() { unmockkConstructor(ExceptionsAdapter::class) } @Test fun `binds exception text`() { assertTrue(exceptionsView.exceptions_learn_more.movementMethod is LinkMovementMethod) assertTrue(exceptionsView.exceptions_learn_more.text is Spannable) assertEquals("Learn more", exceptionsView.exceptions_learn_more.text.toString()) every { interactor.onLearnMore() } just Runs exceptionsView.exceptions_learn_more.performClick() verify { interactor.onLearnMore() } } @Test fun `binds empty list to adapter`() { exceptionsView.update(ExceptionsFragmentState(emptyList())) assertTrue(exceptionsView.exceptions_empty_view.isVisible) assertFalse(exceptionsView.exceptions_list.isVisible) verify { anyConstructed<ExceptionsAdapter>().updateData(emptyList()) } } @Test fun `binds list with items to adapter`() { val items = listOf<TrackingProtectionException>(mockk(), mockk()) exceptionsView.update(ExceptionsFragmentState(items)) assertFalse(exceptionsView.exceptions_empty_view.isVisible) assertTrue(exceptionsView.exceptions_list.isVisible) verify { anyConstructed<ExceptionsAdapter>().updateData(items) } } }