Use glide-like image loading function
parent
ccfaa3826b
commit
88c05a5f43
|
@ -11,20 +11,14 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.reactivex.Observer
|
||||
import kotlinx.android.synthetic.main.collection_tab_list_row.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||
import org.mozilla.fenix.utils.AdapterWithJob
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class CollectionCreationTabListAdapter(
|
||||
val actionEmitter: Observer<CollectionCreationAction>
|
||||
) : AdapterWithJob<TabViewHolder>() {
|
||||
) : RecyclerView.Adapter<TabViewHolder>() {
|
||||
private var tabs: List<Tab> = listOf()
|
||||
private var selectedTabs: MutableSet<Tab> = mutableSetOf()
|
||||
private var hideCheckboxes = false
|
||||
|
@ -33,7 +27,7 @@ class CollectionCreationTabListAdapter(
|
|||
val view =
|
||||
LayoutInflater.from(parent.context).inflate(TabViewHolder.LAYOUT_ID, parent, false)
|
||||
|
||||
return TabViewHolder(view, adapterJob)
|
||||
return TabViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: TabViewHolder, position: Int, payloads: MutableList<Any>) {
|
||||
|
@ -44,11 +38,11 @@ class CollectionCreationTabListAdapter(
|
|||
is CheckChanged -> {
|
||||
val checkChanged = payloads[0] as CheckChanged
|
||||
if (checkChanged.shouldBeChecked) {
|
||||
holder.view.tab_selected_checkbox.isChecked = true
|
||||
holder.itemView.tab_selected_checkbox.isChecked = true
|
||||
} else if (checkChanged.shouldBeUnchecked) {
|
||||
holder.view.tab_selected_checkbox.isChecked = false
|
||||
holder.itemView.tab_selected_checkbox.isChecked = false
|
||||
}
|
||||
holder.view.tab_selected_checkbox.visibility =
|
||||
holder.itemView.tab_selected_checkbox.visibility =
|
||||
if (checkChanged.shouldHideCheckBox) View.GONE else View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +52,7 @@ class CollectionCreationTabListAdapter(
|
|||
override fun onBindViewHolder(holder: TabViewHolder, position: Int) {
|
||||
val tab = tabs[position]
|
||||
val isSelected = selectedTabs.contains(tab)
|
||||
holder.view.tab_selected_checkbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
holder.itemView.tab_selected_checkbox.setOnCheckedChangeListener { _, isChecked ->
|
||||
val action = if (isChecked) {
|
||||
selectedTabs.add(tab)
|
||||
CollectionCreationAction.AddTabToSelection(tab)
|
||||
|
@ -124,14 +118,7 @@ private class TabDiffUtil(
|
|||
|
||||
data class CheckChanged(val shouldBeChecked: Boolean, val shouldBeUnchecked: Boolean, val shouldHideCheckBox: Boolean)
|
||||
|
||||
class TabViewHolder(
|
||||
val view: View,
|
||||
val job: Job
|
||||
) :
|
||||
RecyclerView.ViewHolder(view), CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + job
|
||||
class TabViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private var tab: Tab? = null
|
||||
private val checkbox = view.tab_selected_checkbox!!
|
||||
|
@ -144,21 +131,15 @@ class TabViewHolder(
|
|||
|
||||
fun bind(tab: Tab, isSelected: Boolean, shouldHideCheckBox: Boolean) {
|
||||
this.tab = tab
|
||||
view.hostname.text = tab.hostname
|
||||
view.tab_title.text = tab.title
|
||||
itemView.hostname.text = tab.hostname
|
||||
itemView.tab_title.text = tab.title
|
||||
checkbox.visibility = if (shouldHideCheckBox) View.INVISIBLE else View.VISIBLE
|
||||
view.isClickable = !shouldHideCheckBox
|
||||
itemView.isClickable = !shouldHideCheckBox
|
||||
if (checkbox.isChecked != isSelected) {
|
||||
checkbox.isChecked = isSelected
|
||||
}
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = view.favicon_image.context.components.core.icons
|
||||
.loadIcon(IconRequest(tab.url)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
view.favicon_image.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
itemView.context.components.core.icons.loadIntoView(itemView.favicon_image, tab.url)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -23,9 +23,6 @@ import io.reactivex.Observer
|
|||
import io.reactivex.functions.Consumer
|
||||
import kotlinx.android.synthetic.main.component_collection_creation.*
|
||||
import kotlinx.android.synthetic.main.component_collection_creation.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import mozilla.components.support.ktx.android.view.hideKeyboard
|
||||
import mozilla.components.support.ktx.android.view.showKeyboard
|
||||
import org.mozilla.fenix.R
|
||||
|
@ -36,7 +33,6 @@ import org.mozilla.fenix.ext.urlToTrimmedHost
|
|||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||
import org.mozilla.fenix.mvi.UIView
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class CollectionCreationUIView(
|
||||
container: ViewGroup,
|
||||
|
@ -46,10 +42,7 @@ class CollectionCreationUIView(
|
|||
container,
|
||||
actionEmitter,
|
||||
changesObservable
|
||||
), CoroutineScope {
|
||||
private lateinit var job: Job
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
) {
|
||||
|
||||
override val view = LayoutInflater.from(container.context)
|
||||
.inflate(R.layout.component_collection_creation, container, true)
|
||||
|
@ -67,7 +60,6 @@ class CollectionCreationUIView(
|
|||
private val transition = AutoTransition()
|
||||
|
||||
init {
|
||||
job = Job()
|
||||
transition.duration = TRANSITION_DURATION
|
||||
|
||||
selectTabsConstraints.clone(collection_constraint_layout)
|
||||
|
|
|
@ -10,7 +10,6 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
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,7 +33,7 @@ private class ExceptionsList(val exceptions: List<ExceptionsItem>) {
|
|||
|
||||
class ExceptionsAdapter(
|
||||
private val interactor: ExceptionsInteractor
|
||||
) : AdapterWithJob<RecyclerView.ViewHolder>() {
|
||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private var exceptionsList: ExceptionsList = ExceptionsList(emptyList())
|
||||
|
||||
fun updateData(items: List<ExceptionsItem>) {
|
||||
|
@ -61,11 +60,7 @@ class ExceptionsAdapter(
|
|||
interactor
|
||||
)
|
||||
ExceptionsHeaderViewHolder.LAYOUT_ID -> ExceptionsHeaderViewHolder(view)
|
||||
ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(
|
||||
view,
|
||||
interactor,
|
||||
adapterJob
|
||||
)
|
||||
ExceptionsListItemViewHolder.LAYOUT_ID -> ExceptionsListItemViewHolder(view, interactor)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,25 +7,16 @@ package org.mozilla.fenix.exceptions.viewholders
|
|||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.exception_item.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.exceptions.ExceptionsInteractor
|
||||
import org.mozilla.fenix.exceptions.ExceptionsItem
|
||||
import org.mozilla.fenix.ext.components
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
|
||||
class ExceptionsListItemViewHolder(
|
||||
view: View,
|
||||
private val interactor: ExceptionsInteractor,
|
||||
val job: Job
|
||||
) : RecyclerView.ViewHolder(view), CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + job
|
||||
private val interactor: ExceptionsInteractor
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val favicon = view.favicon_image
|
||||
private val url = view.domainView
|
||||
|
@ -48,13 +39,7 @@ class ExceptionsListItemViewHolder(
|
|||
}
|
||||
|
||||
private fun updateFavIcon(url: String) {
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = favicon.context.components.core.icons
|
||||
.loadIcon(IconRequest(url)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
favicon.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
favicon.context.components.core.icons.loadIntoView(favicon, url)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* 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.ext
|
||||
|
||||
import android.widget.ImageView
|
||||
import mozilla.components.browser.icons.BrowserIcons
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
|
||||
fun BrowserIcons.loadIntoView(view: ImageView, url: String) = loadIntoView(view, IconRequest(url))
|
|
@ -11,6 +11,7 @@ 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 org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHolder
|
||||
|
@ -29,7 +30,6 @@ 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) {
|
||||
|
@ -91,7 +91,7 @@ class AdapterItemDiffCallback : DiffUtil.ItemCallback<AdapterItem>() {
|
|||
|
||||
class SessionControlAdapter(
|
||||
private val actionEmitter: Observer<SessionControlAction>
|
||||
) : ListAdapterWithJob<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
|
||||
) : ListAdapter<AdapterItem, RecyclerView.ViewHolder>(AdapterItemDiffCallback()) {
|
||||
|
||||
// This method triggers the ComplexMethod lint error when in fact it's quite simple.
|
||||
@SuppressWarnings("ComplexMethod")
|
||||
|
@ -99,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, adapterJob)
|
||||
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter)
|
||||
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)
|
||||
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, adapterJob)
|
||||
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter)
|
||||
OnboardingHeaderViewHolder.LAYOUT_ID -> OnboardingHeaderViewHolder(view)
|
||||
OnboardingSectionHeaderViewHolder.LAYOUT_ID -> OnboardingSectionHeaderViewHolder(view)
|
||||
OnboardingFirefoxAccountViewHolder.LAYOUT_ID -> OnboardingFirefoxAccountViewHolder(view)
|
||||
|
|
|
@ -12,34 +12,25 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import io.reactivex.Observer
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.tab_in_collection.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.support.ktx.android.util.dpToFloat
|
||||
import org.jetbrains.anko.backgroundColor
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.getColorFromAttr
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
import org.mozilla.fenix.ext.urlToTrimmedHost
|
||||
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||
import org.mozilla.fenix.home.sessioncontrol.onNext
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import mozilla.components.feature.tab.collections.Tab as ComponentTab
|
||||
|
||||
class TabInCollectionViewHolder(
|
||||
val view: View,
|
||||
val actionEmitter: Observer<SessionControlAction>,
|
||||
val job: Job,
|
||||
override val containerView: View? = view
|
||||
) : RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + job
|
||||
) : RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
lateinit var collection: TabCollection
|
||||
private set
|
||||
|
@ -82,13 +73,7 @@ class TabInCollectionViewHolder(
|
|||
collection_tab_hostname.text = tab.url.urlToTrimmedHost(view.context)
|
||||
|
||||
collection_tab_title.text = tab.title
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = collection_tab_icon.context.components.core.icons
|
||||
.loadIcon(IconRequest(tab.url)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
collection_tab_icon.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
collection_tab_icon.context.components.core.icons.loadIntoView(collection_tab_icon, tab.url)
|
||||
|
||||
// If I'm the last one...
|
||||
if (isLastTab) {
|
||||
|
|
|
@ -12,33 +12,24 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import io.reactivex.Observer
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.tab_list_row.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||
import mozilla.components.support.ktx.android.util.dpToFloat
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.increaseTapArea
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||
import org.mozilla.fenix.home.sessioncontrol.TabAction
|
||||
import org.mozilla.fenix.home.sessioncontrol.onNext
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class TabViewHolder(
|
||||
view: View,
|
||||
actionEmitter: Observer<SessionControlAction>,
|
||||
private val job: Job,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + job
|
||||
RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
var tab: Tab? = null
|
||||
private var tabMenu: TabItemMenu
|
||||
|
@ -92,13 +83,7 @@ class TabViewHolder(
|
|||
private fun updateTabUI(tab: Tab) {
|
||||
hostname.text = tab.hostname
|
||||
tab_title.text = tab.title
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = favicon_image.context.components.core.icons
|
||||
.loadIcon(IconRequest(tab.url)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
favicon_image.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
favicon_image.context.components.core.icons.loadIntoView(favicon_image, tab.url)
|
||||
}
|
||||
|
||||
fun updateSelected(selected: Boolean) {
|
||||
|
|
|
@ -13,12 +13,7 @@ import androidx.recyclerview.widget.DiffUtil
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.bookmark_row.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.appservices.places.BookmarkRoot
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.menu.BrowserMenu
|
||||
import mozilla.components.concept.storage.BookmarkNode
|
||||
import mozilla.components.concept.storage.BookmarkNodeType
|
||||
|
@ -26,11 +21,10 @@ 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
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
|
||||
class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteractor) :
|
||||
AdapterWithJob<BookmarkAdapter.BookmarkNodeViewHolder>() {
|
||||
RecyclerView.Adapter<BookmarkAdapter.BookmarkNodeViewHolder>() {
|
||||
|
||||
private var tree: List<BookmarkNode> = listOf()
|
||||
private var mode: BookmarkState.Mode = BookmarkState.Mode.Normal
|
||||
|
@ -86,13 +80,13 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
|
||||
return when (viewType) {
|
||||
BookmarkItemViewHolder.viewType.ordinal -> BookmarkItemViewHolder(
|
||||
view, interactor, adapterJob
|
||||
view, interactor
|
||||
)
|
||||
BookmarkFolderViewHolder.viewType.ordinal -> BookmarkFolderViewHolder(
|
||||
view, interactor, adapterJob
|
||||
view, interactor
|
||||
)
|
||||
BookmarkSeparatorViewHolder.viewType.ordinal -> BookmarkSeparatorViewHolder(
|
||||
view, interactor, adapterJob
|
||||
view, interactor
|
||||
)
|
||||
else -> throw IllegalStateException("ViewType $viewType does not match to a ViewHolder")
|
||||
}
|
||||
|
@ -120,13 +114,8 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
open class BookmarkNodeViewHolder(
|
||||
view: View,
|
||||
val interactor: BookmarkViewInteractor,
|
||||
private val job: Job,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.Main + job
|
||||
) : RecyclerView.ViewHolder(view), LayoutContainer {
|
||||
|
||||
open fun bind(item: BookmarkNode, mode: BookmarkState.Mode, selected: Boolean) {}
|
||||
}
|
||||
|
@ -134,10 +123,9 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
class BookmarkItemViewHolder(
|
||||
view: View,
|
||||
interactor: BookmarkViewInteractor,
|
||||
job: Job,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
BookmarkNodeViewHolder(view, interactor, job, containerView) {
|
||||
BookmarkNodeViewHolder(view, interactor, containerView) {
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
override fun bind(item: BookmarkNode, mode: BookmarkState.Mode, selected: Boolean) {
|
||||
|
@ -209,14 +197,9 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
bookmark_favicon.backgroundTintList = backgroundTintList
|
||||
if (selected) bookmark_favicon.setImageResource(R.drawable.mozac_ic_check)
|
||||
|
||||
if (!selected && item.url?.startsWith("http") == true) {
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = bookmark_layout.context.components.core.icons
|
||||
.loadIcon(IconRequest(item.url!!)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
bookmark_favicon.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
val url = item.url ?: return
|
||||
if (!selected && url.startsWith("http")) {
|
||||
bookmark_layout.context.components.core.icons.loadIntoView(bookmark_favicon, url)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -251,10 +234,9 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
class BookmarkFolderViewHolder(
|
||||
view: View,
|
||||
interactor: BookmarkViewInteractor,
|
||||
job: Job,
|
||||
override val containerView: View? = view
|
||||
) :
|
||||
BookmarkNodeViewHolder(view, interactor, job, containerView) {
|
||||
BookmarkNodeViewHolder(view, interactor, containerView) {
|
||||
|
||||
override fun bind(item: BookmarkNode, mode: BookmarkState.Mode, selected: Boolean) {
|
||||
containerView?.context?.let {
|
||||
|
@ -353,9 +335,8 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto
|
|||
class BookmarkSeparatorViewHolder(
|
||||
view: View,
|
||||
interactor: BookmarkViewInteractor,
|
||||
job: Job,
|
||||
override val containerView: View? = view
|
||||
) : BookmarkNodeViewHolder(view, interactor, job, containerView) {
|
||||
) : BookmarkNodeViewHolder(view, interactor, containerView) {
|
||||
|
||||
override fun bind(item: BookmarkNode, mode: BookmarkState.Mode, selected: Boolean) {
|
||||
|
||||
|
|
|
@ -14,7 +14,6 @@ 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 org.mozilla.fenix.utils.AdapterWithJob
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
|
@ -94,7 +93,7 @@ private class HistoryList(val history: List<HistoryItem>) {
|
|||
}
|
||||
|
||||
class HistoryAdapter(private val historyInteractor: HistoryInteractor) :
|
||||
AdapterWithJob<RecyclerView.ViewHolder>() {
|
||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||
private var historyList: HistoryList = HistoryList(emptyList())
|
||||
private var mode: HistoryState.Mode = HistoryState.Mode.Normal
|
||||
var selected = listOf<HistoryItem>()
|
||||
|
@ -158,16 +157,9 @@ class HistoryAdapter(private val historyInteractor: HistoryInteractor) :
|
|||
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||
|
||||
return when (viewType) {
|
||||
HistoryDeleteButtonViewHolder.LAYOUT_ID -> HistoryDeleteButtonViewHolder(
|
||||
view,
|
||||
historyInteractor
|
||||
)
|
||||
HistoryDeleteButtonViewHolder.LAYOUT_ID -> HistoryDeleteButtonViewHolder(view, historyInteractor)
|
||||
HistoryHeaderViewHolder.LAYOUT_ID -> HistoryHeaderViewHolder(view)
|
||||
HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(
|
||||
view,
|
||||
historyInteractor,
|
||||
adapterJob
|
||||
)
|
||||
HistoryListItemViewHolder.LAYOUT_ID -> HistoryListItemViewHolder(view, historyInteractor)
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,29 +9,20 @@ import android.widget.CompoundButton
|
|||
import androidx.core.content.ContextCompat
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.android.synthetic.main.history_list_item.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.browser.menu.BrowserMenu
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ThemeManager
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
import org.mozilla.fenix.library.history.HistoryInteractor
|
||||
import org.mozilla.fenix.library.history.HistoryItem
|
||||
import org.mozilla.fenix.library.history.HistoryItemMenu
|
||||
import org.mozilla.fenix.library.history.HistoryState
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
class HistoryListItemViewHolder(
|
||||
view: View,
|
||||
private val historyInteractor: HistoryInteractor,
|
||||
val job: Job
|
||||
) : RecyclerView.ViewHolder(view), CoroutineScope {
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + job
|
||||
private val historyInteractor: HistoryInteractor
|
||||
) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
private val favicon = view.history_favicon
|
||||
private val title = view.history_title
|
||||
|
@ -124,13 +115,7 @@ class HistoryListItemViewHolder(
|
|||
}
|
||||
|
||||
private fun updateFavIcon(url: String) {
|
||||
launch(Dispatchers.IO) {
|
||||
val bitmap = favicon.context.components.core.icons
|
||||
.loadIcon(IconRequest(url)).await().bitmap
|
||||
launch(Dispatchers.Main) {
|
||||
favicon.setImageBitmap(bitmap)
|
||||
}
|
||||
}
|
||||
favicon.context.components.core.icons.loadIntoView(favicon, url)
|
||||
}
|
||||
|
||||
private fun setClickListeners(
|
||||
|
|
|
@ -17,23 +17,17 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceViewHolder
|
||||
import kotlinx.android.synthetic.main.search_engine_radio_button.view.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import mozilla.components.browser.search.SearchEngine
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
abstract class SearchEngineListPreference @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
defStyleAttr: Int = android.R.attr.preferenceStyle
|
||||
) : Preference(context, attrs, defStyleAttr), CompoundButton.OnCheckedChangeListener, CoroutineScope {
|
||||
private val job = Job()
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = job + Dispatchers.Main
|
||||
) : Preference(context, attrs, defStyleAttr), CompoundButton.OnCheckedChangeListener {
|
||||
|
||||
protected var searchEngines: List<SearchEngine> = emptyList()
|
||||
protected var searchEngineGroup: RadioGroup? = null
|
||||
|
||||
|
@ -54,11 +48,6 @@ abstract class SearchEngineListPreference @JvmOverloads constructor(
|
|||
refreshSearchEngineViews(context)
|
||||
}
|
||||
|
||||
override fun onDetached() {
|
||||
job.cancel()
|
||||
super.onDetached()
|
||||
}
|
||||
|
||||
protected abstract fun onSearchEngineSelected(searchEngine: SearchEngine)
|
||||
protected abstract fun updateDefaultItem(defaultButton: CompoundButton)
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
package org.mozilla.fenix.settings
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -24,20 +23,17 @@ import androidx.paging.PagedListAdapter
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.icons.IconRequest
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import org.jetbrains.anko.alert
|
||||
import org.jetbrains.anko.noButton
|
||||
import org.jetbrains.anko.yesButton
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.loadIntoView
|
||||
import org.mozilla.fenix.ext.nav
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
private const val MAX_ITEMS_PER_PAGE = 50
|
||||
|
||||
|
@ -135,21 +131,7 @@ class SitePermissionsViewHolder(val view: View, val iconView: ImageView, val sit
|
|||
RecyclerView.ViewHolder(view)
|
||||
|
||||
class ExceptionsAdapter(private val clickListener: View.OnClickListener) :
|
||||
PagedListAdapter<SitePermissions, SitePermissionsViewHolder>(diffCallback), CoroutineScope {
|
||||
private lateinit var job: Job
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Main + job
|
||||
|
||||
override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onAttachedToRecyclerView(recyclerView)
|
||||
job = Job()
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
job.cancel()
|
||||
}
|
||||
PagedListAdapter<SitePermissions, SitePermissionsViewHolder>(diffCallback) {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SitePermissionsViewHolder {
|
||||
val context = parent.context
|
||||
|
@ -164,15 +146,7 @@ class ExceptionsAdapter(private val clickListener: View.OnClickListener) :
|
|||
val sitePermissions = requireNotNull(getItem(position))
|
||||
val context = holder.view.context
|
||||
|
||||
launch(IO) {
|
||||
|
||||
val bitmap = context.components.core.icons
|
||||
.loadIcon(IconRequest("https://${sitePermissions.origin}/")).await().bitmap
|
||||
launch(Main) {
|
||||
val drawable = BitmapDrawable(context.resources, bitmap)
|
||||
holder.iconView.setImageDrawable(drawable)
|
||||
}
|
||||
}
|
||||
context.components.core.icons.loadIntoView(holder.iconView, "https://${sitePermissions.origin}/")
|
||||
holder.siteTextView.text = sitePermissions.origin
|
||||
holder.view.tag = sitePermissions
|
||||
holder.view.setOnClickListener(clickListener)
|
||||
|
|
|
@ -19,11 +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.cancel
|
||||
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(
|
||||
context: Context,
|
||||
|
@ -40,10 +39,10 @@ class AppShareAdapter(
|
|||
private val context: Context,
|
||||
val actionEmitter: Observer<ShareAction>,
|
||||
private val intentType: String = "text/plain"
|
||||
) : AdapterWithJob<AppShareItemViewHolder>(), CoroutineScope {
|
||||
) : RecyclerView.Adapter<AppShareItemViewHolder>() {
|
||||
|
||||
private var scope = CoroutineScope(Dispatchers.IO)
|
||||
|
||||
override val coroutineContext: CoroutineContext
|
||||
get() = Dispatchers.IO + adapterJob
|
||||
private var size: Int = 0
|
||||
private val shareItems: MutableList<ShareItem> = mutableListOf()
|
||||
|
||||
|
@ -53,7 +52,7 @@ class AppShareAdapter(
|
|||
flags = FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
|
||||
launch {
|
||||
scope.launch {
|
||||
val activities = context.packageManager.queryIntentActivities(testIntent, 0)
|
||||
|
||||
val items = activities.map { resolveInfo ->
|
||||
|
@ -86,6 +85,11 @@ class AppShareAdapter(
|
|||
override fun onBindViewHolder(holder: AppShareItemViewHolder, position: Int) {
|
||||
holder.bind(shareItems[position])
|
||||
}
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
scope.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
class AppShareItemViewHolder(
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
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 initialized to a RecyclerView and canceled when detached.
|
||||
*/
|
||||
abstract class AdapterWithJob<VH : RecyclerView.ViewHolder> : RecyclerView.Adapter<VH>() {
|
||||
protected var adapterJob: Job = 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 initialized to a RecyclerView and canceled when detached.
|
||||
*/
|
||||
abstract class ListAdapterWithJob<T, VH : RecyclerView.ViewHolder>(
|
||||
diffCallback: DiffUtil.ItemCallback<T>
|
||||
) : ListAdapter<T, VH>(diffCallback) {
|
||||
protected var adapterJob: Job = Job()
|
||||
|
||||
override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
|
||||
super.onDetachedFromRecyclerView(recyclerView)
|
||||
adapterJob.cancel()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?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/. -->
|
||||
<resources>
|
||||
<item name="TAG_ICON_JOB" type="id" />
|
||||
</resources>
|
Loading…
Reference in New Issue