From bfc955cd402d707862609b2a4f47722c4f373d46 Mon Sep 17 00:00:00 2001 From: Mihai Branescu Date: Tue, 16 Jun 2020 10:42:16 +0300 Subject: [PATCH] For #11498 - add Sync tabs error view (including sign-in CTA) --- .../mozilla/fenix/sync/SyncedTabsAdapter.kt | 11 +++- .../mozilla/fenix/sync/SyncedTabsLayout.kt | 4 +- .../fenix/sync/SyncedTabsViewHolder.kt | 60 ++++++++++++++++++- .../main/res/layout/component_sync_tabs.xml | 14 ----- app/src/main/res/values/strings.xml | 2 - 5 files changed, 72 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt index 69ace066f..2d3e8b885 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt @@ -6,10 +6,13 @@ package org.mozilla.fenix.sync import android.view.LayoutInflater import android.view.ViewGroup +import androidx.navigation.NavController import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import mozilla.components.browser.storage.sync.SyncedDeviceTabs import org.mozilla.fenix.sync.SyncedTabsViewHolder.DeviceViewHolder +import org.mozilla.fenix.sync.SyncedTabsViewHolder.ErrorViewHolder +import org.mozilla.fenix.sync.SyncedTabsViewHolder.SignInViewHolder import org.mozilla.fenix.sync.SyncedTabsViewHolder.TabViewHolder import mozilla.components.browser.storage.sync.Tab as SyncTab import mozilla.components.concept.sync.Device as SyncDevice @@ -24,6 +27,8 @@ class SyncedTabsAdapter( return when (viewType) { DeviceViewHolder.LAYOUT_ID -> DeviceViewHolder(itemView) TabViewHolder.LAYOUT_ID -> TabViewHolder(itemView) + ErrorViewHolder.LAYOUT_ID -> ErrorViewHolder(itemView) + SignInViewHolder.LAYOUT_ID -> SignInViewHolder(itemView) else -> throw IllegalStateException() } } @@ -35,6 +40,8 @@ class SyncedTabsAdapter( override fun getItemViewType(position: Int) = when (getItem(position)) { is AdapterItem.Device -> DeviceViewHolder.LAYOUT_ID is AdapterItem.Tab -> TabViewHolder.LAYOUT_ID + is AdapterItem.Error -> ErrorViewHolder.LAYOUT_ID + is AdapterItem.SignIn -> SignInViewHolder.LAYOUT_ID } fun updateData(syncedTabs: List) { @@ -55,7 +62,7 @@ class SyncedTabsAdapter( when (oldItem) { is AdapterItem.Device -> newItem is AdapterItem.Device && oldItem.device.id == newItem.device.id - is AdapterItem.Tab -> + is AdapterItem.Tab, AdapterItem.Error, AdapterItem.SignIn -> oldItem == newItem } @@ -67,5 +74,7 @@ class SyncedTabsAdapter( sealed class AdapterItem { data class Device(val device: SyncDevice) : AdapterItem() data class Tab(val tab: SyncTab) : AdapterItem() + data class SignIn(val navController: NavController) : AdapterItem() + data class Error(val errorResId: Int) : AdapterItem() } } diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt index 0889ccb50..c1decbf0f 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt @@ -6,8 +6,10 @@ package org.mozilla.fenix.sync import android.content.Context import android.util.AttributeSet -import android.view.View import android.widget.FrameLayout +import androidx.annotation.StringRes +import androidx.fragment.app.findFragment +import androidx.navigation.fragment.findNavController import androidx.recyclerview.widget.LinearLayoutManager import kotlinx.android.synthetic.main.component_sync_tabs.view.* import kotlinx.coroutines.CoroutineScope diff --git a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt index bcd494cf0..8be6c56d1 100644 --- a/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt @@ -5,11 +5,17 @@ package org.mozilla.fenix.sync import android.view.View +import android.view.View.GONE +import android.widget.LinearLayout +import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView +import kotlinx.android.synthetic.main.no_content_message_with_action.view.* import kotlinx.android.synthetic.main.sync_tabs_list_item.view.* import kotlinx.android.synthetic.main.view_synced_tabs_group.view.* import mozilla.components.browser.storage.sync.Tab import mozilla.components.concept.sync.DeviceType +import mozilla.components.support.ktx.android.util.dpToPx +import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.R import org.mozilla.fenix.sync.SyncedTabsAdapter.AdapterItem @@ -38,6 +44,44 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item } } + class SignInViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { + + override fun bind(item: T, interactor: (Tab) -> Unit) { + val signInItem = item as AdapterItem.SignIn + setErrorMargins() + + itemView.no_content_header.visibility = GONE + itemView.no_content_description.text = + itemView.context.getString(R.string.synced_tabs_sign_in_message) + itemView.no_content_button.text = + itemView.context.getString(R.string.synced_tabs_sign_in_button) + itemView.no_content_button.icon = + ContextCompat.getDrawable(itemView.context, R.drawable.ic_sign_in) + itemView.no_content_button.setOnClickListener { + signInItem.navController.navigate(NavGraphDirections.actionGlobalTurnOnSync()) + } + } + + companion object { + const val LAYOUT_ID = R.layout.no_content_message_with_action + } + } + + class ErrorViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { + + override fun bind(item: T, interactor: (Tab) -> Unit) { + val errorItem = item as AdapterItem.Error + setErrorMargins() + + itemView.no_content_header.visibility = GONE + itemView.no_content_description.text = itemView.context.getString(errorItem.errorResId) + } + + companion object { + const val LAYOUT_ID = R.layout.no_content_message + } + } + class DeviceViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) { override fun bind(item: T, interactor: (Tab) -> Unit) { @@ -45,7 +89,6 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item } private fun bindHeader(device: AdapterItem.Device) { - val deviceLogoDrawable = when (device.device.deviceType) { DeviceType.DESKTOP -> R.drawable.mozac_ic_device_desktop else -> R.drawable.mozac_ic_device_mobile @@ -59,4 +102,19 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item const val LAYOUT_ID = R.layout.view_synced_tabs_group } } + + internal fun setErrorMargins() { + val lp = LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) + val displayMetrics = itemView.context.resources.displayMetrics + val margin = ERROR_MARGIN.dpToPx(displayMetrics) + lp.setMargins(margin, margin, margin, 0) + itemView.layoutParams = lp + } + + companion object { + private const val ERROR_MARGIN = 20 + } } diff --git a/app/src/main/res/layout/component_sync_tabs.xml b/app/src/main/res/layout/component_sync_tabs.xml index 0ec378aad..f5a07f096 100644 --- a/app/src/main/res/layout/component_sync_tabs.xml +++ b/app/src/main/res/layout/component_sync_tabs.xml @@ -20,20 +20,6 @@ app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent" /> - - A login with that username already exists - - Connect with a Firefox Account. Connect another device.