1
0
Fork 0

Use glide-like image loading function

master
Tiger Oakes 2019-06-26 16:40:20 -04:00 committed by Emily Kager
parent ccfaa3826b
commit 88c05a5f43
16 changed files with 81 additions and 253 deletions

View File

@ -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 {

View File

@ -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)

View File

@ -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()
}
}

View File

@ -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 {

View File

@ -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))

View File

@ -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)

View File

@ -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) {

View File

@ -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) {

View File

@ -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) {

View File

@ -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()
}
}

View File

@ -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(

View File

@ -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)

View File

@ -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)

View File

@ -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(

View File

@ -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()
}
}

View File

@ -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>