For #11498 - removed SignIn ViewHolder and unified with the Error one
parent
5d1aeb5ea7
commit
ff50dae8e9
|
@ -12,7 +12,6 @@ import androidx.recyclerview.widget.ListAdapter
|
||||||
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
|
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
|
||||||
import org.mozilla.fenix.sync.SyncedTabsViewHolder.DeviceViewHolder
|
import org.mozilla.fenix.sync.SyncedTabsViewHolder.DeviceViewHolder
|
||||||
import org.mozilla.fenix.sync.SyncedTabsViewHolder.ErrorViewHolder
|
import org.mozilla.fenix.sync.SyncedTabsViewHolder.ErrorViewHolder
|
||||||
import org.mozilla.fenix.sync.SyncedTabsViewHolder.SignInViewHolder
|
|
||||||
import org.mozilla.fenix.sync.SyncedTabsViewHolder.TabViewHolder
|
import org.mozilla.fenix.sync.SyncedTabsViewHolder.TabViewHolder
|
||||||
import mozilla.components.browser.storage.sync.Tab as SyncTab
|
import mozilla.components.browser.storage.sync.Tab as SyncTab
|
||||||
import mozilla.components.concept.sync.Device as SyncDevice
|
import mozilla.components.concept.sync.Device as SyncDevice
|
||||||
|
@ -28,7 +27,6 @@ class SyncedTabsAdapter(
|
||||||
DeviceViewHolder.LAYOUT_ID -> DeviceViewHolder(itemView)
|
DeviceViewHolder.LAYOUT_ID -> DeviceViewHolder(itemView)
|
||||||
TabViewHolder.LAYOUT_ID -> TabViewHolder(itemView)
|
TabViewHolder.LAYOUT_ID -> TabViewHolder(itemView)
|
||||||
ErrorViewHolder.LAYOUT_ID -> ErrorViewHolder(itemView)
|
ErrorViewHolder.LAYOUT_ID -> ErrorViewHolder(itemView)
|
||||||
SignInViewHolder.LAYOUT_ID -> SignInViewHolder(itemView)
|
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,10 +36,9 @@ class SyncedTabsAdapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = when (getItem(position)) {
|
override fun getItemViewType(position: Int) = when (getItem(position)) {
|
||||||
is AdapterItem.Device -> DeviceViewHolder.LAYOUT_ID
|
is AdapterItem.Device -> DeviceViewHolder.LAYOUT_ID
|
||||||
is AdapterItem.Tab -> TabViewHolder.LAYOUT_ID
|
is AdapterItem.Tab -> TabViewHolder.LAYOUT_ID
|
||||||
is AdapterItem.Error -> ErrorViewHolder.LAYOUT_ID
|
is AdapterItem.Error -> ErrorViewHolder.LAYOUT_ID
|
||||||
is AdapterItem.SignIn -> SignInViewHolder.LAYOUT_ID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateData(syncedTabs: List<SyncedDeviceTabs>) {
|
fun updateData(syncedTabs: List<SyncedDeviceTabs>) {
|
||||||
|
@ -62,7 +59,7 @@ class SyncedTabsAdapter(
|
||||||
when (oldItem) {
|
when (oldItem) {
|
||||||
is AdapterItem.Device ->
|
is AdapterItem.Device ->
|
||||||
newItem is AdapterItem.Device && oldItem.device.id == newItem.device.id
|
newItem is AdapterItem.Device && oldItem.device.id == newItem.device.id
|
||||||
is AdapterItem.Tab, AdapterItem.Error, AdapterItem.SignIn ->
|
is AdapterItem.Tab, is AdapterItem.Error ->
|
||||||
oldItem == newItem
|
oldItem == newItem
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +71,9 @@ class SyncedTabsAdapter(
|
||||||
sealed class AdapterItem {
|
sealed class AdapterItem {
|
||||||
data class Device(val device: SyncDevice) : AdapterItem()
|
data class Device(val device: SyncDevice) : AdapterItem()
|
||||||
data class Tab(val tab: SyncTab) : AdapterItem()
|
data class Tab(val tab: SyncTab) : AdapterItem()
|
||||||
data class SignIn(val navController: NavController) : AdapterItem()
|
data class Error(
|
||||||
data class Error(val errorResId: Int) : AdapterItem()
|
val descriptionResId: Int,
|
||||||
|
val navController: NavController? = null
|
||||||
|
) : AdapterItem()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.util.AttributeSet
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.fragment.app.findFragment
|
import androidx.fragment.app.findFragment
|
||||||
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.synthetic.main.component_sync_tabs.view.*
|
import kotlinx.android.synthetic.main.component_sync_tabs.view.*
|
||||||
|
@ -19,6 +20,7 @@ import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
|
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
|
||||||
import mozilla.components.feature.syncedtabs.view.SyncedTabsView
|
import mozilla.components.feature.syncedtabs.view.SyncedTabsView
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
class SyncedTabsLayout @JvmOverloads constructor(
|
class SyncedTabsLayout @JvmOverloads constructor(
|
||||||
context: Context,
|
context: Context,
|
||||||
|
@ -45,10 +47,17 @@ class SyncedTabsLayout @JvmOverloads constructor(
|
||||||
// We may still be displaying a "loading" spinner, hide it.
|
// We may still be displaying a "loading" spinner, hide it.
|
||||||
stopLoading()
|
stopLoading()
|
||||||
|
|
||||||
sync_tabs_status.text = context.getText(stringResourceForError(error))
|
val navController: NavController? = try {
|
||||||
|
findFragment<SyncedTabsFragment>().findNavController()
|
||||||
|
} catch (exception: IllegalStateException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
synced_tabs_list.visibility = View.GONE
|
val descriptionResId = stringResourceForError(error)
|
||||||
sync_tabs_status.visibility = View.VISIBLE
|
val errorItem = getErrorItem(navController, error, descriptionResId)
|
||||||
|
|
||||||
|
val errorList: List<SyncedTabsAdapter.AdapterItem> = listOf(errorItem)
|
||||||
|
adapter.submitList(errorList)
|
||||||
|
|
||||||
synced_tabs_pull_to_refresh.isEnabled = pullToRefreshEnableState(error)
|
synced_tabs_pull_to_refresh.isEnabled = pullToRefreshEnableState(error)
|
||||||
}
|
}
|
||||||
|
@ -56,17 +65,11 @@ class SyncedTabsLayout @JvmOverloads constructor(
|
||||||
|
|
||||||
override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
|
override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
synced_tabs_list.visibility = View.VISIBLE
|
|
||||||
sync_tabs_status.visibility = View.GONE
|
|
||||||
|
|
||||||
adapter.updateData(syncedTabs)
|
adapter.updateData(syncedTabs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun startLoading() {
|
override fun startLoading() {
|
||||||
synced_tabs_list.visibility = View.VISIBLE
|
|
||||||
sync_tabs_status.visibility = View.GONE
|
|
||||||
|
|
||||||
synced_tabs_pull_to_refresh.isRefreshing = true
|
synced_tabs_pull_to_refresh.isRefreshing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +83,8 @@ class SyncedTabsLayout @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
internal fun pullToRefreshEnableState(error: SyncedTabsView.ErrorType) = when (error) {
|
|
||||||
|
private fun pullToRefreshEnableState(error: SyncedTabsView.ErrorType) = when (error) {
|
||||||
// Disable "pull-to-refresh" when we clearly can't sync tabs, and user needs to take an
|
// Disable "pull-to-refresh" when we clearly can't sync tabs, and user needs to take an
|
||||||
// action within the app.
|
// action within the app.
|
||||||
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE,
|
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE,
|
||||||
|
@ -93,12 +97,26 @@ class SyncedTabsLayout @JvmOverloads constructor(
|
||||||
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> true
|
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> true
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun stringResourceForError(error: SyncedTabsView.ErrorType) = when (error) {
|
private fun stringResourceForError(error: SyncedTabsView.ErrorType) = when (error) {
|
||||||
SyncedTabsView.ErrorType.MULTIPLE_DEVICES_UNAVAILABLE -> R.string.synced_tabs_connect_another_device
|
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_ENGINE_UNAVAILABLE -> R.string.synced_tabs_enable_tab_syncing
|
||||||
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_sign_in_message
|
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> R.string.synced_tabs_sign_in_message
|
||||||
SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth
|
SyncedTabsView.ErrorType.SYNC_NEEDS_REAUTHENTICATION -> R.string.synced_tabs_reauth
|
||||||
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs
|
SyncedTabsView.ErrorType.NO_TABS_AVAILABLE -> R.string.synced_tabs_no_tabs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getErrorItem(
|
||||||
|
navController: NavController?,
|
||||||
|
error: SyncedTabsView.ErrorType,
|
||||||
|
@StringRes stringResId: Int
|
||||||
|
): SyncedTabsAdapter.AdapterItem = 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(descriptionResId = stringResId)
|
||||||
|
SyncedTabsView.ErrorType.SYNC_UNAVAILABLE -> SyncedTabsAdapter.AdapterItem
|
||||||
|
.Error(descriptionResId = stringResId, navController = navController)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ package org.mozilla.fenix.sync
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.View.GONE
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import kotlinx.android.synthetic.main.no_content_message_with_action.view.*
|
import kotlinx.android.synthetic.main.sync_tabs_error_row.view.*
|
||||||
import kotlinx.android.synthetic.main.sync_tabs_list_item.view.*
|
import kotlinx.android.synthetic.main.sync_tabs_list_item.view.*
|
||||||
import kotlinx.android.synthetic.main.view_synced_tabs_group.view.*
|
import kotlinx.android.synthetic.main.view_synced_tabs_group.view.*
|
||||||
import mozilla.components.browser.storage.sync.Tab
|
import mozilla.components.browser.storage.sync.Tab
|
||||||
|
@ -44,41 +44,26 @@ 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) {
|
class ErrorViewHolder(itemView: View) : SyncedTabsViewHolder(itemView) {
|
||||||
|
|
||||||
override fun <T : AdapterItem> bind(item: T, interactor: (Tab) -> Unit) {
|
override fun <T : AdapterItem> bind(item: T, interactor: (Tab) -> Unit) {
|
||||||
val errorItem = item as AdapterItem.Error
|
val errorItem = item as AdapterItem.Error
|
||||||
setErrorMargins()
|
setErrorMargins()
|
||||||
|
|
||||||
itemView.no_content_header.visibility = GONE
|
itemView.sync_tabs_error_description.text =
|
||||||
itemView.no_content_description.text = itemView.context.getString(errorItem.errorResId)
|
itemView.context.getString(errorItem.descriptionResId)
|
||||||
|
itemView.sync_tabs_error_cta_button.visibility = GONE
|
||||||
|
|
||||||
|
errorItem.navController?.let { navController ->
|
||||||
|
itemView.sync_tabs_error_cta_button.visibility = VISIBLE
|
||||||
|
itemView.sync_tabs_error_cta_button.setOnClickListener {
|
||||||
|
navController.navigate(NavGraphDirections.actionGlobalTurnOnSync())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val LAYOUT_ID = R.layout.no_content_message
|
const val LAYOUT_ID = R.layout.sync_tabs_error_row
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +80,12 @@ sealed class SyncedTabsViewHolder(itemView: View) : RecyclerView.ViewHolder(item
|
||||||
}
|
}
|
||||||
|
|
||||||
itemView.synced_tabs_group_name.text = device.device.displayName
|
itemView.synced_tabs_group_name.text = device.device.displayName
|
||||||
itemView.synced_tabs_group_name.setCompoundDrawablesWithIntrinsicBounds(deviceLogoDrawable, 0, 0, 0)
|
itemView.synced_tabs_group_name.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
deviceLogoDrawable,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?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/. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:background="@drawable/empty_session_control_background"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/sync_tabs_error_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
tools:text="@string/synced_tabs_no_tabs"/>
|
||||||
|
|
||||||
|
<com.google.android.material.button.MaterialButton
|
||||||
|
android:id="@+id/sync_tabs_error_cta_button"
|
||||||
|
style="@style/PositiveButton"
|
||||||
|
app:icon="@drawable/ic_sign_in"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/synced_tabs_sign_in_button"
|
||||||
|
android:layout_marginTop="8dp"/>
|
||||||
|
</LinearLayout>
|
|
@ -1464,4 +1464,6 @@
|
||||||
<string name="preferences_show_search_shortcuts">Show search shortcuts</string>
|
<string name="preferences_show_search_shortcuts">Show search shortcuts</string>
|
||||||
<!-- DEPRECATED: Button in the search view that lets a user search by using a shortcut -->
|
<!-- DEPRECATED: Button in the search view that lets a user search by using a shortcut -->
|
||||||
<string name="search_engines_shortcut_button">Search Engine</string>
|
<string name="search_engines_shortcut_button">Search Engine</string>
|
||||||
|
<!-- DEPRECATED: 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>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue