Skip to content

Commit

Permalink
For mozilla-mobile#11498 - add Sync tabs error view (including sign-i…
Browse files Browse the repository at this point in the history
…n CTA)
  • Loading branch information
BranescuMihai committed Jun 25, 2020
1 parent c958cc0 commit 4f5a2dd
Show file tree
Hide file tree
Showing 5 changed files with 106 additions and 43 deletions.
19 changes: 12 additions & 7 deletions app/src/main/java/org/mozilla/fenix/sync/SyncedTabsAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ 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.concept.sync.Device as SyncDevice
import mozilla.components.browser.storage.sync.Tab as SyncTab
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

class SyncedTabsAdapter(
private val listener: (SyncTab) -> Unit
Expand All @@ -25,22 +28,22 @@ 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()
}
}

override fun onBindViewHolder(holder: SyncedTabsViewHolder, position: Int) {
val item = when (holder) {
is DeviceViewHolder -> getItem(position) as AdapterItem.Device
is TabViewHolder -> getItem(position) as AdapterItem.Tab
}
holder.bind(item, listener)
holder.bind(getItem(position), listener)
}

override fun getItemViewType(position: Int): Int {
return 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
}
}

Expand All @@ -56,5 +59,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()
}
}
50 changes: 33 additions & 17 deletions app/src/main/java/org/mozilla/fenix/sync/SyncedTabsLayout.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 mozilla.components.browser.storage.sync.SyncedDeviceTabs
Expand All @@ -34,25 +36,17 @@ class SyncedTabsLayout @JvmOverloads constructor(
}

override fun onError(error: SyncedTabsView.ErrorType) {
val stringResId = when (error) {
SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE -> R.string.synced_tabs_connect_another_device
SyncedTabsView.ErrorType.SYNC_ENGINE_UNAVAILABLE -> R.string.synced_tabs_enable_tab_syncing
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_connect_to_sync_account
SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs
}
val stringResId = getErrorStringRes(error)
val errorItem = getErrorItem(error, stringResId)

sync_tabs_status.text = context.getText(stringResId)
val errorList: List<SyncedTabsAdapter.AdapterItem> = listOf(errorItem)
adapter.submitList(errorList)

synced_tabs_list.visibility = View.GONE
sync_tabs_status.visibility = View.VISIBLE
synced_tabs_pull_to_refresh.isEnabled = false
}

override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
synced_tabs_list.visibility = View.VISIBLE
sync_tabs_status.visibility = View.GONE

synced_tabs_pull_to_refresh.isEnabled = true
val allDeviceTabs = emptyList<SyncedTabsAdapter.AdapterItem>().toMutableList()

syncedTabs.forEach { (device, tabs) ->
Expand All @@ -69,13 +63,35 @@ class SyncedTabsLayout @JvmOverloads constructor(
}

override fun startLoading() {
synced_tabs_list.visibility = View.VISIBLE
sync_tabs_status.visibility = View.GONE

synced_tabs_pull_to_refresh.isRefreshing = true
}

override fun stopLoading() {
synced_tabs_pull_to_refresh.isRefreshing = false
}

private fun getErrorItem(
error: SyncedTabsView.ErrorType,
@StringRes stringResId: Int
): SyncedTabsAdapter.AdapterItem {
return when (error) {
SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE,
SyncedTabsView.ErrorType.SYNC_ENGINE_UNAVAILABLE,
SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION,
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE-> SyncedTabsAdapter.AdapterItem
.Error(stringResId)
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> SyncedTabsAdapter.AdapterItem
.SignIn(findFragment<SyncedTabsFragment>().findNavController())
}
}

private fun getErrorStringRes(error: SyncedTabsView.ErrorType): Int {
return when (error) {
SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE -> R.string.synced_tabs_connect_another_device
SyncedTabsView.ErrorType.SYNC_ENGINE_UNAVAILABLE -> R.string.synced_tabs_enable_tab_syncing
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_connect_to_sync_account
SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs
}
}
}
64 changes: 61 additions & 3 deletions app/src/main/java/org/mozilla/fenix/sync/SyncedTabsViewHolder.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -38,17 +44,54 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
}
}

class SignInViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) {

override fun <T : AdapterItem> 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 <T : AdapterItem> 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 <T : AdapterItem> bind(item: T, interactor: (Tab) -> Unit) {
bindHeader(item as AdapterItem.Device)
}

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 }
DeviceType.DESKTOP -> R.drawable.mozac_ic_device_desktop
else -> R.drawable.mozac_ic_device_mobile
}

itemView.synced_tabs_group_name.text = device.device.displayName
Expand All @@ -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
}
}
14 changes: 0 additions & 14 deletions app/src/main/res/layout/component_sync_tabs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,6 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<TextView
android:id="@+id/sync_tabs_status"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:text="@string/sync_connect_device"
android:textColor="?secondaryText"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />

<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/synced_tabs_pull_to_refresh"
android:layout_width="match_parent"
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1396,8 +1396,6 @@
<string name="saved_login_duplicate">A login with that username already exists</string>

<!-- Synced Tabs -->
<!-- Text displayed when user is not logged into a Firefox Account -->
<string name="synced_tabs_connect_to_sync_account">Connect with a Firefox Account.</string>
<!-- Text displayed to ask user to connect another device as no devices found with account -->
<string name="synced_tabs_connect_another_device">Connect another device.</string>
<!-- Text displayed asking user to re-authenticate -->
Expand Down

0 comments on commit 4f5a2dd

Please sign in to comment.