mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-03 23:15:31 +00:00
For #23966 - Migrate MessageCardViewHolder to Compose
This commit is contained in:
parent
a3d930b5e2
commit
aea6124851
@ -25,9 +25,9 @@ private const val EXPECTED_SUPPRESSION_COUNT = 19
|
||||
@Suppress("TopLevelPropertyNaming") // it's silly this would have a different naming convention b/c no const
|
||||
private val EXPECTED_RUNBLOCKING_RANGE = 0..1 // CI has +1 counts compared to local runs: increment these together
|
||||
private val EXPECTED_RECYCLER_VIEW_CONSTRAINT_LAYOUT_CHILDREN =
|
||||
4..5 // The messaging framework is not deterministic and could add a +1 to the count
|
||||
3..4 // The messaging framework is not deterministic and could add a +1 to the count
|
||||
private val EXPECTED_NUMBER_OF_INFLATION =
|
||||
14..15 // The messaging framework is not deterministic and could add a +1 to the count
|
||||
13..14 // The messaging framework is not deterministic and could add a +1 to the count
|
||||
|
||||
private val failureMsgStrictMode = getErrorMessage(
|
||||
shortName = "StrictMode suppression",
|
||||
|
@ -72,7 +72,7 @@ fun CollectionsPlaceholder(
|
||||
modifier = Modifier.size(20.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.ic_close),
|
||||
painter = painterResource(R.drawable.mozac_ic_close_20),
|
||||
contentDescription = stringResource(
|
||||
R.string.remove_home_collection_placeholder_content_description
|
||||
),
|
||||
|
218
app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt
Normal file
218
app/src/main/java/org/mozilla/fenix/compose/MessageCard.kt
Normal file
@ -0,0 +1,218 @@
|
||||
/* 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.compose
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
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.ui.Modifier
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import org.mozilla.experiments.nimbus.StringHolder
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.compose.button.PrimaryButton
|
||||
import org.mozilla.fenix.gleanplumb.Message
|
||||
import org.mozilla.fenix.nimbus.MessageData
|
||||
import org.mozilla.fenix.nimbus.StyleData
|
||||
import org.mozilla.fenix.theme.FirefoxTheme
|
||||
import org.mozilla.fenix.theme.Theme
|
||||
|
||||
/**
|
||||
* Message Card.
|
||||
*
|
||||
* @param message [Message] that holds a representation of GleanPlum message from Nimbus.
|
||||
* @param onClick Invoked when user clicks on the message card.
|
||||
* @param onCloseButtonClick Invoked when user clicks on close button to remove message.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun MessageCard(
|
||||
message: Message,
|
||||
onClick: () -> Unit,
|
||||
onCloseButtonClick: () -> Unit,
|
||||
) {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.padding(vertical = 16.dp)
|
||||
.then(
|
||||
if (message.data.buttonLabel.isNullOrBlank()) {
|
||||
Modifier.clickable(onClick = onClick)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
backgroundColor = FirefoxTheme.colors.layer2,
|
||||
) {
|
||||
Column(
|
||||
Modifier
|
||||
.padding(all = 16.dp)
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
val title = message.data.title
|
||||
if (!title.isNullOrBlank()) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
SectionHeader(
|
||||
text = title,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
)
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier.size(20.dp),
|
||||
onClick = onCloseButtonClick
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.mozac_ic_close_20),
|
||||
contentDescription = stringResource(
|
||||
R.string.content_description_close_button
|
||||
),
|
||||
tint = FirefoxTheme.colors.iconPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
PrimaryText(
|
||||
text = message.data.text,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
} else {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
PrimaryText(
|
||||
text = message.data.text,
|
||||
modifier = Modifier.weight(1f),
|
||||
fontSize = 14.sp
|
||||
)
|
||||
|
||||
IconButton(
|
||||
modifier = Modifier.size(20.dp),
|
||||
onClick = onCloseButtonClick
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(R.drawable.mozac_ic_close_20),
|
||||
contentDescription = stringResource(
|
||||
R.string.content_description_close_button
|
||||
),
|
||||
tint = FirefoxTheme.colors.iconPrimary
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!message.data.buttonLabel.isNullOrBlank()) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
PrimaryButton(
|
||||
text = stringResource(R.string.preferences_set_as_default_browser),
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun MessageCardPreview() {
|
||||
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
|
||||
Box(Modifier.background(FirefoxTheme.colors.layer1)) {
|
||||
MessageCard(
|
||||
message = Message(
|
||||
id = "end-",
|
||||
data = MessageData(
|
||||
title = StringHolder(
|
||||
R.string.bookmark_empty_title_error,
|
||||
"Title"
|
||||
),
|
||||
text = StringHolder(
|
||||
R.string.default_browser_experiment_card_text, "description"
|
||||
)
|
||||
),
|
||||
action = "action",
|
||||
style = StyleData(),
|
||||
triggers = listOf("trigger"),
|
||||
metadata = Message.Metadata("end-")
|
||||
),
|
||||
onClick = {},
|
||||
onCloseButtonClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun MessageCardWithoutTitlePreview() {
|
||||
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
|
||||
Box(Modifier.background(FirefoxTheme.colors.layer1)) {
|
||||
MessageCard(
|
||||
message = Message(
|
||||
id = "end-",
|
||||
data = MessageData(
|
||||
text = StringHolder(
|
||||
R.string.default_browser_experiment_card_text, "description"
|
||||
)
|
||||
),
|
||||
action = "action",
|
||||
style = StyleData(),
|
||||
triggers = listOf("trigger"),
|
||||
metadata = Message.Metadata("end-")
|
||||
),
|
||||
onClick = {},
|
||||
onCloseButtonClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Preview
|
||||
private fun MessageCardWithButtonLabelPreview() {
|
||||
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
|
||||
Box(Modifier.background(FirefoxTheme.colors.layer1)) {
|
||||
MessageCard(
|
||||
message = Message(
|
||||
id = "end-",
|
||||
data = MessageData(
|
||||
buttonLabel = StringHolder(R.string.preferences_set_as_default_browser, ""),
|
||||
title = StringHolder(
|
||||
R.string.bookmark_empty_title_error,
|
||||
"Title"
|
||||
),
|
||||
text = StringHolder(
|
||||
R.string.default_browser_experiment_card_text, "description"
|
||||
)
|
||||
),
|
||||
action = "action",
|
||||
style = StyleData(),
|
||||
triggers = listOf("trigger"),
|
||||
metadata = Message.Metadata("end-")
|
||||
),
|
||||
onClick = {},
|
||||
onCloseButtonClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -293,6 +293,11 @@ class SessionControlAdapter(
|
||||
viewLifecycleOwner = viewLifecycleOwner,
|
||||
interactor = interactor,
|
||||
)
|
||||
MessageCardViewHolder.LAYOUT_ID -> return MessageCardViewHolder(
|
||||
composeView = ComposeView(parent.context),
|
||||
viewLifecycleOwner = viewLifecycleOwner,
|
||||
interactor = interactor
|
||||
)
|
||||
}
|
||||
|
||||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||
@ -318,7 +323,6 @@ class SessionControlAdapter(
|
||||
OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder(
|
||||
view
|
||||
)
|
||||
MessageCardViewHolder.LAYOUT_ID -> MessageCardViewHolder(view, interactor)
|
||||
BottomSpacerViewHolder.LAYOUT_ID -> BottomSpacerViewHolder(view)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
@ -328,6 +332,7 @@ class SessionControlAdapter(
|
||||
when (holder) {
|
||||
is CollectionHeaderViewHolder,
|
||||
is CustomizeHomeButtonViewHolder,
|
||||
is MessageCardViewHolder,
|
||||
is NoCollectionsMessageViewHolder,
|
||||
is RecentlyVisitedViewHolder,
|
||||
is RecentVisitsHeaderViewHolder,
|
||||
@ -390,9 +395,6 @@ class SessionControlAdapter(
|
||||
is TopSitePagerViewHolder -> {
|
||||
holder.bind((item as AdapterItem.TopSitePager).topSites)
|
||||
}
|
||||
is MessageCardViewHolder -> {
|
||||
holder.bind((item as AdapterItem.NimbusMessageCard).message)
|
||||
}
|
||||
is CollectionViewHolder -> {
|
||||
val (collection, expanded) = item as AdapterItem.CollectionItem
|
||||
holder.bindSession(collection, expanded)
|
||||
|
@ -5,53 +5,53 @@
|
||||
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
|
||||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import mozilla.components.lib.state.ext.observeAsComposableState
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.databinding.NimbusMessageCardBinding
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.gleanplumb.Message
|
||||
import org.mozilla.fenix.components.components
|
||||
import org.mozilla.fenix.compose.ComposeViewHolder
|
||||
import org.mozilla.fenix.compose.MessageCard
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlInteractor
|
||||
|
||||
/**
|
||||
* View holder for the Nimbus Message Card.
|
||||
*
|
||||
* @property interactor [SessionControlInteractor] which will have delegated to all user
|
||||
* interactions.
|
||||
*/
|
||||
class MessageCardViewHolder(
|
||||
view: View,
|
||||
private val interactor: SessionControlInteractor
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(message: Message) {
|
||||
val binding = NimbusMessageCardBinding.bind(itemView)
|
||||
|
||||
if (message.data.title.isNullOrBlank()) {
|
||||
binding.titleText.isVisible = false
|
||||
} else {
|
||||
binding.titleText.text = message.data.title
|
||||
}
|
||||
|
||||
binding.descriptionText.text = message.data.text
|
||||
|
||||
if (message.data.buttonLabel.isNullOrBlank()) {
|
||||
binding.messageButton.isVisible = false
|
||||
binding.experimentCard.setOnClickListener {
|
||||
interactor.onMessageClicked(message)
|
||||
}
|
||||
} else {
|
||||
binding.messageButton.text = message.data.buttonLabel
|
||||
binding.messageButton.setOnClickListener {
|
||||
interactor.onMessageClicked(message)
|
||||
}
|
||||
}
|
||||
|
||||
binding.close.apply {
|
||||
increaseTapArea(CLOSE_BUTTON_EXTRA_DPS)
|
||||
setOnClickListener {
|
||||
interactor.onMessageClosedClicked(message)
|
||||
}
|
||||
}
|
||||
interactor.onMessageDisplayed(message)
|
||||
}
|
||||
composeView: ComposeView,
|
||||
viewLifecycleOwner: LifecycleOwner,
|
||||
private val interactor: SessionControlInteractor,
|
||||
) : ComposeViewHolder(composeView, viewLifecycleOwner) {
|
||||
|
||||
companion object {
|
||||
internal const val LAYOUT_ID = R.layout.nimbus_message_card
|
||||
private const val CLOSE_BUTTON_EXTRA_DPS = 38
|
||||
internal val LAYOUT_ID = View.generateViewId()
|
||||
}
|
||||
|
||||
init {
|
||||
val horizontalPadding =
|
||||
composeView.resources.getDimensionPixelSize(R.dimen.home_item_horizontal_margin)
|
||||
composeView.setPadding(horizontalPadding, 0, horizontalPadding, 0)
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val messaging = components.appStore.observeAsComposableState { state -> state.messaging }
|
||||
val message = messaging.value?.messageToShow
|
||||
|
||||
message?.let {
|
||||
MessageCard(
|
||||
message = it,
|
||||
onClick = { interactor.onMessageClicked(message) },
|
||||
onCloseButtonClick = { interactor.onMessageClosedClicked(message) }
|
||||
)
|
||||
}
|
||||
|
||||
if (message != null) {
|
||||
interactor.onMessageDisplayed(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,58 +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/. -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/experiment_card"
|
||||
style="@style/OnboardingCardLightWithPadding"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/home_item_horizontal_margin">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
tools:text="Title"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:textAppearance="@style/Header16TextStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/close"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/description_text" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/close"
|
||||
android:layout_width="10dp"
|
||||
android:layout_height="10dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/content_description_close_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/description_text"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_close"
|
||||
tools:srcCompat="@drawable/ic_close" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/default_browser_experiment_card_text"
|
||||
android:textAppearance="@style/Body14TextStyle"
|
||||
app:layout_constraintBottom_toTopOf="@id/message_button"
|
||||
app:layout_constraintEnd_toStartOf="@id/close"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/title_text" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/message_button"
|
||||
style="@style/PositiveButton"
|
||||
android:layout_height="36dp"
|
||||
android:background="@drawable/rounded_button_background"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="@string/preferences_set_as_default_browser"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/description_text" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user