Moves Coil's image loader choice to a subscription on account.
This commit is contained in:
@@ -163,10 +163,11 @@ class Amethyst : Application() {
|
|||||||
|
|
||||||
fun contentResolverFn(): ContentResolver = contentResolver
|
fun contentResolverFn(): ContentResolver = contentResolver
|
||||||
|
|
||||||
fun setImageLoader(shouldUseTor: Boolean?) =
|
fun setImageLoader(shouldUseTor: (String) -> Boolean?) {
|
||||||
ImageLoaderSetup.setup(this, diskCache, memoryCache) {
|
ImageLoaderSetup.setup(this, diskCache, memoryCache) { url ->
|
||||||
shouldUseTor?.let { okHttpClients.getHttpClient(it) } ?: okHttpClients.getHttpClient(false)
|
shouldUseTor(url)?.let { okHttpClients.getHttpClient(it) } ?: okHttpClients.getHttpClient(false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun encryptedStorage(npub: String? = null): EncryptedSharedPreferences = EncryptedStorage.preferences(instance, npub)
|
fun encryptedStorage(npub: String? = null): EncryptedSharedPreferences = EncryptedStorage.preferences(instance, npub)
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,6 @@ class ServiceManager(
|
|||||||
|
|
||||||
val myAccount = account
|
val myAccount = account
|
||||||
|
|
||||||
Amethyst.instance.setImageLoader(myAccount?.shouldUseTorForImageDownload())
|
|
||||||
|
|
||||||
if (myAccount != null) {
|
if (myAccount != null) {
|
||||||
val relaySet = myAccount.connectToRelaysWithProxy.value
|
val relaySet = myAccount.connectToRelaysWithProxy.value
|
||||||
client.reconnect(relaySet)
|
client.reconnect(relaySet)
|
||||||
|
|||||||
@@ -618,6 +618,7 @@ class Account(
|
|||||||
listName,
|
listName,
|
||||||
location = Amethyst.instance.locationManager.geohashStateFlow,
|
location = Amethyst.instance.locationManager.geohashStateFlow,
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
val note = LocalCache.checkGetOrCreateAddressableNote(listName)
|
val note = LocalCache.checkGetOrCreateAddressableNote(listName)
|
||||||
if (note != null) {
|
if (note != null) {
|
||||||
@@ -1126,7 +1127,7 @@ class Account(
|
|||||||
|
|
||||||
class EmojiMedia(
|
class EmojiMedia(
|
||||||
val code: String,
|
val code: String,
|
||||||
val url: MediaUrlImage,
|
val link: MediaUrlImage,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getEmojiPackSelection(): EmojiPackSelectionEvent? = getEmojiPackSelectionNote().event as? EmojiPackSelectionEvent
|
fun getEmojiPackSelection(): EmojiPackSelectionEvent? = getEmojiPackSelectionNote().event as? EmojiPackSelectionEvent
|
||||||
@@ -1173,7 +1174,7 @@ class Account(
|
|||||||
null
|
null
|
||||||
}
|
}
|
||||||
}.flatten()
|
}.flatten()
|
||||||
.distinctBy { it.url }
|
.distinctBy { it.link }
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
val myEmojis by lazy {
|
val myEmojis by lazy {
|
||||||
@@ -3646,11 +3647,33 @@ class Account(
|
|||||||
|
|
||||||
fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME)
|
fun markDonatedInThisVersion() = settings.markDonatedInThisVersion(BuildConfig.VERSION_NAME)
|
||||||
|
|
||||||
fun shouldUseTorForImageDownload() =
|
fun shouldUseTorForImageDownload(url: String) =
|
||||||
when (settings.torSettings.torType.value) {
|
shouldUseTorFor(
|
||||||
TorType.OFF -> false
|
url,
|
||||||
TorType.INTERNAL -> settings.torSettings.imagesViaTor.value
|
settings.torSettings.torType.value,
|
||||||
TorType.EXTERNAL -> settings.torSettings.imagesViaTor.value
|
settings.torSettings.imagesViaTor.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun shouldUseTorFor(
|
||||||
|
url: String,
|
||||||
|
torType: TorType,
|
||||||
|
imagesViaTor: Boolean,
|
||||||
|
) = when (torType) {
|
||||||
|
TorType.OFF -> false
|
||||||
|
TorType.INTERNAL -> shouldUseTor(url, imagesViaTor)
|
||||||
|
TorType.EXTERNAL -> shouldUseTor(url, imagesViaTor)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun shouldUseTor(
|
||||||
|
normalizedUrl: String,
|
||||||
|
final: Boolean,
|
||||||
|
): Boolean =
|
||||||
|
if (isLocalHost(normalizedUrl)) {
|
||||||
|
false
|
||||||
|
} else if (isOnionUrl(normalizedUrl)) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
final
|
||||||
}
|
}
|
||||||
|
|
||||||
fun shouldUseTorForVideoDownload() =
|
fun shouldUseTorForVideoDownload() =
|
||||||
|
|||||||
+87
-10
@@ -24,12 +24,19 @@ import android.app.Application
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import coil3.ImageLoader
|
import coil3.ImageLoader
|
||||||
import coil3.SingletonImageLoader
|
import coil3.SingletonImageLoader
|
||||||
|
import coil3.Uri
|
||||||
import coil3.annotation.DelicateCoilApi
|
import coil3.annotation.DelicateCoilApi
|
||||||
|
import coil3.annotation.ExperimentalCoilApi
|
||||||
import coil3.disk.DiskCache
|
import coil3.disk.DiskCache
|
||||||
|
import coil3.fetch.Fetcher
|
||||||
import coil3.gif.AnimatedImageDecoder
|
import coil3.gif.AnimatedImageDecoder
|
||||||
import coil3.gif.GifDecoder
|
import coil3.gif.GifDecoder
|
||||||
import coil3.memory.MemoryCache
|
import coil3.memory.MemoryCache
|
||||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
import coil3.network.CacheStrategy
|
||||||
|
import coil3.network.ConnectivityChecker
|
||||||
|
import coil3.network.NetworkFetcher
|
||||||
|
import coil3.network.okhttp.asNetworkClient
|
||||||
|
import coil3.request.Options
|
||||||
import coil3.size.Precision
|
import coil3.size.Precision
|
||||||
import coil3.svg.SvgDecoder
|
import coil3.svg.SvgDecoder
|
||||||
import coil3.util.DebugLogger
|
import coil3.util.DebugLogger
|
||||||
@@ -38,12 +45,22 @@ import okhttp3.Call
|
|||||||
|
|
||||||
class ImageLoaderSetup {
|
class ImageLoaderSetup {
|
||||||
companion object {
|
companion object {
|
||||||
|
val gifFactory =
|
||||||
|
if (Build.VERSION.SDK_INT >= 28) {
|
||||||
|
AnimatedImageDecoder.Factory()
|
||||||
|
} else {
|
||||||
|
GifDecoder.Factory()
|
||||||
|
}
|
||||||
|
val svgFactory = SvgDecoder.Factory()
|
||||||
|
|
||||||
|
val debugLogger = if (isDebug) DebugLogger() else null
|
||||||
|
|
||||||
@OptIn(DelicateCoilApi::class)
|
@OptIn(DelicateCoilApi::class)
|
||||||
fun setup(
|
fun setup(
|
||||||
app: Application,
|
app: Application,
|
||||||
diskCache: DiskCache,
|
diskCache: DiskCache,
|
||||||
memoryCache: MemoryCache,
|
memoryCache: MemoryCache,
|
||||||
callFactory: () -> Call.Factory,
|
callFactory: (url: String) -> Call.Factory,
|
||||||
) {
|
) {
|
||||||
SingletonImageLoader.setUnsafe(
|
SingletonImageLoader.setUnsafe(
|
||||||
ImageLoader
|
ImageLoader
|
||||||
@@ -51,21 +68,81 @@ class ImageLoaderSetup {
|
|||||||
.diskCache { diskCache }
|
.diskCache { diskCache }
|
||||||
.memoryCache { memoryCache }
|
.memoryCache { memoryCache }
|
||||||
.precision(Precision.INEXACT)
|
.precision(Precision.INEXACT)
|
||||||
.logger(if (isDebug) DebugLogger() else null)
|
.logger(debugLogger)
|
||||||
.components {
|
.components {
|
||||||
if (Build.VERSION.SDK_INT >= 28) {
|
add(gifFactory)
|
||||||
add(AnimatedImageDecoder.Factory())
|
add(svgFactory)
|
||||||
} else {
|
|
||||||
add(GifDecoder.Factory())
|
|
||||||
}
|
|
||||||
add(SvgDecoder.Factory())
|
|
||||||
add(Base64Fetcher.Factory)
|
add(Base64Fetcher.Factory)
|
||||||
add(BlurHashFetcher.Factory)
|
add(BlurHashFetcher.Factory)
|
||||||
add(Base64Fetcher.BKeyer)
|
add(Base64Fetcher.BKeyer)
|
||||||
add(BlurHashFetcher.BKeyer)
|
add(BlurHashFetcher.BKeyer)
|
||||||
add(OkHttpNetworkFetcherFactory(callFactory))
|
add(OkHttpFactory(callFactory))
|
||||||
}.build(),
|
}.build(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copied from Coil to allow networkClient to be a function of the url.
|
||||||
|
* So that Tor and non Tor clients can be used.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalCoilApi::class)
|
||||||
|
class OkHttpFactory(
|
||||||
|
val networkClient: (url: String) -> Call.Factory,
|
||||||
|
) : Fetcher.Factory<Uri> {
|
||||||
|
private val cacheStrategyLazy = lazy { CacheStrategy.DEFAULT }
|
||||||
|
private val connectivityCheckerLazy = singleParameterLazy(::ConnectivityChecker)
|
||||||
|
|
||||||
|
override fun create(
|
||||||
|
data: Uri,
|
||||||
|
options: Options,
|
||||||
|
imageLoader: ImageLoader,
|
||||||
|
): Fetcher? {
|
||||||
|
if (!isApplicable(data)) return null
|
||||||
|
|
||||||
|
val url = data.toString()
|
||||||
|
|
||||||
|
return NetworkFetcher(
|
||||||
|
url = url,
|
||||||
|
options = options,
|
||||||
|
networkClient = lazy { networkClient(url).asNetworkClient() },
|
||||||
|
diskCache = lazy { imageLoader.diskCache },
|
||||||
|
cacheStrategy = cacheStrategyLazy,
|
||||||
|
connectivityChecker = connectivityCheckerLazy.get(options.context),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isApplicable(data: Uri): Boolean = data.scheme == "http" || data.scheme == "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun <P, T> singleParameterLazy(initializer: (P) -> T) = SingleParameterLazy(initializer)
|
||||||
|
|
||||||
|
internal class SingleParameterLazy<P, T>(
|
||||||
|
initializer: (P) -> T,
|
||||||
|
) : Any() {
|
||||||
|
private var initializer: ((P) -> T)? = initializer
|
||||||
|
private var value: Any? = UNINITIALIZED
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun get(parameter: P): T {
|
||||||
|
val value1 = value
|
||||||
|
if (value1 !== UNINITIALIZED) {
|
||||||
|
return value1 as T
|
||||||
|
}
|
||||||
|
|
||||||
|
return synchronized(this) {
|
||||||
|
val value2 = value
|
||||||
|
if (value2 !== UNINITIALIZED) {
|
||||||
|
value2 as T
|
||||||
|
} else {
|
||||||
|
val newValue = initializer!!(parameter)
|
||||||
|
value = newValue
|
||||||
|
initializer = null
|
||||||
|
newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object UNINITIALIZED
|
||||||
|
|||||||
@@ -879,7 +879,7 @@ open class NewPostViewModel :
|
|||||||
): List<EmojiUrlTag> {
|
): List<EmojiUrlTag> {
|
||||||
if (myEmojiSet == null) return emptyList()
|
if (myEmojiSet == null) return emptyList()
|
||||||
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
||||||
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.url.url) }
|
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.link.url) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1078,12 +1078,12 @@ open class NewPostViewModel :
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
||||||
val wordToInsert = item.url.url + " "
|
val wordToInsert = item.link.url + " "
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
iMetaAttachments.downloadAndPrepare(
|
iMetaAttachments.downloadAndPrepare(
|
||||||
item.url.url,
|
item.link.url,
|
||||||
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload() ?: false) },
|
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -80,7 +80,7 @@ fun ShowEmojiSuggestionList(
|
|||||||
horizontalArrangement = spacedBy(Size10dp),
|
horizontalArrangement = spacedBy(Size10dp),
|
||||||
) {
|
) {
|
||||||
Box(Size40Modifier) {
|
Box(Size40Modifier) {
|
||||||
UrlImageView(it.url, accountViewModel)
|
UrlImageView(it.link, accountViewModel)
|
||||||
}
|
}
|
||||||
Text(it.code, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
|
Text(it.code, fontWeight = FontWeight.Bold, modifier = Modifier.weight(1f))
|
||||||
Box(Size40Modifier, contentAlignment = Alignment.Center) {
|
Box(Size40Modifier, contentAlignment = Alignment.Center) {
|
||||||
|
|||||||
+1
-1
@@ -1522,7 +1522,7 @@ class AccountViewModel(
|
|||||||
|
|
||||||
fun okHttpClientForNip96(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForNIP96(url))
|
fun okHttpClientForNip96(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForNIP96(url))
|
||||||
|
|
||||||
fun okHttpClientForImage(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForImageDownload())
|
fun okHttpClientForImage(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForImageDownload(url))
|
||||||
|
|
||||||
fun okHttpClientForVideo(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForVideoDownload(url))
|
fun okHttpClientForVideo(url: String): OkHttpClient = Amethyst.instance.okHttpClients.getHttpClient(account.shouldUseTorForVideoDownload(url))
|
||||||
|
|
||||||
|
|||||||
+12
-1
@@ -84,9 +84,13 @@ fun LoggedInPage(
|
|||||||
// Adds this account to the authentication procedures for relays.
|
// Adds this account to the authentication procedures for relays.
|
||||||
RelayAuthSubscription(accountViewModel)
|
RelayAuthSubscription(accountViewModel)
|
||||||
|
|
||||||
// Loads account information from Relays.
|
// Sets up Coil's Image Loader
|
||||||
|
ObserveImageLoadingTor(accountViewModel)
|
||||||
|
|
||||||
|
// Loads account information + DMs and Notifications from Relays.
|
||||||
AccountFilterAssemblerSubscription(accountViewModel)
|
AccountFilterAssemblerSubscription(accountViewModel)
|
||||||
|
|
||||||
|
// Pre-loads each of the main screens.
|
||||||
HomeFilterAssemblerSubscription(accountViewModel)
|
HomeFilterAssemblerSubscription(accountViewModel)
|
||||||
ChatroomListFilterAssemblerSubscription(accountViewModel)
|
ChatroomListFilterAssemblerSubscription(accountViewModel)
|
||||||
VideoFilterAssemblerSubscription(accountViewModel)
|
VideoFilterAssemblerSubscription(accountViewModel)
|
||||||
@@ -124,6 +128,13 @@ fun ObserveAntiSpamFilterSettings(accountViewModel: AccountViewModel) {
|
|||||||
Amethyst.instance.cache.antiSpam.active = isSpamActive
|
Amethyst.instance.cache.antiSpam.active = isSpamActive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ObserveImageLoadingTor(accountViewModel: AccountViewModel) {
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
Amethyst.instance.setImageLoader(accountViewModel.account::shouldUseTorForImageDownload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ManageRelayServices(
|
fun ManageRelayServices(
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
|
|||||||
+4
-4
@@ -502,7 +502,7 @@ class ChatNewMessageViewModel :
|
|||||||
): List<EmojiUrlTag> {
|
): List<EmojiUrlTag> {
|
||||||
if (myEmojiSet == null) return emptyList()
|
if (myEmojiSet == null) return emptyList()
|
||||||
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
||||||
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.url.url) }
|
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.link.url) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,12 +647,12 @@ class ChatNewMessageViewModel :
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
||||||
val wordToInsert = item.url.url + " "
|
val wordToInsert = item.link.url + " "
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
iMetaAttachments.downloadAndPrepare(
|
iMetaAttachments.downloadAndPrepare(
|
||||||
item.url.url,
|
item.link.url,
|
||||||
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload() ?: false) },
|
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -464,7 +464,7 @@ open class ChannelNewMessageViewModel :
|
|||||||
): List<EmojiUrlTag> {
|
): List<EmojiUrlTag> {
|
||||||
if (myEmojiSet == null) return emptyList()
|
if (myEmojiSet == null) return emptyList()
|
||||||
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
||||||
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.url.url) }
|
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.link.url) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -561,12 +561,12 @@ open class ChannelNewMessageViewModel :
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
||||||
val wordToInsert = item.url.url + " "
|
val wordToInsert = item.link.url + " "
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
iMetaAttachments.downloadAndPrepare(
|
iMetaAttachments.downloadAndPrepare(
|
||||||
item.url.url,
|
item.link.url,
|
||||||
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload() ?: false) },
|
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -374,7 +374,7 @@ open class NewProductViewModel :
|
|||||||
): List<EmojiUrlTag> {
|
): List<EmojiUrlTag> {
|
||||||
if (myEmojiSet == null) return emptyList()
|
if (myEmojiSet == null) return emptyList()
|
||||||
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
return CustomEmoji.findAllEmojiCodes(message).mapNotNull { possibleEmoji ->
|
||||||
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.url.url) }
|
myEmojiSet.firstOrNull { it.code == possibleEmoji }?.let { EmojiUrlTag(it.code, it.link.url) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,12 +555,12 @@ open class NewProductViewModel :
|
|||||||
}
|
}
|
||||||
|
|
||||||
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
open fun autocompleteWithEmojiUrl(item: Account.EmojiMedia) {
|
||||||
val wordToInsert = item.url.url + " "
|
val wordToInsert = item.link.url + " "
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
iMetaDescription.downloadAndPrepare(
|
iMetaDescription.downloadAndPrepare(
|
||||||
item.url.url,
|
item.link.url,
|
||||||
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload() ?: false) },
|
{ Amethyst.instance.okHttpClients.getHttpClient(accountViewModel?.account?.shouldUseTorForImageDownload(item.link.url) ?: false) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user