[fenix] For https://github.com/mozilla-mobile/fenix/pull/24455 - Migrate NoCollectionsMessageViewHolder to Compose
parent
d75322cbaf
commit
d2fa53ff1d
@ -0,0 +1,117 @@
|
|||||||
|
/* 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.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
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.semantics.semantics
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.unit.sp
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.compose.button.PrimaryButton
|
||||||
|
import org.mozilla.fenix.compose.ext.dashedBorder
|
||||||
|
import org.mozilla.fenix.theme.FirefoxTheme
|
||||||
|
import org.mozilla.fenix.theme.Theme
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [CollectionsPlaceholder] for displaying a message detailing the collections feature and
|
||||||
|
* allowing users to easily start creating their collection.
|
||||||
|
*
|
||||||
|
* @param showAddToCollectionButton Whether or not the "Add to Collection" button should be shown.
|
||||||
|
* @param onAddTabsToCollectionButtonClick Invoked when the user clicks on the "Add Tabs to Collection" button.
|
||||||
|
* @param onRemovePlaceholderClick Invoked when the user clicks on the close button to remove the Collections
|
||||||
|
* placeholder.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun CollectionsPlaceholder(
|
||||||
|
showAddToCollectionButton: Boolean,
|
||||||
|
onAddTabsToCollectionButtonClick: () -> Unit,
|
||||||
|
onRemovePlaceholderClick: () -> Unit,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.semantics(mergeDescendants = true) {}
|
||||||
|
.dashedBorder(
|
||||||
|
color = FirefoxTheme.colors.borderPrimary,
|
||||||
|
cornerRadius = 8.dp,
|
||||||
|
dashHeight = 2.dp,
|
||||||
|
dashWidth = 4.dp
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
SectionHeader(
|
||||||
|
text = stringResource(R.string.collections_header),
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
|
||||||
|
IconButton(
|
||||||
|
onClick = onRemovePlaceholderClick,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_close),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
R.string.remove_home_collection_placeholder_content_description
|
||||||
|
),
|
||||||
|
tint = FirefoxTheme.colors.iconPrimary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
SecondaryText(
|
||||||
|
text = stringResource(R.string.no_collections_description2),
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
fontSize = 14.sp
|
||||||
|
)
|
||||||
|
|
||||||
|
if (showAddToCollectionButton) {
|
||||||
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
|
|
||||||
|
PrimaryButton(
|
||||||
|
text = stringResource(R.string.tabs_menu_save_to_collection1),
|
||||||
|
icon = painterResource(R.drawable.ic_tab_collection),
|
||||||
|
onClick = onAddTabsToCollectionButtonClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
@Preview
|
||||||
|
private fun CollectionsPlaceholderPreview() {
|
||||||
|
FirefoxTheme(theme = Theme.getTheme(isPrivate = false)) {
|
||||||
|
Box(Modifier.background(FirefoxTheme.colors.layer1)) {
|
||||||
|
CollectionsPlaceholder(
|
||||||
|
showAddToCollectionButton = true,
|
||||||
|
onAddTabsToCollectionButtonClick = {},
|
||||||
|
onRemovePlaceholderClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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">
|
|
||||||
<stroke android:width="2dp" android:dashWidth="4dp" android:color="?borderPrimary" android:dashGap="4dp" />
|
|
||||||
<corners android:radius="8dp" />
|
|
||||||
</shape>
|
|
@ -1,69 +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"
|
|
||||||
android:id="@+id/no_collections_wrapper"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginHorizontal="@dimen/home_item_horizontal_margin"
|
|
||||||
android:layout_marginTop="40dp"
|
|
||||||
android:layout_marginBottom="12dp"
|
|
||||||
android:background="@drawable/empty_session_control_background"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="16dp">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_collections_header"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/collections_header"
|
|
||||||
android:textAppearance="@style/HeaderTextStyle"
|
|
||||||
android:textSize="16sp"
|
|
||||||
app:fontFamily="@font/metropolis_semibold"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/remove_collection_placeholder"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageButton
|
|
||||||
android:id="@+id/remove_collection_placeholder"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
|
||||||
android:contentDescription="@string/remove_home_collection_placeholder_content_description"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/no_collections_header"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/no_collections_header"
|
|
||||||
app:srcCompat="@drawable/ic_close" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/no_collections_description"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="4dp"
|
|
||||||
android:text="@string/no_collections_description2"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textColor="?attr/textSecondary"
|
|
||||||
android:textSize="14sp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/no_collections_header" />
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/add_tabs_to_collections_button"
|
|
||||||
style="@style/PositiveButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:maxLines="2"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/tabs_menu_save_to_collection1"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:icon="@drawable/ic_tab_collection"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/no_collections_description" />
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,78 +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.view.LayoutInflater
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import io.mockk.mockk
|
|
||||||
import io.mockk.verify
|
|
||||||
import mozilla.components.browser.state.state.BrowserState
|
|
||||||
import mozilla.components.browser.state.state.createTab
|
|
||||||
import mozilla.components.browser.state.store.BrowserStore
|
|
||||||
import mozilla.components.support.test.robolectric.testContext
|
|
||||||
import org.junit.Assert.assertFalse
|
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mozilla.fenix.databinding.NoCollectionsMessageBinding
|
|
||||||
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.CollectionInteractor
|
|
||||||
|
|
||||||
@RunWith(FenixRobolectricTestRunner::class)
|
|
||||||
class NoCollectionsMessageViewHolderTest {
|
|
||||||
|
|
||||||
private lateinit var binding: NoCollectionsMessageBinding
|
|
||||||
private val store: BrowserStore = BrowserStore(
|
|
||||||
initialState = BrowserState(
|
|
||||||
listOf(
|
|
||||||
createTab("https://www.mozilla.org", id = "reader-inactive-tab")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private lateinit var lifecycleOwner: LifecycleOwner
|
|
||||||
private lateinit var interactor: CollectionInteractor
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
binding = NoCollectionsMessageBinding.inflate(LayoutInflater.from(testContext))
|
|
||||||
lifecycleOwner = mockk(relaxed = true)
|
|
||||||
interactor = mockk(relaxed = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `hide add to collection button when there are no tabs open`() {
|
|
||||||
val noTabsStore = BrowserStore()
|
|
||||||
NoCollectionsMessageViewHolder(binding.root, lifecycleOwner, noTabsStore, interactor)
|
|
||||||
|
|
||||||
assertFalse(binding.addTabsToCollectionsButton.isVisible)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `show add to collection button when there are tabs`() {
|
|
||||||
NoCollectionsMessageViewHolder(binding.root, lifecycleOwner, store, interactor)
|
|
||||||
|
|
||||||
assertTrue(binding.addTabsToCollectionsButton.isVisible)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `call interactor on click`() {
|
|
||||||
NoCollectionsMessageViewHolder(binding.root, lifecycleOwner, store, interactor)
|
|
||||||
|
|
||||||
binding.addTabsToCollectionsButton.performClick()
|
|
||||||
verify { interactor.onAddTabsToCollectionTapped() }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `hide view and change setting on remove placeholder click`() {
|
|
||||||
NoCollectionsMessageViewHolder(binding.root, lifecycleOwner, store, interactor)
|
|
||||||
|
|
||||||
binding.removeCollectionPlaceholder.performClick()
|
|
||||||
verify {
|
|
||||||
interactor.onRemoveCollectionsPlaceholder()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue