From 7185eee3df9f7d359a3b22202535b39d15286fbd Mon Sep 17 00:00:00 2001 From: Mugurell Date: Tue, 26 Apr 2022 19:10:39 +0300 Subject: [PATCH] [fenix] For https://github.com/mozilla-mobile/fenix/issues/24333 - Replace the xml based CollectionViewHolder with a composable --- .../fenix/components/TabCollectionStorage.kt | 7 +- .../fenix/home/collections/Collection.kt | 226 ++++++++++++++++++ .../fenix/home/collections/CollectionMenu.kt | 210 ++++++++++++++++ .../home/collections/CollectionViewHolder.kt | 207 ++++++---------- .../sessioncontrol/SessionControlAdapter.kt | 13 +- .../res/layout/collection_home_list_row.xml | 98 -------- 6 files changed, 529 insertions(+), 232 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt create mode 100644 app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt delete mode 100644 app/src/main/res/layout/collection_home_list_row.xml diff --git a/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt b/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt index 20d669131f..530157b8c1 100644 --- a/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt +++ b/app/src/main/java/org/mozilla/fenix/components/TabCollectionStorage.kt @@ -21,9 +21,10 @@ import mozilla.components.support.base.observer.Observable import mozilla.components.support.base.observer.ObserverRegistry import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.toShortUrl -import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder import org.mozilla.fenix.perf.StrictModeManager +private const val COLLECTION_MAX_TITLE_LENGTH = 20 + class TabCollectionStorage( private val context: Context, strictMode: StrictModeManager, @@ -106,10 +107,10 @@ fun TabCollection.description(context: Context): String { return this.tabs .map { it.url.toShortUrl(context.components.publicSuffixList) } .map { - if (it.length > CollectionViewHolder.maxTitleLength) { + if (it.length > COLLECTION_MAX_TITLE_LENGTH) { it.substring( 0, - CollectionViewHolder.maxTitleLength + COLLECTION_MAX_TITLE_LENGTH ) + "…" } else { it 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 new file mode 100644 index 0000000000..7be997890b --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/home/collections/Collection.kt @@ -0,0 +1,226 @@ +/* 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.clickable +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +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.Icon +import androidx.compose.material.IconButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.BlendMode +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.tooling.preview.Preview +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 mozilla.components.feature.tab.collections.TabCollection +import org.mozilla.fenix.R.drawable +import org.mozilla.fenix.R.string +import org.mozilla.fenix.compose.list.ExpandableListHeader +import org.mozilla.fenix.ext.getIconColor +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.theme.Theme + +/** + * Rectangular shape with all corners rounded used to display a collapsed collection. + */ +private val collapsedCollectionShape = RoundedCornerShape(8.dp) + +/** + * Rectangular shape with only the top corners rounded used to display an expanded collection with other views + * placed immediately below this which can be shown immediately next to it, with no visible separation. + */ +private val expandedCollectionShape = RoundedCornerShape(topStart = 8.dp, topEnd = 8.dp) + +/** + * Displays an individual [TabCollection]. + * + * @param collection [TabCollection] to display. + * @param expanded Whether the collection is expanded to show it's containing tabs or not. + * @param menuItems List of [CollectionMenuItem] to be shown in a menu. + * @param onToggleCollectionExpanded Invoked when the user clicks on the collection. + * @param onCollectionShareTabsClicked Invoked when the user clicks to share the collection. + * @param onCollectionMenuOpened Invoked when the user clicks to open a menu for the collection. + */ +@Composable +@Suppress("LongParameterList") +fun Collection( + collection: TabCollection, + expanded: Boolean, + menuItems: List, + onToggleCollectionExpanded: (TabCollection, Boolean) -> Unit, + onCollectionShareTabsClicked: (TabCollection) -> Unit, + onCollectionMenuOpened: () -> Unit, +) { + var isMenuExpanded by remember(collection) { mutableStateOf(false) } + val isExpanded by remember(collection) { mutableStateOf(expanded) } + + Card( + modifier = Modifier + .semantics(mergeDescendants = true) {} + .clickable { onToggleCollectionExpanded(collection, !isExpanded) } + .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. + ) { + Row( + modifier = Modifier + .fillMaxHeight(), + verticalAlignment = Alignment.CenterVertically, + ) { + Icon( + painter = painterResource(drawable.ic_tab_collection), + contentDescription = null, + modifier = Modifier.padding( + start = 16.dp, + end = 8.dp // (24.dp - 16.dp) hardcoded in ExpandableListHeader + ), + tint = Paint().apply { + color = Color(collection.getIconColor(LocalContext.current)) + blendMode = BlendMode.SrcIn + }.color, + ) + + ExpandableListHeader( + headerText = collection.title, + expanded = isExpanded, + ) { + if (isExpanded) { + Row { + IconButton( + onClick = { onCollectionShareTabsClicked(collection) } + ) { + Icon( + painter = painterResource(drawable.ic_share), + contentDescription = stringResource(string.share_button_content_description), + tint = FirefoxTheme.colors.iconPrimary, + ) + } + + IconButton( + onClick = { + isMenuExpanded = !isMenuExpanded + onCollectionMenuOpened() + } + ) { + Icon( + painter = painterResource(drawable.ic_menu), + contentDescription = stringResource( + string.collection_menu_button_content_description + ), + tint = FirefoxTheme.colors.iconPrimary, + ) + + CollectionMenu( + showMenu = isMenuExpanded, + menuItems = menuItems, + onDismissRequest = { isMenuExpanded = false }, + ) + } + } + } + } + } + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun CollectionDarkPreview() { + FirefoxTheme(Theme.Dark) { + Collection( + collection = collectionPreview, + expanded = false, + menuItems = emptyList(), + onToggleCollectionExpanded = { _, _ -> }, + onCollectionShareTabsClicked = {}, + onCollectionMenuOpened = {}, + ) + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun CollectionDarkExpandedPreview() { + FirefoxTheme(Theme.Dark) { + Collection( + collection = collectionPreview, + expanded = true, + menuItems = emptyList(), + onToggleCollectionExpanded = { _, _ -> }, + onCollectionShareTabsClicked = {}, + onCollectionMenuOpened = {}, + ) + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun CollectionLightPreview() { + FirefoxTheme(Theme.Light) { + Collection( + collection = collectionPreview, + expanded = false, + menuItems = emptyList(), + onToggleCollectionExpanded = { _, _ -> }, + onCollectionShareTabsClicked = {}, + onCollectionMenuOpened = {}, + ) + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun CollectionLightExpandedPreview() { + FirefoxTheme(Theme.Light) { + Collection( + collection = collectionPreview, + expanded = true, + menuItems = emptyList(), + onToggleCollectionExpanded = { _, _ -> }, + onCollectionShareTabsClicked = {}, + onCollectionMenuOpened = {}, + ) + } +} + +private val collectionPreview = object : TabCollection { + override val id: Long = 1L + override val tabs: List = emptyList() + override val title: String = "Collection 1" + + override fun restore( + context: Context, + engine: Engine, + restoreSessionId: Boolean, + ): List = emptyList() + + override fun restoreSubset( + context: Context, + engine: Engine, + tabs: List, + restoreSessionId: Boolean, + ): List = emptyList() +} diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt new file mode 100644 index 0000000000..bfaf060770 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionMenu.kt @@ -0,0 +1,210 @@ +/* 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.background +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.Immutable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import mozilla.components.browser.state.selector.normalTabs +import mozilla.components.browser.state.state.recover.RecoverableTab +import mozilla.components.concept.engine.Engine +import mozilla.components.feature.tab.collections.Tab +import mozilla.components.feature.tab.collections.TabCollection +import org.mozilla.fenix.R.string +import org.mozilla.fenix.compose.inComposePreview +import org.mozilla.fenix.ext.components +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.theme.Theme + +/** + * Menu shown for a [org.mozilla.fenix.home.collections.Collection]. + * + * @see [DropdownMenu] + * + * @param showMenu Whether this is currently open and visible to the user. + * @param menuItems List of options shown. + * @param onDismissRequest Called when the user chooses a menu option or requests to dismiss the menu. + */ +@Composable +fun CollectionMenu( + showMenu: Boolean, + menuItems: List, + onDismissRequest: () -> Unit, +) { + DisposableEffect(LocalConfiguration.current.orientation) { + onDispose { onDismissRequest() } + } + + // DropdownMenu uses the medium shape from MaterialTheme. + // Override it's corner radius to be the same 8.dp as in mozac_browser_menu_corner_radius + MaterialTheme(shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(8.dp))) { + DropdownMenu( + expanded = showMenu, + onDismissRequest = { onDismissRequest() }, + modifier = Modifier + .background(color = FirefoxTheme.colors.layer2), + ) { + for (item in menuItems) { + DropdownMenuItem( + onClick = { + onDismissRequest() + item.onClick() + }, + ) { + Text( + text = item.title, + color = item.color, + maxLines = 1, + modifier = Modifier + .fillMaxHeight() + .align(Alignment.CenterVertically) + ) + } + } + } + } +} + +/** + * A menu item for collections. + * + * @property title The menu item title. + * @property color The color that should be set for the title. + * @property onClick Invoked when the user clicks on the menu item. + */ +@Immutable +data class CollectionMenuItem( + val title: String, + val color: Color, + val onClick: () -> Unit, +) + +/** + * Constructs and returns the default list of menu options for a [TabCollection]. + * + * @param collection [TabCollection] for which the menu will be shown. + * Might serve as an argument for the callbacks for when the user interacts with certain menu options. + * @param onOpenTabsTapped Invoked when the user chooses to open the tabs from [collection]. + * @param onRenameCollectionTapped Invoked when the user chooses to rename the [collection]. + * @param onAddTabTapped Invoked when the user chooses to add tabs to [collection]. + * @param onDeleteCollectionTapped Invoked when the user chooses to delete [collection]. + */ +@Composable +fun getMenuItems( + collection: TabCollection, + onOpenTabsTapped: (TabCollection) -> Unit, + onRenameCollectionTapped: (TabCollection) -> Unit, + onAddTabTapped: (TabCollection) -> Unit, + onDeleteCollectionTapped: (TabCollection) -> Unit, +): List { + return listOfNotNull( + CollectionMenuItem( + title = stringResource(string.collection_open_tabs), + color = FirefoxTheme.colors.textPrimary + ) { + onOpenTabsTapped(collection) + }, + CollectionMenuItem( + title = stringResource(string.collection_rename), + color = FirefoxTheme.colors.textPrimary + ) { + onRenameCollectionTapped(collection) + }, + + if (hasOpenTabs()) { + CollectionMenuItem( + title = stringResource(string.add_tab), + color = FirefoxTheme.colors.textPrimary + ) { + onAddTabTapped(collection) + } + } else { + null + }, + + CollectionMenuItem( + title = stringResource(string.collection_delete), + color = FirefoxTheme.colors.textWarning + ) { + onDeleteCollectionTapped(collection) + }, + ) +} + +@Composable +private fun hasOpenTabs() = when (inComposePreview) { + true -> true + false -> LocalContext.current.components.core.store.state.normalTabs.isNotEmpty() +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +private fun CollectionMenuDarkPreview() { + FirefoxTheme(Theme.Dark) { + CollectionMenu( + showMenu = true, + menuItems = getMenuItems( + collection = collectionPreview, + onOpenTabsTapped = {}, + onRenameCollectionTapped = {}, + onAddTabTapped = {}, + onDeleteCollectionTapped = {} + ), + ) {} + } +} + +@Composable +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +private fun CollectionMenuLightPreview() { + FirefoxTheme(Theme.Light) { + CollectionMenu( + showMenu = true, + menuItems = getMenuItems( + collection = collectionPreview, + onOpenTabsTapped = {}, + onRenameCollectionTapped = {}, + onAddTabTapped = {}, + onDeleteCollectionTapped = {} + ), + ) {} + } +} + +private val collectionPreview = object : TabCollection { + override val id: Long = 1L + override val tabs: List = emptyList() + override val title: String = "Collection 1" + + override fun restore( + context: Context, + engine: Engine, + restoreSessionId: Boolean, + ): List = emptyList() + + override fun restoreSubset( + context: Context, + engine: Engine, + tabs: List, + restoreSessionId: Boolean, + ): List = emptyList() +} diff --git a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt index 810cdc03ad..c22f56ac30 100644 --- a/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/collections/CollectionViewHolder.kt @@ -2,154 +2,103 @@ * 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 +package org.mozilla.fenix.home.collections -import android.content.Context import android.view.View -import androidx.core.graphics.BlendModeColorFilterCompat.createBlendModeColorFilterCompat -import androidx.core.graphics.BlendModeCompat.SRC_IN -import mozilla.components.browser.menu.BrowserMenuBuilder -import mozilla.components.browser.menu.item.SimpleBrowserMenuItem -import mozilla.components.browser.state.selector.normalTabs +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.unit.dp +import androidx.lifecycle.LifecycleOwner +import androidx.recyclerview.widget.RecyclerView import mozilla.components.feature.tab.collections.TabCollection import org.mozilla.fenix.R -import org.mozilla.fenix.databinding.CollectionHomeListRowBinding -import org.mozilla.fenix.utils.view.ViewHolder -import org.mozilla.fenix.ext.components -import org.mozilla.fenix.ext.getIconColor -import org.mozilla.fenix.ext.increaseTapArea -import org.mozilla.fenix.ext.removeAndDisable -import org.mozilla.fenix.ext.removeTouchDelegate -import org.mozilla.fenix.ext.showAndEnable +import org.mozilla.fenix.compose.ComposeViewHolder import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor -import org.mozilla.fenix.theme.ThemeManager +/** + * [RecyclerView.ViewHolder] for displaying an individual [TabCollection]. + * Clients are expected to use [bindSession] to link a particular [TabCollection] 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 CollectionViewHolder( - view: View, - val interactor: CollectionInteractor -) : ViewHolder(view) { - - private lateinit var collection: TabCollection - private var expanded = false - private var collectionMenu: CollectionItemMenu - private var binding: CollectionHomeListRowBinding + composeView: ComposeView, + viewLifecycleOwner: LifecycleOwner, + private val interactor: CollectionInteractor, +) : ComposeViewHolder(composeView, viewLifecycleOwner) { + private var collectionData = CollectionInfo() init { - binding = CollectionHomeListRowBinding.bind(view) + val horizontalPadding = + composeView.resources.getDimensionPixelSize(R.dimen.home_item_horizontal_margin) + composeView.setPadding(horizontalPadding, 0, horizontalPadding, 0) + } - collectionMenu = CollectionItemMenu( - view.context, - { view.context.components.core.store.state.normalTabs.isNotEmpty() } - ) { - when (it) { - is CollectionItemMenu.Item.DeleteCollection -> interactor.onDeleteCollectionTapped(collection) - is CollectionItemMenu.Item.AddTab -> interactor.onCollectionAddTabTapped(collection) - is CollectionItemMenu.Item.RenameCollection -> interactor.onRenameCollectionTapped(collection) - is CollectionItemMenu.Item.OpenTabs -> interactor.onCollectionOpenTabsTapped(collection) + @Composable + override fun Content() { + val collectionInfo by remember { mutableStateOf(collectionData) } + + collectionInfo.collection?.let { collection -> + val menuItems = getMenuItems( + collection = collection, + onOpenTabsTapped = interactor::onCollectionOpenTabsTapped, + onRenameCollectionTapped = interactor::onRenameCollectionTapped, + onAddTabTapped = interactor::onCollectionAddTabTapped, + onDeleteCollectionTapped = interactor::onDeleteCollectionTapped, + ) + + Column { + Spacer(Modifier.height(12.dp)) + + Collection( + collection = collection, + expanded = collectionInfo.isExpanded, + menuItems = menuItems, + onToggleCollectionExpanded = interactor::onToggleCollectionExpanded, + onCollectionShareTabsClicked = interactor::onCollectionShareTabsClicked, + onCollectionMenuOpened = interactor::onCollectionMenuOpened, + ) } } - - binding.collectionOverflowButton.setOnClickListener { - interactor.onCollectionMenuOpened() - collectionMenu.menuBuilder - .build(view.context) - .show(anchor = it) - } - - binding.collectionShareButton.setOnClickListener { - interactor.onCollectionShareTabsClicked(collection) - } - - view.clipToOutline = true - view.setOnClickListener { - interactor.onToggleCollectionExpanded(collection, !expanded) - } } + /** + * Dynamically replace the current [TabCollection] shown in this `ViewHolder`. + * + * @param collection [TabCollection] to be shown + * @param expanded Whether to show the collection as expanded or collapsed. + */ fun bindSession(collection: TabCollection, expanded: Boolean) { - this.collection = collection - this.expanded = expanded - updateCollectionUI() - } - - private fun updateCollectionUI() { - binding.collectionTitle.text = collection.title - - itemView.isActivated = expanded - if (expanded) { - binding.collectionShareButton.apply { - showAndEnable() - increaseTapArea(buttonIncreaseDps) - } - binding.collectionOverflowButton.apply { - showAndEnable() - increaseTapArea(buttonIncreaseDps) - } - } else { - - binding.collectionShareButton.apply { - removeAndDisable() - removeTouchDelegate() - } - binding.collectionOverflowButton.apply { - removeAndDisable() - removeTouchDelegate() - } - } - - binding.collectionIcon.colorFilter = createBlendModeColorFilterCompat( - collection.getIconColor(itemView.context), - SRC_IN + collectionData = CollectionInfo( + collection = collection, + isExpanded = expanded ) } companion object { - const val buttonIncreaseDps = 16 - const val LAYOUT_ID = R.layout.collection_home_list_row - const val maxTitleLength = 20 + val LAYOUT_ID = View.generateViewId() } } -class CollectionItemMenu( - private val context: Context, - private val shouldShowAddTab: () -> Boolean, - private val onItemTapped: (Item) -> Unit = {} -) { - sealed class Item { - object DeleteCollection : Item() - object AddTab : Item() - object RenameCollection : Item() - object OpenTabs : Item() - } - - val menuBuilder by lazy { BrowserMenuBuilder(menuItems) } - - private val menuItems by lazy { - listOf( - SimpleBrowserMenuItem( - context.getString(R.string.collection_open_tabs) - ) { - onItemTapped.invoke(Item.OpenTabs) - }, - - SimpleBrowserMenuItem( - context.getString(R.string.collection_rename) - ) { - onItemTapped.invoke(Item.RenameCollection) - }, - - SimpleBrowserMenuItem( - context.getString(R.string.add_tab) - ) { - onItemTapped.invoke(Item.AddTab) - }.apply { visible = shouldShowAddTab }, - - SimpleBrowserMenuItem( - context.getString(R.string.collection_delete), - textColorResource = ThemeManager.resolveAttribute(R.attr.textWarning, context) - ) { - onItemTapped.invoke(Item.DeleteCollection) - } - ) - } -} +/** + * Wrapper over a [TabCollection] adding information about whether it should be shown as expanded or collapsed. + * + * @property collection [TabCollection] to display. + * @property isExpanded Whether the collection is expanded to show it's containing tabs or not. + */ +@Stable +private data class CollectionInfo( + val collection: TabCollection? = null, + val isExpanded: 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 26b45facd1..196b650e7d 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 @@ -20,6 +20,7 @@ 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.pocket.PocketCategoriesViewHolder import org.mozilla.fenix.home.pocket.PocketRecommendationsHeaderViewHolder import org.mozilla.fenix.home.pocket.PocketStoriesViewHolder @@ -30,7 +31,6 @@ import org.mozilla.fenix.home.recenttabs.view.RecentTabsHeaderViewHolder import org.mozilla.fenix.home.recentvisits.view.RecentVisitsHeaderViewHolder import org.mozilla.fenix.home.recentvisits.view.RecentlyVisitedViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder @@ -278,6 +278,11 @@ class SessionControlAdapter( viewLifecycleOwner = viewLifecycleOwner, interactor = interactor ) + CollectionViewHolder.LAYOUT_ID -> return CollectionViewHolder( + composeView = ComposeView(parent.context), + viewLifecycleOwner, + interactor = interactor + ) } val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) @@ -288,7 +293,6 @@ class SessionControlAdapter( viewLifecycleOwner = viewLifecycleOwner, interactor = interactor ) - CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor) TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder( view as WidgetSiteItemView, interactor @@ -335,6 +339,11 @@ class SessionControlAdapter( // This View already listens and maps store updates. Avoid creating and binding new Views. // The composition will live until the ViewTreeLifecycleOwner to which it's attached to is destroyed. } + is CollectionViewHolder -> { + // 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/res/layout/collection_home_list_row.xml b/app/src/main/res/layout/collection_home_list_row.xml deleted file mode 100644 index 61c711b739..0000000000 --- a/app/src/main/res/layout/collection_home_list_row.xml +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - -