You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
iceraven-browser/app/src/main/java/org/mozilla/fenix/home/pocket/PocketStoriesViewHolder.kt

127 lines
5.2 KiB
Kotlin

/* 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.pocket
import android.view.View
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.lib.state.ext.observeAsComposableState
import mozilla.components.service.pocket.PocketStory.PocketRecommendedStory
import org.mozilla.fenix.R
import org.mozilla.fenix.components.components
import org.mozilla.fenix.compose.ComposeViewHolder
import org.mozilla.fenix.compose.home.HomeSectionHeader
import org.mozilla.fenix.theme.FirefoxTheme
import org.mozilla.fenix.wallpapers.WallpaperState
/**
* [RecyclerView.ViewHolder] for displaying the list of [PocketRecommendedStory]s from [AppStore].
*
* @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 [PocketStoriesInteractor] callback for user interaction.
*/
class PocketStoriesViewHolder(
composeView: ComposeView,
viewLifecycleOwner: LifecycleOwner,
private val interactor: PocketStoriesInteractor,
) : ComposeViewHolder(composeView, viewLifecycleOwner) {
companion object {
val LAYOUT_ID = View.generateViewId()
}
@Composable
override fun Content() {
val horizontalPadding = dimensionResource(R.dimen.home_item_horizontal_margin)
val homeScreenReady = components.appStore
.observeAsComposableState { state -> state.firstFrameDrawn }.value ?: false
val stories = components.appStore
.observeAsComposableState { state -> state.pocketStories }.value
val wallpaperState = components.appStore
.observeAsComposableState { state -> state.wallpaperState }.value ?: WallpaperState.default
/* This was originally done to address this perf issue:
* https://github.com/mozilla-mobile/fenix/issues/25545 for details.
* It was determined that Pocket content was becoming available before the first frame was
* rendered more regularly. Including Pocket in the first render pass significantly
* increases time-to-render in lower-end devices. By waiting until the first frame has
* rendered, the perceived performance should increase since the app becomes active more
* quickly. This was intended as a workaround until the Compose upgrade was completed and a
* more robust solution could be investigated.
*/
if (!homeScreenReady) return
LaunchedEffect(stories) {
// We should report back when a certain story is actually being displayed.
// Cannot do it reliably so for now we'll just mass report everything as being displayed.
stories?.let {
// Only report here the impressions for recommended stories.
// Sponsored stories use a different API for more accurate tracking.
interactor.onStoriesShown(it.filterIsInstance<PocketRecommendedStory>())
}
}
Column(modifier = Modifier.padding(top = 72.dp)) {
// Simple wrapper to add horizontal padding to just the header while the stories have none.
Box(modifier = Modifier.padding(horizontal = horizontalPadding)) {
HomeSectionHeader(
headerText = stringResource(R.string.pocket_stories_header_1),
)
}
Spacer(Modifier.height(16.dp))
PocketStories(
stories = stories ?: emptyList(),
contentPadding = horizontalPadding,
backgroundColor = wallpaperState.wallpaperCardColor,
onStoryShown = interactor::onStoryShown,
onStoryClicked = interactor::onStoryClicked,
onDiscoverMoreClicked = interactor::onDiscoverMoreClicked,
)
}
}
}
@Composable
@Preview
fun PocketStoriesViewHolderPreview() {
FirefoxTheme {
Column {
HomeSectionHeader(
headerText = stringResource(R.string.pocket_stories_header_1),
)
Spacer(Modifier.height(16.dp))
@Suppress("MagicNumber")
PocketStories(
stories = getFakePocketStories(8),
contentPadding = 0.dp,
backgroundColor = FirefoxTheme.colors.layer2,
onStoryShown = { _, _ -> },
onStoryClicked = { _, _ -> },
onDiscoverMoreClicked = {},
)
}
}
}