For #24316 - Migrate TabInCollectionViewHolder to Compose

pull/543/head
Mugurell 2 years ago committed by mergify[bot]
parent 30fa80151d
commit a93e434f0d

@ -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

@ -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
}

@ -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,
)

@ -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)
}
}

@ -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)
}
}

@ -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)
}
}
}

@ -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
}
}

@ -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
}
}

@ -1,10 +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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="@dimen/tab_corner_radius" />
<solid android:color="?layer3" />
</shape>

@ -1,10 +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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:bottomLeftRadius="@dimen/tab_corner_radius" android:bottomRightRadius="@dimen/tab_corner_radius" />
<solid android:color="?layer3" />
</shape>

@ -1,9 +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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?layer3" />
</shape>

@ -76,7 +76,6 @@
<!-- Home Fragment -->
<dimen name="home_fragment_top_toolbar_header_margin">60dp</dimen>
<dimen name="home_item_elevation">5dp</dimen>
<dimen name="home_item_horizontal_margin">16dp</dimen>
<!-- Browser Fragment -->

@ -458,7 +458,6 @@
<ID>UndocumentedPublicClass:SupportUtils.kt$SupportUtils</ID>
<ID>UndocumentedPublicClass:SupportUtils.kt$SupportUtils$MozillaPage</ID>
<ID>UndocumentedPublicClass:SupportUtils.kt$SupportUtils$SumoTopic</ID>
<ID>UndocumentedPublicClass:SwipeToDeleteCallback.kt$SwipeToDeleteCallback : SimpleCallback</ID>
<ID>UndocumentedPublicClass:SwitchWithDescription.kt$SwitchWithDescription : ConstraintLayout</ID>
<ID>UndocumentedPublicClass:Tab.kt$Tab</ID>
<ID>UndocumentedPublicClass:TabCollectionStorage.kt$TabCollectionStorage : Observable</ID>

Loading…
Cancel
Save