diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt
index 7be997890..6875e305e 100644
--- a/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt
+++ b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt
@@ -83,7 +83,7 @@ fun Collection(
.height(48.dp),
shape = if (isExpanded) expandedCollectionShape else collapsedCollectionShape,
backgroundColor = FirefoxTheme.colors.layer2,
- elevation = 5.dp, // This needs to match the elevation of TabInCollection for matching shadows.
+ elevation = 5.dp,
) {
Row(
modifier = Modifier
diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionItem.kt b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionItem.kt
new file mode 100644
index 000000000..2c5ad9e2e
--- /dev/null
+++ b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionItem.kt
@@ -0,0 +1,261 @@
+/* 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.collections
+
+import android.content.Context
+import android.content.res.Configuration
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.Card
+import androidx.compose.material.DismissDirection
+import androidx.compose.material.DismissDirection.EndToStart
+import androidx.compose.material.DismissDirection.StartToEnd
+import androidx.compose.material.ExperimentalMaterialApi
+import androidx.compose.material.Icon
+import androidx.compose.material.SwipeToDismiss
+import androidx.compose.material.rememberDismissState
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.graphics.drawscope.clipRect
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.dp
+import mozilla.components.browser.state.state.recover.RecoverableTab
+import mozilla.components.concept.engine.Engine
+import mozilla.components.feature.tab.collections.Tab
+import org.mozilla.fenix.R.drawable
+import org.mozilla.fenix.R.string
+import org.mozilla.fenix.compose.inComposePreview
+import org.mozilla.fenix.compose.list.FaviconListItem
+import org.mozilla.fenix.ext.components
+import org.mozilla.fenix.ext.toShortUrl
+import org.mozilla.fenix.theme.FirefoxTheme
+import org.mozilla.fenix.theme.Theme
+
+/**
+ * Rectangular shape with only right angles used to display a middle tab.
+ */
+private val MIDDLE_TAB_SHAPE = RoundedCornerShape(0.dp)
+
+/**
+ * Rectangular shape with only the bottom corners rounded used to display the last tab in a collection.
+ */
+private val BOTTOM_TAB_SHAPE = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)
+
+/**
+ * Display an individual [Tab] as part of a collection.
+ *
+ * @param tab [Tab] to display.
+ * @param isLastInCollection Whether the tab is to be shown between others or as the last one in collection.
+ * @param onClick Invoked when the user click on the tab.
+ * @param onRemove Invoked when the user removes the tab informing also if the tab was swiped to be removed.
+ */
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+fun CollectionItem(
+ tab: Tab,
+ isLastInCollection: Boolean,
+ onClick: () -> Unit,
+ onRemove: (Boolean) -> Unit,
+) {
+ val dismissState = rememberDismissState()
+
+ if (dismissState.isDismissed(StartToEnd) || dismissState.isDismissed(EndToStart)) {
+ onRemove(true)
+ }
+
+ SwipeToDismiss(
+ state = dismissState,
+ background = {
+ DismissedTabBackground(
+ dismissDirection = dismissState.dismissDirection,
+ isLastInCollection = isLastInCollection,
+ )
+ }
+ ) {
+ // We need to clip the top bounds to avoid this item drawing shadows over the above item.
+ // But we need to add this shadows back to have a clearer separation between tabs
+ // when one is being swiped away.
+ val clippingModifier by remember {
+ derivedStateOf {
+ try {
+ if (dismissState.progress.fraction != 1f) Modifier else Modifier.clipTop()
+ } catch (e: NoSuchElementException) {
+ // `androidx.compose.material.Swipeable.findBounds` couldn't find anchors.
+ // Happened once in testing when deleting a tab. Could not reproduce afterwards.
+ Modifier.clipTop()
+ }
+ }
+ }
+
+ Card(
+ modifier = clippingModifier
+ .fillMaxWidth(),
+ shape = if (isLastInCollection) BOTTOM_TAB_SHAPE else MIDDLE_TAB_SHAPE,
+ backgroundColor = FirefoxTheme.colors.layer2,
+ elevation = 5.dp,
+ ) {
+ FaviconListItem(
+ label = tab.title,
+ description = shortenUrl(tab.url),
+ onClick = onClick,
+ url = tab.url,
+ iconPainter = painterResource(drawable.ic_close),
+ iconDescription = stringResource(string.remove_tab_from_collection),
+ onIconClick = { onRemove(false) },
+ )
+ }
+ }
+}
+
+/**
+ * Composable used to display the background of a [Tab] shown in collections that is being swiped left or right.
+ *
+ * @param dismissDirection [DismissDirection] of the tab being swiped depending on which this composable
+ * will also indicate the swipe direction by placing a warning icon at the start of the swipe gesture.
+ * If `null` the warning icon will be shown at both ends.
+ * @param isLastInCollection Whether the tab is to be shown between others or as the last one in collection.
+ */
+@Composable
+private fun DismissedTabBackground(
+ dismissDirection: DismissDirection?,
+ isLastInCollection: Boolean,
+) {
+ Card(
+ modifier = Modifier.fillMaxSize(),
+ backgroundColor = FirefoxTheme.colors.layer3,
+ shape = if (isLastInCollection) BOTTOM_TAB_SHAPE else MIDDLE_TAB_SHAPE,
+ elevation = 0.dp,
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Icon(
+ painter = painterResource(drawable.ic_delete),
+ contentDescription = null,
+ modifier = Modifier
+ .padding(horizontal = 32.dp)
+ // Only show the delete icon for where the swipe starts.
+ .alpha(
+ if (dismissDirection == StartToEnd) 1f else 0f
+ ),
+ tint = FirefoxTheme.colors.iconWarning,
+ )
+
+ Icon(
+ painter = painterResource(drawable.ic_delete),
+ contentDescription = null,
+ modifier = Modifier
+ .padding(horizontal = 32.dp)
+ // Only show the delete icon for where the swipe starts.
+ .alpha(
+ if (dismissDirection == EndToStart) 1f else 0f
+ ),
+ tint = FirefoxTheme.colors.iconWarning,
+ )
+ }
+ }
+}
+
+/**
+ * Clips the Composable this applies to such that it cannot draw content / shadows outside it's top bound.
+ */
+private fun Modifier.clipTop() = this.then(
+ Modifier.drawWithContent {
+ val paddingPx = Constraints.Infinity.toFloat()
+ clipRect(
+ left = 0f - paddingPx,
+ top = 0f,
+ right = size.width + paddingPx,
+ bottom = size.height + paddingPx
+ ) {
+ this@drawWithContent.drawContent()
+ }
+ }
+)
+
+/**
+ * Get a friendlier short url for [url].
+ *
+ * @param url Full url to be shortened.
+ *
+ * @see toShortUrl
+ */
+@Composable
+private fun shortenUrl(url: String): String {
+ return if (inComposePreview) {
+ url
+ } else {
+ url.toShortUrl(LocalContext.current.components.publicSuffixList)
+ }
+}
+
+@OptIn(ExperimentalMaterialApi::class)
+@Composable
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO)
+private fun TabInCollectionPreview() {
+ FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
+ Column {
+ Box(modifier = Modifier.height(56.dp)) {
+ DismissedTabBackground(
+ dismissDirection = StartToEnd,
+ isLastInCollection = false,
+ )
+ }
+ CollectionItem(
+ tab = tabPreview,
+ isLastInCollection = false,
+ onClick = {},
+ onRemove = {},
+ )
+
+ Spacer(Modifier.height(10.dp))
+
+ Box(modifier = Modifier.height(56.dp)) {
+ DismissedTabBackground(
+ dismissDirection = EndToStart,
+ isLastInCollection = true,
+ )
+ }
+ CollectionItem(
+ tab = tabPreview,
+ isLastInCollection = true,
+ onClick = {},
+ onRemove = {},
+ )
+ }
+ }
+}
+
+private val tabPreview = object : Tab {
+ override val id = 2L
+ override val title = "Mozilla-Firefox"
+ override val url = "https://www.mozilla.org/en-US/firefox/whats-new-in-last-version"
+
+ override fun restore(
+ context: Context,
+ engine: Engine,
+ restoreSessionId: Boolean
+ ): RecoverableTab? = null
+}
diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/TabInCollectionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/collections/TabInCollectionViewHolder.kt
new file mode 100644
index 000000000..520d819b7
--- /dev/null
+++ b/app/src/main/java/org/mozilla/fenix/home/collections/TabInCollectionViewHolder.kt
@@ -0,0 +1,94 @@
+/* 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.collections
+
+import android.view.View
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.ComposeView
+import androidx.lifecycle.LifecycleOwner
+import androidx.recyclerview.widget.RecyclerView
+import mozilla.components.feature.tab.collections.Tab
+import mozilla.components.feature.tab.collections.TabCollection
+import org.mozilla.fenix.R
+import org.mozilla.fenix.compose.ComposeViewHolder
+import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor
+
+/**
+ * [RecyclerView.ViewHolder] for displaying an individual [Tab].
+ * Clients are expected to use [bindSession] to link a particular [Tab] to be displayed
+ * otherwise this will be an empty, 0 size View.
+ *
+ * @param composeView [ComposeView] which will be populated with Jetpack Compose UI content.
+ * @param viewLifecycleOwner [LifecycleOwner] to which this Composable will be tied to.
+ * @param interactor [CollectionInteractor] callback for user interactions.
+ */
+class TabInCollectionViewHolder(
+ composeView: ComposeView,
+ viewLifecycleOwner: LifecycleOwner,
+ private val interactor: CollectionInteractor,
+) : ComposeViewHolder(composeView, viewLifecycleOwner) {
+ private var tabData = TabInfo()
+
+ init {
+ val horizontalPadding =
+ composeView.resources.getDimensionPixelSize(R.dimen.home_item_horizontal_margin)
+ composeView.setPadding(horizontalPadding, 0, horizontalPadding, 0)
+ }
+
+ @Composable
+ override fun Content() {
+ val tabInfo = remember { mutableStateOf(tabData) }
+
+ tabInfo.value.tab?.let { tab ->
+ tabInfo.value.collection?.let { collection ->
+
+ CollectionItem(
+ tab = tab,
+ isLastInCollection = tabInfo.value.isLastInCollection,
+ onClick = { interactor.onCollectionOpenTabClicked(tab) },
+ onRemove = { wasSwiped ->
+ interactor.onCollectionRemoveTab(
+ collection = collection,
+ tab = tab,
+ wasSwiped = wasSwiped,
+ )
+ },
+ )
+ }
+ }
+ }
+
+ /**
+ * Dynamically replace the current [Tab] shown in this `ViewHolder`.
+ *
+ * @param collection [TabCollection] containing [tab].
+ * @param tab [Tab] to display.
+ * @param isLastInCollection Whether [tab] is to be shown as the last item in [collection].
+ */
+ fun bindSession(collection: TabCollection, tab: Tab, isLastInCollection: Boolean) {
+ tabData = TabInfo(collection, tab, isLastInCollection)
+ }
+
+ companion object {
+ val LAYOUT_ID = View.generateViewId()
+ }
+}
+
+/**
+ * Wrapper over a [Tab] adding information about the collection it is part of and the position in this collection.
+ *
+ * @property collection [TabCollection] which contains this tab.
+ * @property tab [Tab] to display.
+ * @property isLastInCollection Whether the tab is to be shown between others or as the last one in collection.
+ */
+@Stable
+private data class TabInfo(
+ val collection: TabCollection? = null,
+ val tab: Tab? = null,
+ val isLastInCollection: Boolean = false,
+)
diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
index 932c24646..b375abe28 100644
--- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
+++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
@@ -15,12 +15,12 @@ import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.top.sites.TopSite
-import mozilla.components.ui.widgets.WidgetSiteItemView
import org.mozilla.fenix.components.Components
import org.mozilla.fenix.gleanplumb.Message
import org.mozilla.fenix.home.BottomSpacerViewHolder
import org.mozilla.fenix.home.TopPlaceholderViewHolder
import org.mozilla.fenix.home.collections.CollectionViewHolder
+import org.mozilla.fenix.home.collections.TabInCollectionViewHolder
import org.mozilla.fenix.home.pocket.PocketCategoriesViewHolder
import org.mozilla.fenix.home.pocket.PocketRecommendationsHeaderViewHolder
import org.mozilla.fenix.home.pocket.PocketStoriesViewHolder
@@ -34,7 +34,6 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHol
import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
-import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.MessageCardViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder
@@ -284,9 +283,14 @@ class SessionControlAdapter(
)
CollectionViewHolder.LAYOUT_ID -> return CollectionViewHolder(
composeView = ComposeView(parent.context),
- viewLifecycleOwner,
+ viewLifecycleOwner = viewLifecycleOwner,
interactor = interactor
)
+ TabInCollectionViewHolder.LAYOUT_ID -> return TabInCollectionViewHolder(
+ composeView = ComposeView(parent.context),
+ viewLifecycleOwner = viewLifecycleOwner,
+ interactor = interactor,
+ )
}
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
@@ -297,10 +301,6 @@ class SessionControlAdapter(
viewLifecycleOwner = viewLifecycleOwner,
interactor = interactor
)
- TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(
- view as WidgetSiteItemView,
- interactor
- )
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view)
OnboardingManualSignInViewHolder.LAYOUT_ID -> OnboardingManualSignInViewHolder(view)
@@ -348,6 +348,11 @@ class SessionControlAdapter(
// This ViewHolder can be removed / re-added and we need it to show a fresh new composition.
holder.composeView.disposeComposition()
}
+ is TabInCollectionViewHolder -> {
+ // Dispose the underlying composition immediately.
+ // This ViewHolder can be removed / re-added and we need it to show a fresh new composition.
+ holder.composeView.disposeComposition()
+ }
else -> super.onViewRecycled(holder)
}
}
diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
index fc7c6d9d8..f5b160236 100644
--- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
+++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
@@ -7,7 +7,6 @@ package org.mozilla.fenix.home.sessioncontrol
import android.view.View
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LifecycleOwner
-import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.feature.tab.collections.TabCollection
@@ -202,13 +201,6 @@ class SessionControlView(
JumpBackInCFRDialog(view).showIfNeeded()
}
}
- val itemTouchHelper =
- ItemTouchHelper(
- SwipeToDeleteCallback(
- interactor
- )
- )
- itemTouchHelper.attachToRecyclerView(this)
}
}
diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SwipeToDeleteCallback.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SwipeToDeleteCallback.kt
deleted file mode 100644
index 814722a8f..000000000
--- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SwipeToDeleteCallback.kt
+++ /dev/null
@@ -1,135 +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
-
-import android.content.res.Resources
-import android.graphics.Canvas
-import android.graphics.drawable.Drawable
-import androidx.appcompat.content.res.AppCompatResources
-import androidx.recyclerview.widget.ItemTouchHelper
-import androidx.recyclerview.widget.RecyclerView
-import mozilla.components.support.ktx.android.content.getColorFromAttr
-import org.mozilla.fenix.R
-import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
-
-class SwipeToDeleteCallback(
- val interactor: SessionControlInteractor
-) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {
- override fun onMove(
- recyclerView: RecyclerView,
- viewHolder: RecyclerView.ViewHolder,
- target: RecyclerView.ViewHolder
- ): Boolean {
- // We don't support drag and drop so this method will never be called
- return false
- }
-
- override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
- when (viewHolder) {
- is TabInCollectionViewHolder -> {
- interactor.onCollectionRemoveTab(viewHolder.collection, viewHolder.tab, wasSwiped = true)
- }
- }
- }
-
- override fun onChildDraw(
- c: Canvas,
- recyclerView: RecyclerView,
- viewHolder: RecyclerView.ViewHolder,
- dX: Float,
- dY: Float,
- actionState: Int,
- isCurrentlyActive: Boolean
- ) {
- super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
- val icon = AppCompatResources.getDrawable(recyclerView.context, R.drawable.ic_delete)
- icon?.setTint(recyclerView.context.getColorFromAttr(R.attr.textWarning))
-
- val backgroundDrawable = when {
- viewHolder is TabInCollectionViewHolder && viewHolder.isLastItem -> {
- R.drawable.tab_in_collection_last_swipe_background
- }
- viewHolder is TabInCollectionViewHolder -> {
- R.drawable.tab_in_collection_swipe_background
- }
- else -> R.drawable.session_background
- }
-
- val background = AppCompatResources.getDrawable(recyclerView.context, backgroundDrawable)
- background?.let {
- icon?.let {
- val itemView = viewHolder.itemView
- val iconLeft: Int
- val iconRight: Int
- val margin = convertDpToPixel(MARGIN.toFloat())
- val iconWidth = icon.intrinsicWidth
- val iconHeight = icon.intrinsicHeight
- val cellHeight = itemView.bottom - itemView.top
- val iconTop = itemView.top + (cellHeight - iconHeight) / 2
- val iconBottom = iconTop + iconHeight
-
- when {
- dX > 0 -> { // Swiping to the right
- iconLeft = itemView.left + margin
- iconRight = itemView.left + margin + iconWidth
- background.setBounds(
- itemView.left, itemView.top,
- (itemView.left + dX).toInt() + BACKGROUND_CORNER_OFFSET,
- itemView.bottom
- )
- icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
- draw(background, icon, c)
- }
- dX < 0 -> { // Swiping to the left
- iconLeft = itemView.right - margin - iconWidth
- iconRight = itemView.right - margin
- background.setBounds(
- (itemView.right + dX).toInt() - BACKGROUND_CORNER_OFFSET,
- itemView.top, itemView.right, itemView.bottom
- )
- icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
- draw(background, icon, c)
- }
- else -> { // View not swiped
- background.setBounds(0, 0, 0, 0)
- icon.setBounds(0, 0, 0, 0)
- }
- }
- }
- }
- }
-
- override fun getSwipeDirs(
- recyclerView: RecyclerView,
- viewHolder: RecyclerView.ViewHolder
- ): Int {
- return if (recyclerView.hasWindowFocus() &&
- viewHolder is TabInCollectionViewHolder
- ) {
- super.getSwipeDirs(recyclerView, viewHolder)
- } else 0
- }
-
- companion object {
- const val BACKGROUND_CORNER_OFFSET = 40
- const val MARGIN = 32
- private const val DENSITY_CONVERSION = 160f
-
- private fun draw(
- background: Drawable,
- icon: Drawable,
- c: Canvas
- ) {
- background.draw(c)
- icon.draw(c)
- }
-
- private fun convertDpToPixel(dp: Float): Int {
- val metrics = Resources.getSystem().displayMetrics
- val px = dp * (metrics.densityDpi / DENSITY_CONVERSION)
- return Math.round(px)
- }
- }
-}
diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TabInCollectionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TabInCollectionViewHolder.kt
deleted file mode 100644
index 17ad83f28..000000000
--- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TabInCollectionViewHolder.kt
+++ /dev/null
@@ -1,88 +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.os.Build
-import android.os.Build.VERSION.SDK_INT
-import androidx.appcompat.content.res.AppCompatResources
-import mozilla.components.browser.icons.BrowserIcons
-import mozilla.components.feature.tab.collections.TabCollection
-import mozilla.components.lib.publicsuffixlist.PublicSuffixList
-import mozilla.components.support.ktx.android.content.getColorFromAttr
-import mozilla.components.support.ktx.android.content.res.resolveAttribute
-import mozilla.components.ui.widgets.WidgetSiteItemView
-import org.mozilla.fenix.R
-import org.mozilla.fenix.ext.components
-import org.mozilla.fenix.ext.loadIntoView
-import org.mozilla.fenix.ext.toShortUrl
-import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor
-import org.mozilla.fenix.utils.view.ViewHolder
-import mozilla.components.feature.tab.collections.Tab as ComponentTab
-
-class TabInCollectionViewHolder(
- private val view: WidgetSiteItemView,
- val interactor: CollectionInteractor,
- private val icons: BrowserIcons = view.context.components.core.icons,
- private val publicSuffixList: PublicSuffixList = view.context.components.publicSuffixList
-) : ViewHolder(view) {
-
- lateinit var collection: TabCollection
- private set
- lateinit var tab: ComponentTab
- private set
- var isLastItem = false
- private set
-
- init {
- if (SDK_INT >= Build.VERSION_CODES.M) {
- view.foreground = AppCompatResources.getDrawable(
- view.context,
- view.context.theme.resolveAttribute(R.attr.selectableItemBackground)
- )
- }
-
- // This needs to match the elevation of the CollectionViewHolder for the shadow
- view.elevation = view.resources.getDimension(R.dimen.home_item_elevation)
-
- view.setOnClickListener {
- interactor.onCollectionOpenTabClicked(tab)
- }
-
- view.setSecondaryButton(
- icon = R.drawable.ic_close,
- contentDescription = R.string.remove_tab_from_collection
- ) {
- interactor.onCollectionRemoveTab(collection, tab, wasSwiped = false)
- }
- }
-
- fun bindSession(collection: TabCollection, tab: ComponentTab, isLastTab: Boolean) {
- this.collection = collection
- this.tab = tab
- this.isLastItem = isLastTab
- updateTabUI()
- }
-
- private fun updateTabUI() {
- view.setText(
- label = tab.title,
- caption = tab.url.toShortUrl(publicSuffixList)
- )
-
- icons.loadIntoView(view.iconView, tab.url)
-
- // If last item and we want to change UI for it
- val context = view.context
- if (isLastItem) {
- view.background = AppCompatResources.getDrawable(context, R.drawable.rounded_bottom_corners)
- } else {
- view.setBackgroundColor(context.getColorFromAttr(R.attr.layer2))
- }
- }
-
- companion object {
- const val LAYOUT_ID = R.layout.site_list_item
- }
-}
diff --git a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsTouchHelper.kt b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsTouchHelper.kt
index 41041350c..49825d270 100644
--- a/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsTouchHelper.kt
+++ b/app/src/main/java/org/mozilla/fenix/tabstray/browser/TabsTouchHelper.kt
@@ -17,7 +17,6 @@ import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.content.getDrawableWithTint
import mozilla.components.support.ktx.android.util.dpToPx
import org.mozilla.fenix.R
-import org.mozilla.fenix.home.sessioncontrol.SwipeToDeleteCallback
/**
* A callback for consumers to know when a [RecyclerView.ViewHolder] is about to be touched.
@@ -95,7 +94,7 @@ class TouchCallback(
val iconLeft: Int
val iconRight: Int
val margin =
- SwipeToDeleteCallback.MARGIN.dpToPx(recyclerView.resources.displayMetrics)
+ MARGIN.dpToPx(recyclerView.resources.displayMetrics)
val iconWidth = icon.intrinsicWidth
val iconHeight = icon.intrinsicHeight
val cellHeight = itemView.bottom - itemView.top
@@ -108,7 +107,7 @@ class TouchCallback(
iconRight = itemView.left + margin + iconWidth
background.setBounds(
itemView.left, itemView.top,
- (itemView.left + dX).toInt() + SwipeToDeleteCallback.BACKGROUND_CORNER_OFFSET,
+ (itemView.left + dX).toInt() + BACKGROUND_CORNER_OFFSET,
itemView.bottom
)
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
@@ -118,7 +117,7 @@ class TouchCallback(
iconLeft = itemView.right - margin - iconWidth
iconRight = itemView.right - margin
background.setBounds(
- (itemView.right + dX).toInt() - SwipeToDeleteCallback.BACKGROUND_CORNER_OFFSET,
+ (itemView.right + dX).toInt() - BACKGROUND_CORNER_OFFSET,
itemView.top, itemView.right, itemView.bottom
)
icon.setBounds(iconLeft, iconTop, iconRight, iconBottom)
@@ -139,4 +138,9 @@ class TouchCallback(
background.draw(c)
icon.draw(c)
}
+
+ companion object {
+ const val BACKGROUND_CORNER_OFFSET = 40
+ const val MARGIN = 32
+ }
}
diff --git a/app/src/main/res/drawable/session_background.xml b/app/src/main/res/drawable/session_background.xml
deleted file mode 100644
index a53dd3768..000000000
--- a/app/src/main/res/drawable/session_background.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/tab_in_collection_last_swipe_background.xml b/app/src/main/res/drawable/tab_in_collection_last_swipe_background.xml
deleted file mode 100644
index 983fbdc22..000000000
--- a/app/src/main/res/drawable/tab_in_collection_last_swipe_background.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
diff --git a/app/src/main/res/drawable/tab_in_collection_swipe_background.xml b/app/src/main/res/drawable/tab_in_collection_swipe_background.xml
deleted file mode 100644
index fcc47f735..000000000
--- a/app/src/main/res/drawable/tab_in_collection_swipe_background.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index cb2a676cb..f0333bebf 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -76,7 +76,6 @@
60dp
- 5dp
16dp
diff --git a/detekt-baseline.xml b/detekt-baseline.xml
index 53a7d694c..d676235bf 100644
--- a/detekt-baseline.xml
+++ b/detekt-baseline.xml
@@ -458,7 +458,6 @@
UndocumentedPublicClass:SupportUtils.kt$SupportUtils
UndocumentedPublicClass:SupportUtils.kt$SupportUtils$MozillaPage
UndocumentedPublicClass:SupportUtils.kt$SupportUtils$SumoTopic
- UndocumentedPublicClass:SwipeToDeleteCallback.kt$SwipeToDeleteCallback : SimpleCallback
UndocumentedPublicClass:SwitchWithDescription.kt$SwitchWithDescription : ConstraintLayout
UndocumentedPublicClass:Tab.kt$Tab
UndocumentedPublicClass:TabCollectionStorage.kt$TabCollectionStorage : Observable