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