mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 17:29:32 +01:00
Improve organization of glide packages.
Generic image processing classes were scattered alongside Signal-specific Glide code across multiple packages: `org.signal.glide`, `org.thoughtcrime.securesms.glide` and `org.thoughtcrime.securesms.mms`. This change provides a clearer separation of concerns: - `org.signal.glide` contains generic image loading components - `org.thoughtcrime.securesms.glide` contains Signal-specific Glide integrations - Feature-specific loaders are moved to their respective domain packages (e.g. `.badges`, `.contacts`)
This commit is contained in:
committed by
Jeffrey Starke
parent
cc43add7af
commit
47508495ed
@@ -8,15 +8,14 @@ import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.RequestManager
|
||||
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.badges.glide.BadgeSpriteTransformation
|
||||
import org.thoughtcrime.securesms.badges.load.BadgeSpriteTransformation
|
||||
import org.thoughtcrime.securesms.badges.load.GiftBadgeModel
|
||||
import org.thoughtcrime.securesms.badges.models.Badge
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.BadgeImageSize
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.glide.GiftBadgeModel
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.util.ScreenDensity
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
class BadgeImageView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.badges.load;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.load.Options;
|
||||
import com.bumptech.glide.load.model.GlideUrl;
|
||||
import com.bumptech.glide.load.model.ModelLoader;
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory;
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory;
|
||||
|
||||
import org.thoughtcrime.securesms.badges.models.Badge;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.glide.OkHttpStreamFetcher;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
/**
|
||||
* A loader which will load a sprite sheet for a particular badge at the correct dpi for this device.
|
||||
*/
|
||||
public class BadgeLoader implements ModelLoader<Badge, InputStream> {
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
private BadgeLoader(OkHttpClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable LoadData<InputStream> buildLoadData(@NonNull Badge request, int width, int height, @NonNull Options options) {
|
||||
return new LoadData<>(request, new OkHttpStreamFetcher(client, new GlideUrl(request.getImageUrl().toString())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handles(@NonNull Badge badgeSpriteSheetRequest) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Factory createFactory() {
|
||||
return new Factory(AppDependencies.getSignalOkHttpClient());
|
||||
}
|
||||
|
||||
public static class Factory implements ModelLoaderFactory<Badge, InputStream> {
|
||||
|
||||
private final OkHttpClient client;
|
||||
|
||||
private Factory(@NonNull OkHttpClient client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ModelLoader<Badge, InputStream> build(@NonNull MultiModelLoaderFactory multiFactory) {
|
||||
return new BadgeLoader(client);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teardown() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,9 @@
|
||||
package org.thoughtcrime.securesms.badges.glide
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.badges.load
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2025 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.badges.load
|
||||
|
||||
import com.bumptech.glide.Priority
|
||||
import com.bumptech.glide.load.DataSource
|
||||
import com.bumptech.glide.load.Key
|
||||
import com.bumptech.glide.load.Options
|
||||
import com.bumptech.glide.load.data.DataFetcher
|
||||
import com.bumptech.glide.load.model.GlideUrl
|
||||
import com.bumptech.glide.load.model.ModelLoader
|
||||
import com.bumptech.glide.load.model.ModelLoaderFactory
|
||||
import com.bumptech.glide.load.model.MultiModelLoaderFactory
|
||||
import okhttp3.OkHttpClient
|
||||
import org.signal.libsignal.zkgroup.receipts.ReceiptCredentialPresentation
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.getBadge
|
||||
import org.thoughtcrime.securesms.database.model.databaseprotos.GiftBadge
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies
|
||||
import org.thoughtcrime.securesms.glide.OkHttpStreamFetcher
|
||||
import java.io.InputStream
|
||||
import java.security.MessageDigest
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* Glide Model allowing the direct loading of a GiftBadge.
|
||||
*
|
||||
* This model will first resolve a GiftBadge into a Badge, and then it will delegate to the Badge loader.
|
||||
*/
|
||||
data class GiftBadgeModel(val giftBadge: GiftBadge) : Key {
|
||||
class Loader(val client: OkHttpClient) : ModelLoader<GiftBadgeModel, InputStream> {
|
||||
override fun buildLoadData(model: GiftBadgeModel, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
|
||||
return ModelLoader.LoadData(model, Fetcher(client, model))
|
||||
}
|
||||
|
||||
override fun handles(model: GiftBadgeModel): Boolean = true
|
||||
}
|
||||
|
||||
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
|
||||
messageDigest.update(giftBadge.encode())
|
||||
}
|
||||
|
||||
class Fetcher(
|
||||
private val client: OkHttpClient,
|
||||
private val giftBadge: GiftBadgeModel
|
||||
) : DataFetcher<InputStream> {
|
||||
|
||||
private var okHttpStreamFetcher: OkHttpStreamFetcher? = null
|
||||
|
||||
override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) {
|
||||
try {
|
||||
val receiptCredentialPresentation = ReceiptCredentialPresentation(giftBadge.giftBadge.redemptionToken.toByteArray())
|
||||
val giftBadgeResponse = AppDependencies.donationsService.getDonationsConfiguration(Locale.getDefault())
|
||||
if (giftBadgeResponse.result.isPresent) {
|
||||
val badge = giftBadgeResponse.result.get().getBadge(receiptCredentialPresentation.receiptLevel.toInt())
|
||||
okHttpStreamFetcher = OkHttpStreamFetcher(client, GlideUrl(badge.imageUrl.toString()))
|
||||
okHttpStreamFetcher?.loadData(priority, callback)
|
||||
} else if (giftBadgeResponse.applicationError.isPresent) {
|
||||
callback.onLoadFailed(Exception(giftBadgeResponse.applicationError.get()))
|
||||
} else if (giftBadgeResponse.executionError.isPresent) {
|
||||
callback.onLoadFailed(Exception(giftBadgeResponse.executionError.get()))
|
||||
} else {
|
||||
callback.onLoadFailed(Exception("No result or error in service response."))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
callback.onLoadFailed(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun cleanup() {
|
||||
okHttpStreamFetcher?.cleanup()
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
okHttpStreamFetcher?.cancel()
|
||||
}
|
||||
|
||||
override fun getDataClass(): Class<InputStream> {
|
||||
return InputStream::class.java
|
||||
}
|
||||
|
||||
override fun getDataSource(): DataSource {
|
||||
return DataSource.REMOTE
|
||||
}
|
||||
}
|
||||
|
||||
class Factory(private val client: OkHttpClient) : ModelLoaderFactory<GiftBadgeModel, InputStream> {
|
||||
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<GiftBadgeModel, InputStream> {
|
||||
return Loader(client)
|
||||
}
|
||||
|
||||
override fun teardown() {}
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun createFactory(): Factory {
|
||||
return Factory(AppDependencies.signalOkHttpClient)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.badges.glide.BadgeSpriteTransformation
|
||||
import org.thoughtcrime.securesms.badges.load.BadgeSpriteTransformation
|
||||
import org.thoughtcrime.securesms.components.settings.PreferenceModel
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
|
||||
Reference in New Issue
Block a user