1
0
Fork 0

Move adapter Job setup code to helper class (#3407)

master
Tiger Oakes 2019-07-01 14:34:25 -04:00 committed by Colin Lee
parent eb1ea882cf
commit 8cd1a0cb38
8 changed files with 74 additions and 104 deletions

View File

@ -19,21 +19,21 @@ import mozilla.components.browser.icons.IconRequest
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.utils.AdapterWithJob
import kotlin.coroutines.CoroutineContext
class CollectionCreationTabListAdapter(
val actionEmitter: Observer<CollectionCreationAction>
) : RecyclerView.Adapter<TabViewHolder>() {
) : AdapterWithJob<TabViewHolder>() {
private var tabs: List<Tab> = listOf()
private var selectedTabs: MutableSet<Tab> = mutableSetOf()
private lateinit var job: Job
private var hideCheckboxes = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TabViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(TabViewHolder.LAYOUT_ID, parent, false)
return TabViewHolder(view, job)
return TabViewHolder(view, adapterJob)
}
override fun onBindViewHolder(holder: TabViewHolder, position: Int, payloads: MutableList<Any>) {
@ -73,16 +73,6 @@ class CollectionCreationTabListAdapter(
override fun getItemCount(): Int = tabs.size
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
fun updateData(tabs: List<Tab>, selectedTabs: Set<Tab>, hideCheckboxes: Boolean = false) {
val diffUtil = DiffUtil.calculateDiff(
TabDiffUtil(

View File

@ -19,13 +19,13 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.components.description
import org.mozilla.fenix.home.sessioncontrol.Tab
import org.mozilla.fenix.home.sessioncontrol.TabCollection
import org.mozilla.fenix.utils.AdapterWithJob
import kotlin.coroutines.CoroutineContext
class SaveCollectionListAdapter(
val actionEmitter: Observer<CollectionCreationAction>
) : RecyclerView.Adapter<CollectionViewHolder>() {
) : AdapterWithJob<CollectionViewHolder>() {
private lateinit var job: Job
private var tabCollections = listOf<TabCollection>()
private var selectedTabs: Set<Tab> = setOf()
@ -33,7 +33,7 @@ class SaveCollectionListAdapter(
val view = LayoutInflater.from(parent.context)
.inflate(CollectionViewHolder.LAYOUT_ID, parent, false)
return CollectionViewHolder(view, actionEmitter, job)
return CollectionViewHolder(view, actionEmitter, adapterJob)
}
override fun onBindViewHolder(holder: CollectionViewHolder, position: Int) {
@ -49,16 +49,6 @@ class SaveCollectionListAdapter(
override fun getItemCount(): Int = tabCollections.size
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
fun updateData(tabCollections: List<TabCollection>, selectedTabs: Set<Tab>) {
this.tabCollections = tabCollections
this.selectedTabs = selectedTabs

View File

@ -8,10 +8,10 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.coroutines.Job
import org.mozilla.fenix.exceptions.viewholders.ExceptionsDeleteButtonViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsHeaderViewHolder
import org.mozilla.fenix.exceptions.viewholders.ExceptionsListItemViewHolder
import org.mozilla.fenix.utils.AdapterWithJob
private sealed class AdapterItem {
object DeleteButton : AdapterItem()
@ -34,9 +34,8 @@ private class ExceptionsList(val exceptions: List<ExceptionsItem>) {
class ExceptionsAdapter(
private val actionEmitter: Observer<ExceptionsAction>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
) : AdapterWithJob<RecyclerView.ViewHolder>() {
private var exceptionsList: ExceptionsList = ExceptionsList(emptyList())
private lateinit var job: Job
fun updateData(items: List<ExceptionsItem>) {
this.exceptionsList = ExceptionsList(items)
@ -59,7 +58,7 @@ class ExceptionsAdapter(
return when (viewType) {
ExceptionsDeleteButtonViewHolder.LAYOUT_ID -> ExceptionsDeleteButtonViewHolder(view, actionEmitter)
ExceptionsHeaderViewHolder.LAYOUT_ID -> ExceptionsHeaderViewHolder(view)
ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(view, actionEmitter, job)
ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(view, actionEmitter, adapterJob)
else -> throw IllegalStateException()
}
}
@ -71,14 +70,4 @@ class ExceptionsAdapter(
}
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
}

View File

@ -11,10 +11,8 @@ import androidx.annotation.DrawableRes
import androidx.annotation.LayoutRes
import androidx.annotation.StringRes
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.coroutines.Job
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.NoContentMessageViewHolder
@ -31,6 +29,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingPr
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.OnboardingTrackingProtectionViewHolder
import org.mozilla.fenix.utils.ListAdapterWithJob
import mozilla.components.feature.tab.collections.Tab as ComponentTab
sealed class AdapterItem(@LayoutRes val viewType: Int) {
@ -92,9 +91,7 @@ class AdapterItemDiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
class SessionControlAdapter(
private val actionEmitter: Observer<SessionControlAction>
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
private lateinit var job: Job
) : ListAdapterWithJob<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
// This method triggers the ComplexMethod lint error when in fact it's quite simple.
@SuppressWarnings("ComplexMethod")
@ -102,13 +99,13 @@ class SessionControlAdapter(
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
return when (viewType) {
TabHeaderViewHolder.LAYOUT_ID -> TabHeaderViewHolder(view, actionEmitter)
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, job)
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, adapterJob)
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, actionEmitter)
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, actionEmitter)
NoContentMessageViewHolder.LAYOUT_ID -> NoContentMessageViewHolder(view)
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, job)
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, job)
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, adapterJob)
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, adapterJob)
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view)
OnboardingFirefoxAccountViewHolder.LAYOUT_ID -> OnboardingFirefoxAccountViewHolder(view)
@ -121,16 +118,6 @@ class SessionControlAdapter(
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
override fun getItemViewType(position: Int) = getItem(position).viewType
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

View File

@ -26,10 +26,11 @@ import org.mozilla.fenix.R
import org.mozilla.fenix.ThemeManager
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.utils.AdapterWithJob
import kotlin.coroutines.CoroutineContext
class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer<BookmarkAction>) :
RecyclerView.Adapter<BookmarkAdapter.BookmarkNodeViewHolder>() {
AdapterWithJob<BookmarkAdapter.BookmarkNodeViewHolder>() {
private var tree: List<BookmarkNode> = listOf()
private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
@ -37,8 +38,6 @@ class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer<BookmarkA
get() = (mode as? BookmarkState.Mode.Selecting)?.selectedItems ?: setOf()
private var isFirstRun = true
lateinit var job: Job
fun updateData(tree: BookmarkNode?, mode: BookmarkState.Mode) {
this.tree = tree?.children ?: listOf()
isFirstRun = if (isFirstRun) false else {
@ -54,13 +53,13 @@ class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer<BookmarkA
return when (viewType) {
BookmarkItemViewHolder.viewType.ordinal -> BookmarkItemViewHolder(
view, actionEmitter, job
view, actionEmitter, adapterJob
)
BookmarkFolderViewHolder.viewType.ordinal -> BookmarkFolderViewHolder(
view, actionEmitter, job
view, actionEmitter, adapterJob
)
BookmarkSeparatorViewHolder.viewType.ordinal -> BookmarkSeparatorViewHolder(
view, actionEmitter, job
view, actionEmitter, adapterJob
)
else -> throw IllegalStateException("ViewType $viewType does not match to a ViewHolder")
}
@ -75,16 +74,6 @@ class BookmarkAdapter(val emptyView: View, val actionEmitter: Observer<BookmarkA
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
override fun getItemCount(): Int = tree.size
override fun onBindViewHolder(holder: BookmarkNodeViewHolder, position: Int) {

View File

@ -10,14 +10,13 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.coroutines.Job
import org.mozilla.fenix.R
import org.mozilla.fenix.library.history.viewholders.HistoryDeleteButtonViewHolder
import org.mozilla.fenix.library.history.viewholders.HistoryHeaderViewHolder
import org.mozilla.fenix.library.history.viewholders.HistoryListItemViewHolder
import java.lang.IllegalStateException
import java.util.Date
import org.mozilla.fenix.utils.AdapterWithJob
import java.util.Calendar
import java.util.Date
private sealed class AdapterItem {
object DeleteButton : AdapterItem()
@ -96,10 +95,9 @@ private class HistoryList(val history: List<HistoryItem>) {
class HistoryAdapter(
private val actionEmitter: Observer<HistoryAction>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
) : AdapterWithJob<RecyclerView.ViewHolder>() {
private var historyList: HistoryList = HistoryList(emptyList())
private var mode: HistoryState.Mode = HistoryState.Mode.Normal
private lateinit var job: Job
var selected = listOf<HistoryItem>()
fun updateData(items: List<HistoryItem>, mode: HistoryState.Mode) {
@ -126,7 +124,7 @@ class HistoryAdapter(
return when (viewType) {
HistoryDeleteButtonViewHolder.LAYOUT_ID -> HistoryDeleteButtonViewHolder(view, actionEmitter)
HistoryHeaderViewHolder.LAYOUT_ID -> HistoryHeaderViewHolder(view)
HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(view, actionEmitter, job)
HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(view, actionEmitter, adapterJob)
else -> throw IllegalStateException()
}
}
@ -144,14 +142,4 @@ class HistoryAdapter(
}
}
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
}

View File

@ -19,10 +19,10 @@ import io.reactivex.Observer
import kotlinx.android.synthetic.main.app_share_list_item.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mozilla.fenix.R
import org.mozilla.fenix.utils.AdapterWithJob
import kotlin.coroutines.CoroutineContext
class AppShareRecyclerView @JvmOverloads constructor(
@ -40,11 +40,10 @@ class AppShareAdapter(
private val context: Context,
val actionEmitter: Observer<ShareAction>,
private val intentType: String = "text/plain"
) : RecyclerView.Adapter<AppShareItemViewHolder>(), CoroutineScope {
) : AdapterWithJob<AppShareItemViewHolder>(), CoroutineScope {
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.IO + job
get() = Dispatchers.IO + adapterJob
private var size: Int = 0
private val shareItems: MutableList<ShareItem> = mutableListOf()
@ -87,16 +86,6 @@ class AppShareAdapter(
override fun onBindViewHolder(holder: AppShareItemViewHolder, position: Int) {
holder.bind(shareItems[position])
}
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
job = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
job.cancel()
}
}
class AppShareItemViewHolder(

View File

@ -0,0 +1,48 @@
package org.mozilla.fenix.utils
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.Job
/* 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/. */
/**
* [RecyclerView.Adapter] with a [Job] for coroutines.
* The adapterJob is setup when the adapter is attached to a RecyclerView and canceled when detached.
*/
abstract class AdapterWithJob<VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {
protected lateinit var adapterJob: Job
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
adapterJob = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
adapterJob.cancel()
}
}
/**
* [ListAdapter] with a [Job] for coroutines.
* The adapterJob is setup when the adapter is attached to a RecyclerView and canceled when detached.
*/
abstract class ListAdapterWithJob<T, VH : RecyclerView.ViewHolder>(
diffCallback: DiffUtil.ItemCallback<T>
) : ListAdapter<T, VH>(diffCallback) {
protected lateinit var adapterJob: Job
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
super.onAttachedToRecyclerView(recyclerView)
adapterJob = Job()
}
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
super.onDetachedFromRecyclerView(recyclerView)
adapterJob.cancel()
}
}