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 79fdf965ed..4dd98bfd57 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 @@ -4,7 +4,6 @@ package org.mozilla.fenix.home.sessioncontrol -import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup import androidx.annotation.LayoutRes @@ -36,14 +35,6 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CustomizeHomeButtonView import org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.MessageCardViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingManualSignInViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivacyNoticeViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingToolbarPositionPickerViewHolder -import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder import org.mozilla.fenix.home.topsites.TopSitePagerViewHolder import mozilla.components.feature.tab.collections.Tab as ComponentTab @@ -138,16 +129,6 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) { } } - object OnboardingHeader : AdapterItem(OnboardingHeaderViewHolder.LAYOUT_ID) - data class OnboardingSectionHeader( - val labelBuilder: (Context) -> String, - ) : AdapterItem(OnboardingSectionHeaderViewHolder.LAYOUT_ID) { - override fun sameAs(other: AdapterItem) = - other is OnboardingSectionHeader && labelBuilder == other.labelBuilder - } - - object OnboardingManualSignIn : AdapterItem(OnboardingManualSignInViewHolder.LAYOUT_ID) - data class NimbusMessageCard( val message: Message, ) : AdapterItem(MessageCardViewHolder.LAYOUT_ID) { @@ -155,15 +136,6 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) { other is NimbusMessageCard && message.id == other.message.id } - object OnboardingThemePicker : AdapterItem(OnboardingThemePickerViewHolder.LAYOUT_ID) - object OnboardingTrackingProtection : - AdapterItem(OnboardingTrackingProtectionViewHolder.LAYOUT_ID) - - object OnboardingPrivacyNotice : AdapterItem(OnboardingPrivacyNoticeViewHolder.LAYOUT_ID) - object OnboardingFinish : AdapterItem(OnboardingFinishViewHolder.LAYOUT_ID) - object OnboardingToolbarPositionPicker : - AdapterItem(OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID) - object CustomizeHomeButton : AdapterItem(CustomizeHomeButtonViewHolder.LAYOUT_ID) object RecentTabsHeader : AdapterItem(RecentTabsHeaderViewHolder.LAYOUT_ID) @@ -321,21 +293,6 @@ class SessionControlAdapter( components.appStore, interactor, ) - OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view) - OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view) - OnboardingManualSignInViewHolder.LAYOUT_ID -> OnboardingManualSignInViewHolder(view) - OnboardingThemePickerViewHolder.LAYOUT_ID -> OnboardingThemePickerViewHolder(view) - OnboardingTrackingProtectionViewHolder.LAYOUT_ID -> OnboardingTrackingProtectionViewHolder( - view, - ) - OnboardingPrivacyNoticeViewHolder.LAYOUT_ID -> OnboardingPrivacyNoticeViewHolder( - view, - interactor, - ) - OnboardingFinishViewHolder.LAYOUT_ID -> OnboardingFinishViewHolder(view, interactor) - OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder( - view, - ) BottomSpacerViewHolder.LAYOUT_ID -> BottomSpacerViewHolder(view) else -> throw IllegalStateException() } @@ -424,10 +381,6 @@ class SessionControlAdapter( val (collection, tab, isLastTab) = item as AdapterItem.TabInCollectionItem holder.bindSession(collection, tab, isLastTab) } - is OnboardingSectionHeaderViewHolder -> holder.bind( - (item as AdapterItem.OnboardingSectionHeader).labelBuilder, - ) - is OnboardingManualSignInViewHolder, is RecentlyVisitedViewHolder, is RecentBookmarksViewHolder, is RecentTabViewHolder, 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 fc7cd66b22..e88aee21f4 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 @@ -26,6 +26,7 @@ import org.mozilla.fenix.messaging.FenixMessageSurfaceId import org.mozilla.fenix.nimbus.OnboardingPanel import org.mozilla.fenix.onboarding.HomeCFRPresenter import org.mozilla.fenix.onboarding.OnboardingState +import org.mozilla.fenix.onboarding.view.OnboardingAdapterItem import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.nimbus.Onboarding as OnboardingConfig @@ -133,25 +134,25 @@ private fun privateModeAdapterItems() = listOf(AdapterItem.PrivateBrowsingDescri private fun onboardingAdapterItems( onboardingState: OnboardingState, onboardingConfig: OnboardingConfig, -): List { - val items: MutableList = mutableListOf(AdapterItem.OnboardingHeader) +): List { + val items: MutableList = mutableListOf(OnboardingAdapterItem.OnboardingHeader) onboardingConfig.order.forEach { when (it) { - OnboardingPanel.THEMES -> items.add(AdapterItem.OnboardingThemePicker) - OnboardingPanel.TOOLBAR_PLACEMENT -> items.add(AdapterItem.OnboardingToolbarPositionPicker) + OnboardingPanel.THEMES -> items.add(OnboardingAdapterItem.OnboardingThemePicker) + OnboardingPanel.TOOLBAR_PLACEMENT -> items.add(OnboardingAdapterItem.OnboardingToolbarPositionPicker) // Customize FxA items based on where we are with the account state: OnboardingPanel.SYNC -> if (onboardingState == OnboardingState.SignedOutNoAutoSignIn) { - items.add(AdapterItem.OnboardingManualSignIn) + items.add(OnboardingAdapterItem.OnboardingManualSignIn) } - OnboardingPanel.TCP -> items.add(AdapterItem.OnboardingTrackingProtection) - OnboardingPanel.PRIVACY_NOTICE -> items.add(AdapterItem.OnboardingPrivacyNotice) + OnboardingPanel.TCP -> items.add(OnboardingAdapterItem.OnboardingTrackingProtection) + OnboardingPanel.PRIVACY_NOTICE -> items.add(OnboardingAdapterItem.OnboardingPrivacyNotice) } } items.addAll( listOf( - AdapterItem.OnboardingFinish, - AdapterItem.BottomSpacer, + OnboardingAdapterItem.OnboardingFinish, + OnboardingAdapterItem.BottomSpacer, ), ) diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/view/OnboardingAdapter.kt b/app/src/main/java/org/mozilla/fenix/onboarding/view/OnboardingAdapter.kt new file mode 100644 index 0000000000..b01f7b4945 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/view/OnboardingAdapter.kt @@ -0,0 +1,159 @@ +/* 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.onboarding.view + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import org.mozilla.fenix.home.BottomSpacerViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingFinishViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingHeaderViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingManualSignInViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPrivacyNoticeViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingSectionHeaderViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingThemePickerViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingToolbarPositionPickerViewHolder +import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingTrackingProtectionViewHolder +import org.mozilla.fenix.onboarding.interactor.OnboardingInteractor + +/** + * Adapter for a list of onboarding views to be displayed. + */ +class OnboardingAdapter( + private val interactor: OnboardingInteractor, +) : ListAdapter(DiffCallback) { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false) + + return when (viewType) { + OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view) + OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view) + OnboardingManualSignInViewHolder.LAYOUT_ID -> OnboardingManualSignInViewHolder(view) + OnboardingThemePickerViewHolder.LAYOUT_ID -> OnboardingThemePickerViewHolder(view) + OnboardingTrackingProtectionViewHolder.LAYOUT_ID -> OnboardingTrackingProtectionViewHolder( + view, + ) + OnboardingPrivacyNoticeViewHolder.LAYOUT_ID -> OnboardingPrivacyNoticeViewHolder( + view, + interactor, + ) + OnboardingFinishViewHolder.LAYOUT_ID -> OnboardingFinishViewHolder(view, interactor) + OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID -> OnboardingToolbarPositionPickerViewHolder( + view, + ) + BottomSpacerViewHolder.LAYOUT_ID -> BottomSpacerViewHolder(view) + else -> throw IllegalStateException("ViewType $viewType does not match a ViewHolder") + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val item = getItem(position) + + when (holder) { + is OnboardingSectionHeaderViewHolder -> holder.bind( + (item as OnboardingAdapterItem.OnboardingSectionHeader).labelBuilder, + ) + } + } + + override fun getItemViewType(position: Int) = getItem(position).viewType + + internal object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: OnboardingAdapterItem, newItem: OnboardingAdapterItem) = + oldItem.sameAs(newItem) + + @Suppress("DiffUtilEquals") + override fun areContentsTheSame( + oldItem: OnboardingAdapterItem, + newItem: OnboardingAdapterItem, + ) = oldItem.contentsSameAs(newItem) + + override fun getChangePayload( + oldItem: OnboardingAdapterItem, + newItem: OnboardingAdapterItem, + ): Any? { + return oldItem.getChangePayload(newItem) ?: return super.getChangePayload(oldItem, newItem) + } + } +} + +/** + * Enum of the various onboarding views. + */ +sealed class OnboardingAdapterItem(@LayoutRes val viewType: Int) { + /** + * Onboarding top header. + */ + object OnboardingHeader : OnboardingAdapterItem(OnboardingHeaderViewHolder.LAYOUT_ID) + + /** + * Onboarding section header. + */ + data class OnboardingSectionHeader( + val labelBuilder: (Context) -> String, + ) : OnboardingAdapterItem(OnboardingSectionHeaderViewHolder.LAYOUT_ID) { + override fun sameAs(other: OnboardingAdapterItem) = + other is OnboardingSectionHeader && labelBuilder == other.labelBuilder + } + + /** + * Onboarding sign into sync card. + */ + object OnboardingManualSignIn : + OnboardingAdapterItem(OnboardingManualSignInViewHolder.LAYOUT_ID) + + /** + * Onboarding theme picker card. + */ + object OnboardingThemePicker : OnboardingAdapterItem(OnboardingThemePickerViewHolder.LAYOUT_ID) + + /** + * Onboarding tracking protection card. + */ + object OnboardingTrackingProtection : + OnboardingAdapterItem(OnboardingTrackingProtectionViewHolder.LAYOUT_ID) + + /** + * Onboarding privacy card. + */ + object OnboardingPrivacyNotice : + OnboardingAdapterItem(OnboardingPrivacyNoticeViewHolder.LAYOUT_ID) + + /** + * Onboarding start browsing button. + */ + object OnboardingFinish : OnboardingAdapterItem(OnboardingFinishViewHolder.LAYOUT_ID) + + /** + * Onboarding toolbar placement picker. + */ + object OnboardingToolbarPositionPicker : + OnboardingAdapterItem(OnboardingToolbarPositionPickerViewHolder.LAYOUT_ID) + + /** + * Spacer. + */ + object BottomSpacer : OnboardingAdapterItem(BottomSpacerViewHolder.LAYOUT_ID) + + /** + * Returns true if this item represents the same value as other. + */ + open fun sameAs(other: OnboardingAdapterItem) = this::class == other::class + + /** + * Returns a payload if there's been a change or null if not. + */ + open fun getChangePayload(newItem: OnboardingAdapterItem): Any? = null + + /** + * Returns true if this item represents the same value as the other. + */ + open fun contentsSameAs(other: OnboardingAdapterItem) = this::class == other::class +}