|
|
|
@ -31,6 +31,7 @@ import androidx.compose.runtime.mutableStateOf
|
|
|
|
|
import androidx.compose.runtime.remember
|
|
|
|
|
import androidx.compose.runtime.setValue
|
|
|
|
|
import androidx.compose.ui.Alignment
|
|
|
|
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
|
import androidx.compose.ui.composed
|
|
|
|
|
import androidx.compose.ui.graphics.Color
|
|
|
|
@ -44,6 +45,8 @@ import androidx.compose.ui.platform.LocalView
|
|
|
|
|
import androidx.compose.ui.res.painterResource
|
|
|
|
|
import androidx.compose.ui.res.stringResource
|
|
|
|
|
import androidx.compose.ui.semantics.semantics
|
|
|
|
|
import androidx.compose.ui.semantics.testTag
|
|
|
|
|
import androidx.compose.ui.semantics.testTagsAsResourceId
|
|
|
|
|
import androidx.compose.ui.text.style.TextDecoration
|
|
|
|
|
import androidx.compose.ui.text.style.TextOverflow
|
|
|
|
|
import androidx.compose.ui.tooling.preview.Preview
|
|
|
|
@ -101,6 +104,7 @@ private val placeholderStory = PocketRecommendedStory("", "", "", "", "", 0, 0)
|
|
|
|
|
* @param backgroundColor The background [Color] of the story.
|
|
|
|
|
* @param onStoryClick Callback for when the user taps on this story.
|
|
|
|
|
*/
|
|
|
|
|
@OptIn(ExperimentalComposeUiApi::class)
|
|
|
|
|
@Composable
|
|
|
|
|
fun PocketStory(
|
|
|
|
|
@PreviewParameter(PocketStoryProvider::class) story: PocketRecommendedStory,
|
|
|
|
@ -120,6 +124,10 @@ fun PocketStory(
|
|
|
|
|
title = {
|
|
|
|
|
Text(
|
|
|
|
|
text = story.title,
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.story.title"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textPrimary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 2,
|
|
|
|
@ -132,6 +140,10 @@ fun PocketStory(
|
|
|
|
|
} else if (isValidPublisher) {
|
|
|
|
|
Text(
|
|
|
|
|
text = story.publisher,
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.story.publisher"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textSecondary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 1,
|
|
|
|
@ -140,6 +152,10 @@ fun PocketStory(
|
|
|
|
|
} else if (isValidTimeToRead) {
|
|
|
|
|
Text(
|
|
|
|
|
text = "${story.timeToRead} min",
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.story.timeToRead"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textSecondary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 1,
|
|
|
|
@ -157,6 +173,7 @@ fun PocketStory(
|
|
|
|
|
* @param backgroundColor The background [Color] of the story.
|
|
|
|
|
* @param onStoryClick Callback for when the user taps on this story.
|
|
|
|
|
*/
|
|
|
|
|
@OptIn(ExperimentalComposeUiApi::class)
|
|
|
|
|
@Composable
|
|
|
|
|
fun PocketSponsoredStory(
|
|
|
|
|
story: PocketSponsoredStory,
|
|
|
|
@ -178,6 +195,10 @@ fun PocketSponsoredStory(
|
|
|
|
|
) {
|
|
|
|
|
Text(
|
|
|
|
|
text = story.title,
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.sponsoredStory.title"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textPrimary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 2,
|
|
|
|
@ -188,6 +209,10 @@ fun PocketSponsoredStory(
|
|
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
text = stringResource(R.string.pocket_stories_sponsor_indication),
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.sponsoredStory.identifier"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textSecondary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 1,
|
|
|
|
@ -198,6 +223,10 @@ fun PocketSponsoredStory(
|
|
|
|
|
|
|
|
|
|
Text(
|
|
|
|
|
text = story.sponsor,
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.sponsoredStory.sponsor"
|
|
|
|
|
},
|
|
|
|
|
color = FirefoxTheme.colors.textSecondary,
|
|
|
|
|
overflow = TextOverflow.Ellipsis,
|
|
|
|
|
maxLines = 1,
|
|
|
|
@ -219,6 +248,7 @@ fun PocketSponsoredStory(
|
|
|
|
|
* @param onStoryClicked Callback for when the user taps on a recommended story.
|
|
|
|
|
* @param onDiscoverMoreClicked Callback for when the user taps an element which contains an
|
|
|
|
|
*/
|
|
|
|
|
@OptIn(ExperimentalComposeUiApi::class)
|
|
|
|
|
@Suppress("LongParameterList")
|
|
|
|
|
@Composable
|
|
|
|
|
fun PocketStories(
|
|
|
|
@ -237,6 +267,10 @@ fun PocketStories(
|
|
|
|
|
val flingBehavior = EagerFlingBehavior(lazyRowState = listState)
|
|
|
|
|
|
|
|
|
|
LazyRow(
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.stories"
|
|
|
|
|
},
|
|
|
|
|
contentPadding = PaddingValues(horizontal = contentPadding),
|
|
|
|
|
state = listState,
|
|
|
|
|
flingBehavior = flingBehavior,
|
|
|
|
@ -381,6 +415,7 @@ private fun Rect.getIntersectPercentage(realSize: IntSize, other: Rect): Float {
|
|
|
|
|
* @param onCategoryClick Callback for when the user taps a category.
|
|
|
|
|
* @param modifier [Modifier] to be applied to the layout.
|
|
|
|
|
*/
|
|
|
|
|
@OptIn(ExperimentalComposeUiApi::class)
|
|
|
|
|
@Suppress("LongParameterList")
|
|
|
|
|
@Composable
|
|
|
|
|
fun PocketStoriesCategories(
|
|
|
|
@ -393,7 +428,12 @@ fun PocketStoriesCategories(
|
|
|
|
|
onCategoryClick: (PocketRecommendedStoriesCategory) -> Unit,
|
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
|
) {
|
|
|
|
|
Box(modifier = modifier) {
|
|
|
|
|
Box(
|
|
|
|
|
modifier = modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.categories"
|
|
|
|
|
},
|
|
|
|
|
) {
|
|
|
|
|
StaggeredHorizontalGrid(
|
|
|
|
|
horizontalItemsSpacing = 16.dp,
|
|
|
|
|
verticalItemsSpacing = 16.dp,
|
|
|
|
@ -424,6 +464,7 @@ fun PocketStoriesCategories(
|
|
|
|
|
* @param textColor [Color] to be applied to the text.
|
|
|
|
|
* @param linkTextColor [Color] of the link text.
|
|
|
|
|
*/
|
|
|
|
|
@OptIn(ExperimentalComposeUiApi::class)
|
|
|
|
|
@Composable
|
|
|
|
|
fun PoweredByPocketHeader(
|
|
|
|
|
onLearnMoreClicked: (String) -> Unit,
|
|
|
|
@ -437,7 +478,10 @@ fun PoweredByPocketHeader(
|
|
|
|
|
val linkEndIndex = linkStartIndex + link.length
|
|
|
|
|
|
|
|
|
|
Column(
|
|
|
|
|
modifier = modifier,
|
|
|
|
|
modifier = modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.header"
|
|
|
|
|
},
|
|
|
|
|
horizontalAlignment = Alignment.CenterHorizontally,
|
|
|
|
|
) {
|
|
|
|
|
Row(
|
|
|
|
@ -461,19 +505,32 @@ fun PoweredByPocketHeader(
|
|
|
|
|
R.string.pocket_stories_feature_title_2,
|
|
|
|
|
LocalContext.current.getString(R.string.pocket_product_name),
|
|
|
|
|
),
|
|
|
|
|
modifier = Modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.header.title"
|
|
|
|
|
},
|
|
|
|
|
color = textColor,
|
|
|
|
|
style = FirefoxTheme.typography.caption,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
ClickableSubstringLink(
|
|
|
|
|
text = text,
|
|
|
|
|
textColor = textColor,
|
|
|
|
|
linkTextColor = linkTextColor,
|
|
|
|
|
linkTextDecoration = TextDecoration.Underline,
|
|
|
|
|
clickableStartIndex = linkStartIndex,
|
|
|
|
|
clickableEndIndex = linkEndIndex,
|
|
|
|
|
Box(
|
|
|
|
|
modifier = modifier.semantics {
|
|
|
|
|
testTagsAsResourceId = true
|
|
|
|
|
testTag = "pocket.header.subtitle"
|
|
|
|
|
},
|
|
|
|
|
) {
|
|
|
|
|
onLearnMoreClicked("https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE")
|
|
|
|
|
ClickableSubstringLink(
|
|
|
|
|
text = text,
|
|
|
|
|
textColor = textColor,
|
|
|
|
|
linkTextColor = linkTextColor,
|
|
|
|
|
linkTextDecoration = TextDecoration.Underline,
|
|
|
|
|
clickableStartIndex = linkStartIndex,
|
|
|
|
|
clickableEndIndex = linkEndIndex,
|
|
|
|
|
) {
|
|
|
|
|
onLearnMoreClicked(
|
|
|
|
|
"https://www.mozilla.org/en-US/firefox/pocket/?$POCKET_FEATURE_UTM_KEY_VALUE",
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|