From df80a5240b687f81a226e64248eb2ee5276d5305 Mon Sep 17 00:00:00 2001 From: mcarare <“mihai.carare.dev@gmail.com”> Date: Fri, 28 Feb 2020 16:51:29 +0200 Subject: [PATCH] For #6607 Add button to no tab content pane --- .../org/mozilla/fenix/home/HomeFragment.kt | 3 +- .../sessioncontrol/SessionControlAdapter.kt | 16 ++++ .../SessionControlController.kt | 12 ++- .../SessionControlInteractor.kt | 9 +++ .../home/sessioncontrol/SessionControlView.kt | 6 +- .../viewholders/NoContentMessageViewHolder.kt | 2 +- .../NoContentMessageWithActionViewHolder.kt | 54 +++++++++++++ .../layout/no_content_message_with_action.xml | 77 +++++++++++++++++++ 8 files changed, 174 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageWithActionViewHolder.kt create mode 100644 app/src/main/res/layout/no_content_message_with_action.xml diff --git a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt index c810564df..458dba221 100644 --- a/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt @@ -202,7 +202,8 @@ class HomeFragment : Fragment() { registerCollectionStorageObserver = ::registerCollectionStorageObserver, scrollToTheTop = ::scrollToTheTop, showDeleteCollectionPrompt = ::showDeleteCollectionPrompt, - openSettingsScreen = ::openSettingsScreen + openSettingsScreen = ::openSettingsScreen, + openSearchScreen = ::navigateToSearch ) ) updateLayout(view) 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 b911b7c53..074a1d588 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 @@ -23,6 +23,7 @@ import org.mozilla.fenix.home.Tab import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageWithActionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.SaveTabGroupViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder @@ -81,6 +82,15 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) { @StringRes val description: Int ) : AdapterItem(NoContentMessageViewHolder.LAYOUT_ID) + data class NoContentMessageWithAction( + @DrawableRes val icon: Int, + @StringRes val header: Int, + @StringRes val description: Int, + @DrawableRes val buttonIcon: Int = 0, + @StringRes val buttonText: Int = 0, + val listener: (() -> Unit)? = null + ) : AdapterItem(NoContentMessageWithActionViewHolder.LAYOUT_ID) + object CollectionHeader : AdapterItem(CollectionHeaderViewHolder.LAYOUT_ID) data class CollectionItem( val collection: TabCollection, @@ -161,6 +171,7 @@ class SessionControlAdapter( SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, interactor) PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, interactor) NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view) + NoContentMessageWithActionViewHolder.LAYOUT_ID -> NoContentMessageWithActionViewHolder(view) CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view) CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, interactor) TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, interactor) @@ -195,6 +206,11 @@ class SessionControlAdapter( is TopSiteViewHolder -> { holder.bind((item as AdapterItem.TopSiteList).topSites) } + is NoContentMessageWithActionViewHolder -> { + val listener = { interactor.onOpenNewTabClicked() } + val (icon, header, description, buttonIcon, buttonText) = item as AdapterItem.NoContentMessageWithAction + holder.bind(icon, header, description, buttonIcon, buttonText, listener) + } is NoContentMessageViewHolder -> { val (icon, header, description) = item as AdapterItem.NoContentMessage holder.bind(icon, header, description) diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index 3301037a2..f31d6e439 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -148,6 +148,11 @@ interface SessionControlController { * @see [CollectionInteractor.onToggleCollectionExpanded] */ fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean) + + /** + * @see [TabSessionInteractor.onOpenNewTabClicked] + */ + fun handleonOpenNewTabClicked() } @SuppressWarnings("TooManyFunctions", "LargeClass") @@ -165,7 +170,8 @@ class DefaultSessionControlController( private val registerCollectionStorageObserver: () -> Unit, private val scrollToTheTop: () -> Unit, private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit, - private val openSettingsScreen: () -> Unit + private val openSettingsScreen: () -> Unit, + private val openSearchScreen: () -> Unit ) : SessionControlController { private val metrics: MetricController get() = activity.components.analytics.metrics @@ -379,6 +385,10 @@ class DefaultSessionControlController( store.dispatch(HomeFragmentAction.CollectionExpanded(collection, expand)) } + override fun handleonOpenNewTabClicked() { + openSearchScreen() + } + private fun showCollectionCreationFragment( step: SaveCollectionStep, selectedTabIds: Array? = null, diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt index 8052af2d9..6cc5731c3 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt @@ -153,6 +153,11 @@ interface TabSessionInteractor { * mode or tab header menu item. */ fun onShareTabs() + + /** + * Opens a new tab + */ + fun onOpenNewTabClicked() } /** @@ -274,4 +279,8 @@ class SessionControlInteractor( override fun onToggleCollectionExpanded(collection: TabCollection, expand: Boolean) { controller.handleToggleCollectionExpanded(collection, expand) } + + override fun onOpenNewTabClicked() { + controller.handleonOpenNewTabClicked() + } } diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 506fd18e8..1be3f52be 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -22,10 +22,12 @@ import org.mozilla.fenix.home.Mode import org.mozilla.fenix.home.OnboardingState import org.mozilla.fenix.home.Tab -val noTabMessage = AdapterItem.NoContentMessage( +val noTabMessage = AdapterItem.NoContentMessageWithAction( R.drawable.ic_tabs, R.string.no_open_tabs_header_2, - R.string.no_open_tabs_description + R.string.no_open_tabs_description, + R.drawable.ic_new, + R.string.home_screen_shortcut_open_new_tab_2 ) val noCollectionMessage = AdapterItem.NoContentMessage( diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageViewHolder.kt index d6be11fcf..bd7f6e81a 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageViewHolder.kt @@ -12,7 +12,7 @@ import kotlinx.android.synthetic.main.no_content_message.view.* import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds import org.mozilla.fenix.R -class NoContentMessageViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { +open class NoContentMessageViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { fun bind( @DrawableRes icon: Int, diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageWithActionViewHolder.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageWithActionViewHolder.kt new file mode 100644 index 000000000..9d32ac83e --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/NoContentMessageWithActionViewHolder.kt @@ -0,0 +1,54 @@ +/* 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.View +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.core.view.isVisible +import kotlinx.android.synthetic.main.no_content_message_with_action.view.button_icon +import kotlinx.android.synthetic.main.no_content_message_with_action.view.button_layout +import kotlinx.android.synthetic.main.no_content_message_with_action.view.button_text +import org.mozilla.fenix.R + +class NoContentMessageWithActionViewHolder( + private val view: View +) : NoContentMessageViewHolder(view) { + + /** + * @param icon The visible label for header text this menu item. + * @param header ID of string resource for title text. + * @param description ID of string resource for description text. + * @param buttonIcon Optional ID of drawable resource for button icon. + * @param buttonText Optional ID of string resource for button text. + * @param listener Optional Callback to be invoked when the button is clicked. + */ + @Suppress("LongParameterList") + fun bind( + @DrawableRes icon: Int, + @StringRes header: Int, + @StringRes description: Int, + @DrawableRes buttonIcon: Int = 0, + @StringRes buttonText: Int = 0, + listener: (() -> Unit)? = null + ) { + super.bind(icon, header, description) + with(view.context) { + + if (buttonIcon != 0 || buttonText != 0) { + view.button_layout.isVisible = true + view.button_icon.setImageDrawable(getDrawable(buttonIcon)) + view.button_text.text = getString(buttonText) + view.button_layout.setOnClickListener { + listener?.invoke() + } + } + } + } + + companion object { + const val LAYOUT_ID = R.layout.no_content_message_with_action + } +} diff --git a/app/src/main/res/layout/no_content_message_with_action.xml b/app/src/main/res/layout/no_content_message_with_action.xml new file mode 100644 index 000000000..728c1b548 --- /dev/null +++ b/app/src/main/res/layout/no_content_message_with_action.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + \ No newline at end of file