[fenix] For https://github.com/mozilla-mobile/fenix/issues/22250 - Convert Recent Bookmarks to Jetpack Compose

pull/600/head
Gabriel Luong 3 years ago committed by mergify[bot]
parent f2e74f31f8
commit 100d5372ee

@ -1,44 +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.recentbookmarks
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor
import org.mozilla.fenix.home.recentbookmarks.view.RecentBookmarkItemViewHolder
/**
* Adapter for binding individual bookmark items for the homescreen.
*
* @param interactor The [RecentBookmarksInteractor] to be passed into the view.
*/
class RecentBookmarksItemAdapter(
private val interactor: RecentBookmarksInteractor
) : ListAdapter<BookmarkNode, RecentBookmarkItemViewHolder>(RecentBookmarkItemDiffCallback) {
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecentBookmarkItemViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(RecentBookmarkItemViewHolder.LAYOUT_ID, parent, false)
return RecentBookmarkItemViewHolder(view, interactor)
}
override fun onBindViewHolder(holder: RecentBookmarkItemViewHolder, position: Int) {
holder.bind(getItem(position))
}
internal object RecentBookmarkItemDiffCallback : DiffUtil.ItemCallback<BookmarkNode>() {
override fun areItemsTheSame(oldItem: BookmarkNode, newItem: BookmarkNode) =
oldItem.guid == newItem.guid
override fun areContentsTheSame(oldItem: BookmarkNode, newItem: BookmarkNode) =
oldItem == newItem
}
}

@ -1,38 +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.recentbookmarks.view
import android.view.View
import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.RecentBookmarkItemBinding
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.loadIntoView
import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor
import org.mozilla.fenix.utils.view.ViewHolder
class RecentBookmarkItemViewHolder(
private val view: View,
private val interactor: RecentBookmarksInteractor
) : ViewHolder(view) {
fun bind(bookmark: BookmarkNode) {
val binding = RecentBookmarkItemBinding.bind(view)
binding.bookmarkTitle.text = bookmark.title ?: bookmark.url
binding.bookmarkItem.setOnClickListener {
interactor.onRecentBookmarkClicked(bookmark)
}
bookmark.url?.let {
view.context.components.core.icons.loadIntoView(binding.faviconImage, it)
}
}
companion object {
const val LAYOUT_ID = R.layout.recent_bookmark_item
}
}

@ -0,0 +1,182 @@
/* 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.recentbookmarks.view
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import mozilla.components.browser.icons.compose.Loader
import mozilla.components.browser.icons.compose.Placeholder
import mozilla.components.browser.icons.compose.WithIcon
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.ui.colors.PhotonColors
import org.mozilla.fenix.components.components
import org.mozilla.fenix.theme.FirefoxTheme
/**
* A list of recent bookmarks.
*
* @param bookmarks List of [BookmarkNode]s to display.
* @param onRecentBookmarkClick Invoked when the user clicks on a recent bookmark.
*/
@Composable
fun RecentBookmarks(
bookmarks: List<BookmarkNode>,
onRecentBookmarkClick: (BookmarkNode) -> Unit = {}
) {
LazyRow(
contentPadding = PaddingValues(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
items(bookmarks) { bookmark ->
RecentBookmarkItem(
bookmark = bookmark,
onRecentBookmarkClick = onRecentBookmarkClick
)
}
}
}
/**
* A recent bookmark item.
*
* @param bookmark The [BookmarkNode] to display.
* @param onRecentBookmarkClick Invoked when the user clicks on the recent bookmark item.
*/
@Composable
private fun RecentBookmarkItem(
bookmark: BookmarkNode,
onRecentBookmarkClick: (BookmarkNode) -> Unit = {}
) {
Column(
modifier = Modifier
.width(156.dp)
.clickable { onRecentBookmarkClick(bookmark) }
) {
Card(
modifier = Modifier
.fillMaxWidth()
.height(96.dp),
elevation = 6.dp
) {
if (bookmark.url != null) {
components.core.icons.Loader(bookmark.url!!) {
Placeholder {
Box(
modifier = Modifier.background(
color = when (isSystemInDarkTheme()) {
true -> PhotonColors.DarkGrey30
false -> PhotonColors.LightGrey30
}
)
)
}
WithIcon { icon ->
Box(
modifier = Modifier.size(36.dp),
contentAlignment = Alignment.Center
) {
Image(
painter = icon.painter,
contentDescription = null,
modifier = Modifier
.size(36.dp)
.clip(RoundedCornerShape(8.dp)),
contentScale = ContentScale.Fit
)
}
}
}
}
}
Spacer(modifier = Modifier.height(8.dp))
Text(
text = bookmark.title ?: bookmark.url ?: "",
color = FirefoxTheme.colors.textPrimary,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1
)
}
}
@Composable
@Preview
private fun RecentBookmarksPreview() {
FirefoxTheme {
RecentBookmarks(
bookmarks = listOf(
BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "1",
parentGuid = null,
position = null,
title = "Other Bookmark Title",
url = "https://www.example.com",
dateAdded = 0,
children = null
),
BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "2",
parentGuid = null,
position = null,
title = "Other Bookmark Title",
url = "https://www.example.com",
dateAdded = 0,
children = null
),
BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "3",
parentGuid = null,
position = null,
title = "Other Bookmark Title",
url = "https://www.example.com",
dateAdded = 0,
children = null
),
BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "4",
parentGuid = null,
position = null,
title = "Other Bookmark Title",
url = "https://www.example.com",
dateAdded = 0,
children = null
)
)
)
}
}

@ -0,0 +1,43 @@
/* 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.recentbookmarks.view
import android.view.View
import androidx.navigation.findNavController
import org.mozilla.fenix.R
import org.mozilla.fenix.databinding.RecentBookmarksHeaderBinding
import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor
import org.mozilla.fenix.utils.view.ViewHolder
/**
* View holder for the recent bookmarks header and "Show all" button.
*
* @param view The container [View] for this view holder.
* @param interactor [RecentBookmarksInteractor] which will have delegated to all user interactions.
*/
class RecentBookmarksHeaderViewHolder(
view: View,
private val interactor: RecentBookmarksInteractor
) : ViewHolder(view) {
init {
val binding = RecentBookmarksHeaderBinding.bind(view)
binding.showAllBookmarksButton.setOnClickListener {
dismissSearchDialogIfDisplayed()
interactor.onShowAllBookmarksClicked()
}
}
private fun dismissSearchDialogIfDisplayed() {
val navController = itemView.findNavController()
if (navController.currentDestination?.id == R.id.searchDialogFragment) {
navController.navigateUp()
}
}
companion object {
const val LAYOUT_ID = R.layout.recent_bookmarks_header
}
}

@ -5,59 +5,42 @@
package org.mozilla.fenix.home.recentbookmarks.view
import android.view.View
import androidx.navigation.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager.HORIZONTAL
import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.R
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import mozilla.components.lib.state.ext.observeAsComposableState
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
import org.mozilla.fenix.databinding.ComponentRecentBookmarksBinding
import org.mozilla.fenix.home.recentbookmarks.RecentBookmarksItemAdapter
import org.mozilla.fenix.home.HomeFragmentStore
import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.utils.view.ViewHolder
class RecentBookmarksViewHolder(
view: View,
val composeView: ComposeView,
private val store: HomeFragmentStore,
val interactor: RecentBookmarksInteractor,
val metrics: MetricController
) : ViewHolder(view) {
private val recentBookmarksAdapter = RecentBookmarksItemAdapter(interactor)
) : ViewHolder(composeView) {
init {
val recentBookmarksBinding = ComponentRecentBookmarksBinding.bind(view)
val recentBookmarksHeaderBinding = recentBookmarksBinding.recentBookmarksHeader
val linearLayoutManager = LinearLayoutManager(view.context, HORIZONTAL, false)
recentBookmarksBinding.recentBookmarksList.apply {
adapter = recentBookmarksAdapter
layoutManager = linearLayoutManager
}
recentBookmarksHeaderBinding.showAllBookmarksButton.setOnClickListener {
dismissSearchDialogIfDisplayed()
interactor.onShowAllBookmarksClicked()
}
}
fun bind(bookmarks: List<BookmarkNode>) {
recentBookmarksAdapter.submitList(bookmarks)
if (bookmarks.isNotEmpty()) {
metrics.track(Event.RecentBookmarksShown)
}
}
private fun dismissSearchDialogIfDisplayed() {
val navController = itemView.findNavController()
if (navController.currentDestination?.id == R.id.searchDialogFragment) {
navController.navigateUp()
metrics.track(Event.RecentBookmarksShown)
composeView.setViewCompositionStrategy(
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
)
composeView.setContent {
val recentBookmarks = store.observeAsComposableState { state -> state.recentBookmarks }
FirefoxTheme {
RecentBookmarks(
bookmarks = recentBookmarks.value ?: emptyList(),
onRecentBookmarkClick = interactor::onRecentBookmarkClicked
)
}
}
}
companion object {
const val LAYOUT_ID = R.layout.component_recent_bookmarks
val LAYOUT_ID = View.generateViewId()
}
}

@ -13,7 +13,6 @@ import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite
import mozilla.components.feature.top.sites.TopSite.Type.FRECENT
@ -25,6 +24,8 @@ import org.mozilla.fenix.historymetadata.view.HistoryMetadataHeaderViewHolder
import org.mozilla.fenix.home.HomeFragmentStore
import org.mozilla.fenix.home.TopPlaceholderViewHolder
import org.mozilla.fenix.home.OnboardingState
import org.mozilla.fenix.home.pocket.PocketStoriesViewHolder
import org.mozilla.fenix.home.recentbookmarks.view.RecentBookmarksHeaderViewHolder
import org.mozilla.fenix.home.recentbookmarks.view.RecentBookmarksViewHolder
import org.mozilla.fenix.home.recenttabs.view.RecentTabViewHolder
import org.mozilla.fenix.home.recenttabs.view.RecentTabsHeaderViewHolder
@ -44,7 +45,6 @@ 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.OnboardingToolbarPositionPickerViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder
import org.mozilla.fenix.home.pocket.PocketStoriesViewHolder
import org.mozilla.fenix.home.tips.ButtonTipViewHolder
import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder
import mozilla.components.feature.tab.collections.Tab as ComponentTab
@ -167,30 +167,8 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
object HistoryMetadataHeader : AdapterItem(HistoryMetadataHeaderViewHolder.LAYOUT_ID)
object HistoryMetadataGroup : AdapterItem(HistoryMetadataGroupViewHolder.LAYOUT_ID)
data class RecentBookmarks(val recentBookmarks: List<BookmarkNode>) :
AdapterItem(RecentBookmarksViewHolder.LAYOUT_ID) {
override fun sameAs(other: AdapterItem): Boolean {
val newBookmarks = (other as? RecentBookmarks) ?: return false
if (newBookmarks.recentBookmarks.size != this.recentBookmarks.size) {
return false
}
return recentBookmarks.zip(newBookmarks.recentBookmarks).all { (new, old) ->
new.guid == old.guid
}
}
override fun contentsSameAs(other: AdapterItem): Boolean {
val newBookmarks = (other as? RecentBookmarks) ?: return false
val newBookmarksSequence = newBookmarks.recentBookmarks.asSequence()
val oldBookmarksList = this.recentBookmarks.asSequence()
return newBookmarksSequence.zip(oldBookmarksList).all { (new, old) ->
new == old
}
}
}
object RecentBookmarksHeader : AdapterItem(RecentBookmarksHeaderViewHolder.LAYOUT_ID)
object RecentBookmarks : AdapterItem(RecentBookmarksViewHolder.LAYOUT_ID)
object PocketStoriesItem :
AdapterItem(PocketStoriesViewHolder.LAYOUT_ID)
@ -242,6 +220,12 @@ class SessionControlAdapter(
store = store,
interactor = interactor
)
RecentBookmarksViewHolder.LAYOUT_ID -> return RecentBookmarksViewHolder(
composeView = ComposeView(parent.context),
store = store,
interactor = interactor,
metrics = components.analytics.metrics
)
RecentTabViewHolder.LAYOUT_ID -> return RecentTabViewHolder(
composeView = ComposeView(parent.context),
store = store,
@ -297,9 +281,7 @@ class SessionControlAdapter(
)
ExperimentDefaultBrowserCardViewHolder.LAYOUT_ID -> ExperimentDefaultBrowserCardViewHolder(view, interactor)
RecentTabsHeaderViewHolder.LAYOUT_ID -> RecentTabsHeaderViewHolder(view, interactor)
RecentBookmarksViewHolder.LAYOUT_ID -> {
RecentBookmarksViewHolder(view, interactor, components.analytics.metrics)
}
RecentBookmarksHeaderViewHolder.LAYOUT_ID -> RecentBookmarksHeaderViewHolder(view, interactor)
HistoryMetadataHeaderViewHolder.LAYOUT_ID -> HistoryMetadataHeaderViewHolder(
view,
interactor
@ -312,6 +294,7 @@ class SessionControlAdapter(
when (holder) {
is CustomizeHomeButtonViewHolder,
is HistoryMetadataGroupViewHolder,
is RecentBookmarksViewHolder,
is RecentTabViewHolder,
is PocketStoriesViewHolder -> {
// no op
@ -374,12 +357,8 @@ class SessionControlAdapter(
is OnboardingAutomaticSignInViewHolder -> holder.bind(
(item as AdapterItem.OnboardingAutomaticSignIn).state.withAccount
)
is RecentBookmarksViewHolder -> {
holder.bind(
(item as AdapterItem.RecentBookmarks).recentBookmarks
)
}
is HistoryMetadataGroupViewHolder,
is RecentBookmarksViewHolder,
is RecentTabViewHolder,
is PocketStoriesViewHolder -> {
// no-op. This ViewHolder receives the HomeStore as argument and will observe that

@ -66,7 +66,8 @@ internal fun normalModeAdapterItems(
if (recentBookmarks.isNotEmpty()) {
shouldShowCustomizeHome = true
items.add(AdapterItem.RecentBookmarks(recentBookmarks))
items.add(AdapterItem.RecentBookmarksHeader)
items.add(AdapterItem.RecentBookmarks)
}
if (historyMetadata.isNotEmpty()) {

@ -1,26 +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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/home_item_horizontal_margin"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical">
<include
android:id="@+id/recent_bookmarks_header"
layout="@layout/recent_bookmarks_header" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recent_bookmarks_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/recent_bookmark_item"
tools:spanCount="4" />
</LinearLayout>

@ -1,49 +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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bookmark_item"
android:layout_width="@dimen/recent_bookmark_item_width"
android:layout_height="wrap_content" >
<com.google.android.material.card.MaterialCardView
android:layout_width="@dimen/recent_bookmark_item_card_width"
android:layout_height="@dimen/recent_bookmark_item_favicon_height"
android:layout_marginTop="@dimen/recent_bookmark_item_card_padding_top"
android:layout_marginBottom="@dimen/recent_bookmark_item_card_padding_bottom"
app:cardBackgroundColor="?mozac_widget_favicon_background_color"
app:cardElevation="@dimen/recent_bookmark_item_card_elevation"
app:layout_constraintBottom_toTopOf="@+id/bookmark_title"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/favicon_image"
style="@style/recentBookmarkFavicon"
android:layout_width="@dimen/top_sites_favicon_size"
android:layout_height="@dimen/top_sites_favicon_size"
android:layout_gravity="center" />
</com.google.android.material.card.MaterialCardView>
<TextView
android:id="@+id/bookmark_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:importantForAccessibility="yes"
android:maxLines="1"
android:nestedScrollingEnabled="false"
android:scrollbars="none"
android:textAppearance="@style/recentBookmarkItemSubTitleText"
android:paddingHorizontal="@dimen/recent_bookmark_item_text_padding_horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="Recently Saved bookmark item" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1,15 +1,15 @@
<?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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/recent_bookmark_header_margin_top">
android:layout_marginHorizontal="@dimen/home_item_horizontal_margin"
android:layout_marginTop="40dp"
android:layout_marginBottom="16dp">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/header"

@ -80,18 +80,6 @@
<dimen name="home_item_elevation">5dp</dimen>
<dimen name="home_item_horizontal_margin">16dp</dimen>
<!-- Home - Recently saved bookmarks -->
<dimen name="recent_bookmark_header_margin_top">40dp</dimen>
<dimen name="recent_bookmark_item_width">164dp</dimen>
<dimen name="recent_bookmark_item_card_width">156dp</dimen>
<dimen name="recent_bookmark_item_card_padding_top">16dp</dimen>
<dimen name="recent_bookmark_item_card_padding_bottom">8dp</dimen>
<dimen name="recent_bookmark_item_card_elevation">6dp</dimen>
<dimen name="recent_bookmark_item_favicon_height">96dp</dimen>
<dimen name="recent_bookmark_item_favicon_elevation">0dp</dimen>
<dimen name="recent_bookmark_item_favicon_corner_size">8dp</dimen>
<dimen name="recent_bookmark_item_text_padding_horizontal">4dp</dimen>
<!-- Browser Fragment -->
<!--The size of the gap between the tab preview and content layout.-->
<dimen name="browser_fragment_gesture_preview_offset">48dp</dimen>

@ -659,29 +659,6 @@
<item name="cornerSize">@dimen/top_sites_favicon_corner_size</item>
</style>
<style name="recentBookmarkFavicon">
<item name="android:layout_width">@dimen/recent_bookmark_item_width</item>
<item name="android:layout_height">@dimen/recent_bookmark_item_favicon_height</item>
<item name="android:scaleType">fitStart</item>
<item name="android:layout_gravity">start|top</item>
<item name="shapeAppearanceOverlay">@style/recentBookmarkFaviconShape</item>
</style>
<style name="recentBookmarkFaviconShape">
<item name="cornerFamily">rounded</item>
<item name="elevation">@dimen/recent_bookmark_item_favicon_elevation</item>
<item name="cornerSize">@dimen/recent_bookmark_item_favicon_corner_size</item>
</style>
<style name="recentBookmarkItemSubTitleText" parent="Body12TextStyle">
<item name="android:gravity">start</item>
<item name="android:textColor">?primaryText</item>
<item name="android:textAlignment">gravity</item>
<item name="android:singleLine">true</item>
<item name="android:ellipsize">end</item>
<item name="android:maxLines">1</item>
</style>
<style name="TabTrayFab" parent="Widget.MaterialComponents.ExtendedFloatingActionButton">
<item name="elevation">90dp</item>
<item name="android:stateListAnimator">@null</item>

@ -1,90 +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.recentbookmarks.view
import android.view.LayoutInflater
import io.mockk.mockk
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.RecentBookmarkItemBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
@RunWith(FenixRobolectricTestRunner::class)
class RecentBookmarkItemViewHolderTest {
private lateinit var binding: RecentBookmarkItemBinding
private lateinit var interactor: SessionControlInteractor
private val bookmarkNoUrl = BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "guid#${Math.random() * 1000}",
parentGuid = null,
position = null,
title = "Bookmark Title",
url = null,
dateAdded = 0,
children = null
)
private val bookmarkWithUrl = BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "guid#${Math.random() * 1000}",
parentGuid = null,
position = null,
title = "Other Bookmark Title",
url = "https://www.example.com",
dateAdded = 0,
children = null
)
private val bookmarkNoTitle = BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "guid#${Math.random() * 1000}",
parentGuid = null,
position = null,
title = null,
url = "https://www.github.com",
dateAdded = 0,
children = null
)
@Before
fun setup() {
binding = RecentBookmarkItemBinding.inflate(LayoutInflater.from(testContext))
interactor = mockk(relaxed = true)
}
@Test
fun `GIVEN a bookmark exists in the list THEN set the title text`() {
RecentBookmarkItemViewHolder(binding.root, interactor).bind(bookmarkWithUrl)
Assert.assertEquals(bookmarkWithUrl.title, binding.bookmarkTitle.text)
}
@Test
fun `WHEN there is no url for the bookmark THEN do not load an icon `() {
val viewHolder = RecentBookmarkItemViewHolder(binding.root, interactor)
Assert.assertNull(binding.faviconImage.drawable)
viewHolder.bind(bookmarkNoUrl)
Assert.assertNull(binding.faviconImage.drawable)
}
@Test
fun `WHEN a bookmark does not have a title THEN show the url`() {
RecentBookmarkItemViewHolder(binding.root, interactor).bind(bookmarkNoTitle)
Assert.assertEquals(bookmarkNoTitle.url, binding.bookmarkTitle.text)
}
}

@ -0,0 +1,40 @@
/* 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.recentbookmarks.view
import android.view.LayoutInflater
import androidx.navigation.Navigation
import io.mockk.mockk
import io.mockk.verify
import mozilla.components.support.test.robolectric.testContext
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.RecentBookmarksHeaderBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.recentbookmarks.interactor.RecentBookmarksInteractor
@RunWith(FenixRobolectricTestRunner::class)
class RecentBookmarksHeaderViewHolderTest {
private lateinit var binding: RecentBookmarksHeaderBinding
private lateinit var interactor: RecentBookmarksInteractor
@Before
fun setup() {
binding = RecentBookmarksHeaderBinding.inflate(LayoutInflater.from(testContext))
Navigation.setViewNavController(binding.root, mockk(relaxed = true))
interactor = mockk(relaxed = true)
}
@Test
fun `WHEN show all button is clicked THEN interactor is called`() {
RecentBookmarksHeaderViewHolder(binding.root, interactor)
binding.showAllBookmarksButton.performClick()
verify { interactor.onShowAllBookmarksClicked() }
}
}

@ -1,52 +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.recentbookmarks.view
import android.view.LayoutInflater
import androidx.navigation.Navigation
import io.mockk.mockk
import io.mockk.verify
import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.support.test.robolectric.testContext
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.databinding.ComponentRecentBookmarksBinding
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
@RunWith(FenixRobolectricTestRunner::class)
class RecentBookmarksViewHolderTest {
private lateinit var binding: ComponentRecentBookmarksBinding
private lateinit var interactor: SessionControlInteractor
private val bookmark = BookmarkNode(
type = BookmarkNodeType.ITEM,
guid = "guid#${Math.random() * 1000}",
parentGuid = null,
position = null,
title = null,
url = null,
dateAdded = 0,
children = null
)
@Before
fun setup() {
binding = ComponentRecentBookmarksBinding.inflate(LayoutInflater.from(testContext))
Navigation.setViewNavController(binding.root, mockk(relaxed = true))
interactor = mockk(relaxed = true)
}
@Test
fun `WHEN show all bookmarks button is clicked THEN interactor is called`() {
RecentBookmarksViewHolder(binding.root, interactor, mockk(relaxed = true)).bind(listOf(bookmark))
binding.recentBookmarksHeader.showAllBookmarksButton.performClick()
verify { interactor.onShowAllBookmarksClicked() }
}
}

@ -15,8 +15,8 @@ import mozilla.components.feature.top.sites.TopSite
import mozilla.components.service.pocket.PocketRecommendedStory
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ -155,8 +155,9 @@ class SessionControlViewTest {
)
assertTrue(results[0] is AdapterItem.TopPlaceholderItem)
assertTrue(results[1] is AdapterItem.RecentBookmarks)
assertTrue(results[2] is AdapterItem.CustomizeHomeButton)
assertTrue(results[1] is AdapterItem.RecentBookmarksHeader)
assertTrue(results[2] is AdapterItem.RecentBookmarks)
assertTrue(results[3] is AdapterItem.CustomizeHomeButton)
}
@Test

Loading…
Cancel
Save