Migrate to glide v4

This commit is contained in:
Tlaster 2020-04-13 17:33:36 +08:00
parent fc2bbe857b
commit a2cec21b18
16 changed files with 133 additions and 78 deletions

View File

@ -77,9 +77,9 @@ subprojects {
Chameleon : '0.9.28', Chameleon : '0.9.28',
UniqR : '0.9.4', UniqR : '0.9.4',
SQLiteQB : '0.9.15', SQLiteQB : '0.9.15',
Glide : '3.7.0', Glide : '4.11.0',
GlideOkHttp3 : '1.4.0', GlideOkHttp3 : '4.11.0',
GlideTransformations : '2.0.2', GlideTransformations : '4.1.0',
AndroidImageCropper : '2.4.6', AndroidImageCropper : '2.4.6',
ExportablePreferences: '0.9.7', ExportablePreferences: '0.9.7',
ACRA : '4.9.2', ACRA : '4.9.2',

View File

@ -253,6 +253,7 @@ dependencies {
implementation "com.google.android.exoplayer:exoplayer:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:exoplayer:${libVersions['Exoplayer']}"
implementation "com.google.android.exoplayer:extension-okhttp:${libVersions['Exoplayer']}" implementation "com.google.android.exoplayer:extension-okhttp:${libVersions['Exoplayer']}"
implementation "com.github.bumptech.glide:glide:${libVersions['Glide']}" implementation "com.github.bumptech.glide:glide:${libVersions['Glide']}"
kapt "com.github.bumptech.glide:compiler:${libVersions['Glide']}"
implementation "com.github.bumptech.glide:okhttp3-integration:${libVersions['GlideOkHttp3']}@aar" implementation "com.github.bumptech.glide:okhttp3-integration:${libVersions['GlideOkHttp3']}@aar"
implementation "jp.wasabeef:glide-transformations:${libVersions['GlideTransformations']}" implementation "jp.wasabeef:glide-transformations:${libVersions['GlideTransformations']}"
implementation "com.theartofdev.edmodo:android-image-cropper:${libVersions['AndroidImageCropper']}" implementation "com.theartofdev.edmodo:android-image-cropper:${libVersions['AndroidImageCropper']}"

View File

@ -74,7 +74,16 @@
} }
# https://github.com/bumptech/glide # https://github.com/bumptech/glide
-keep class * extends com.bumptech.glide.module.GlideModule -keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
# for DexGuard only
-keepresourcexmlelements manifest/application/meta-data@value=GlideModule
# Essential components # Essential components
-keep class * extends org.mariotaku.twidere.util.Analyzer -keep class * extends org.mariotaku.twidere.util.Analyzer

View File

@ -858,7 +858,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
accountsCount.setText(null) accountsCount.setText(null)
if (displayDoneIcon) { if (displayDoneIcon) {
Glide.clear(accountProfileImage) Glide.with(this).clear(accountProfileImage)
accountProfileImage.setColorFilter(ThemeUtils.getColorFromAttribute(this, accountProfileImage.setColorFilter(ThemeUtils.getColorFromAttribute(this,
android.R.attr.colorForeground)) android.R.attr.colorForeground))
accountProfileImage.scaleType = ImageView.ScaleType.CENTER_INSIDE accountProfileImage.scaleType = ImageView.ScaleType.CENTER_INSIDE
@ -874,7 +874,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
} else { } else {
accountsCount.setText(accounts.size.toString()) accountsCount.setText(accounts.size.toString())
Glide.clear(accountProfileImage) Glide.with(this).clear(accountProfileImage)
if (displayDoneIcon) { if (displayDoneIcon) {
accountProfileImage.setColorFilter(ThemeUtils.getColorFromAttribute(this, accountProfileImage.setColorFilter(ThemeUtils.getColorFromAttribute(this,
android.R.attr.colorForeground)) android.R.attr.colorForeground))

View File

@ -20,11 +20,10 @@
package org.mariotaku.twidere.extension package org.mariotaku.twidere.extension
import android.content.Context import android.content.Context
import com.bumptech.glide.DrawableRequestBuilder import android.graphics.drawable.Drawable
import com.bumptech.glide.DrawableTypeRequest import com.bumptech.glide.RequestBuilder
import com.bumptech.glide.RequestManager import com.bumptech.glide.RequestManager
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import jp.wasabeef.glide.transformations.CropCircleTransformation
import org.mariotaku.twidere.R import org.mariotaku.twidere.R
import org.mariotaku.twidere.annotation.ImageShapeStyle import org.mariotaku.twidere.annotation.ImageShapeStyle
import org.mariotaku.twidere.extension.model.getBestProfileBanner import org.mariotaku.twidere.extension.model.getBestProfileBanner
@ -35,7 +34,7 @@ import org.mariotaku.twidere.util.Utils
import org.mariotaku.twidere.util.glide.RoundedRectTransformation import org.mariotaku.twidere.util.glide.RoundedRectTransformation
fun RequestManager.loadProfileImage(context: Context, url: String?, @ImageShapeStyle style: Int, fun RequestManager.loadProfileImage(context: Context, url: String?, @ImageShapeStyle style: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, style, cornerRadius, cornerRadiusRatio) { return configureLoadProfileImage(context, style, cornerRadius, cornerRadiusRatio) {
if (url == null || size == null) { if (url == null || size == null) {
return@configureLoadProfileImage load(url) return@configureLoadProfileImage load(url)
@ -46,17 +45,17 @@ fun RequestManager.loadProfileImage(context: Context, url: String?, @ImageShapeS
} }
fun RequestManager.loadProfileImage(context: Context, resourceId: Int, @ImageShapeStyle shapeStyle: Int, fun RequestManager.loadProfileImage(context: Context, resourceId: Int, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<Int> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { load(resourceId) } return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { load(resourceId) }
} }
fun RequestManager.loadProfileImage(context: Context, account: AccountDetails, @ImageShapeStyle shapeStyle: Int, fun RequestManager.loadProfileImage(context: Context, account: AccountDetails, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): RequestBuilder<Drawable> {
return loadProfileImage(context, account.user, shapeStyle, cornerRadius, cornerRadiusRatio, size) return loadProfileImage(context, account.user, shapeStyle, cornerRadius, cornerRadiusRatio, size)
} }
fun RequestManager.loadProfileImage(context: Context, user: ParcelableUser, @ImageShapeStyle shapeStyle: Int, fun RequestManager.loadProfileImage(context: Context, user: ParcelableUser, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): RequestBuilder<Drawable> {
if (user.extras != null && user.extras?.profile_image_url_fallback == null) { if (user.extras != null && user.extras?.profile_image_url_fallback == null) {
// No fallback image, use compatible logic // No fallback image, use compatible logic
return loadProfileImage(context, user.profile_image_url, shapeStyle, cornerRadius, return loadProfileImage(context, user.profile_image_url, shapeStyle, cornerRadius,
@ -72,7 +71,7 @@ fun RequestManager.loadProfileImage(context: Context, user: ParcelableUser, @Ima
} }
fun RequestManager.loadProfileImage(context: Context, user: ParcelableLiteUser, @ImageShapeStyle shapeStyle: Int, fun RequestManager.loadProfileImage(context: Context, user: ParcelableLiteUser, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
if (size != null) { if (size != null) {
return@configureLoadProfileImage load(Utils.getTwitterProfileImageOfSize(user.profile_image_url, size)) return@configureLoadProfileImage load(Utils.getTwitterProfileImageOfSize(user.profile_image_url, size))
@ -84,7 +83,7 @@ fun RequestManager.loadProfileImage(context: Context, user: ParcelableLiteUser,
fun RequestManager.loadProfileImage(context: Context, userList: ParcelableUserList, fun RequestManager.loadProfileImage(context: Context, userList: ParcelableUserList,
@ImageShapeStyle shapeStyle: Int, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(userList.user_profile_image_url) load(userList.user_profile_image_url)
} }
@ -92,14 +91,14 @@ fun RequestManager.loadProfileImage(context: Context, userList: ParcelableUserLi
fun RequestManager.loadProfileImage(context: Context, group: ParcelableGroup, fun RequestManager.loadProfileImage(context: Context, group: ParcelableGroup,
@ImageShapeStyle shapeStyle: Int, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(group.homepage_logo) load(group.homepage_logo)
} }
} }
fun RequestManager.loadProfileImage(context: Context, status: ParcelableStatus, @ImageShapeStyle shapeStyle: Int, fun RequestManager.loadProfileImage(context: Context, status: ParcelableStatus, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): DrawableRequestBuilder<String?> { cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, size: String? = null): RequestBuilder<Drawable> {
if (status.extras?.user_profile_image_url_fallback == null) { if (status.extras?.user_profile_image_url_fallback == null) {
// No fallback image, use compatible logic // No fallback image, use compatible logic
return loadProfileImage(context, status.user_profile_image_url, shapeStyle, cornerRadius, return loadProfileImage(context, status.user_profile_image_url, shapeStyle, cornerRadius,
@ -112,7 +111,7 @@ fun RequestManager.loadProfileImage(context: Context, status: ParcelableStatus,
fun RequestManager.loadProfileImage(context: Context, conversation: ParcelableMessageConversation, fun RequestManager.loadProfileImage(context: Context, conversation: ParcelableMessageConversation,
@ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, @ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f,
size: String? = null): DrawableRequestBuilder<*> { size: String? = null): RequestBuilder<*> {
if (conversation.conversation_type == ParcelableMessageConversation.ConversationType.ONE_TO_ONE) { if (conversation.conversation_type == ParcelableMessageConversation.ConversationType.ONE_TO_ONE) {
val user = conversation.user val user = conversation.user
if (user != null) { if (user != null) {
@ -135,30 +134,30 @@ fun RequestManager.loadProfileImage(context: Context, conversation: ParcelableMe
fun RequestManager.loadOriginalProfileImage(context: Context, user: ParcelableUser, fun RequestManager.loadOriginalProfileImage(context: Context, user: ParcelableUser,
@ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f @ImageShapeStyle shapeStyle: Int, cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f
): DrawableRequestBuilder<String> { ): RequestBuilder<Drawable> {
return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) { return configureLoadProfileImage(context, shapeStyle, cornerRadius, cornerRadiusRatio) {
load(user.originalProfileImage) load(user.originalProfileImage)
} }
} }
fun RequestManager.loadProfileBanner(context: Context, user: ParcelableUser, width: Int): DrawableTypeRequest<String?> { fun RequestManager.loadProfileBanner(context: Context, user: ParcelableUser, width: Int): RequestBuilder<Drawable> {
val ratio = context.resources.getFraction(R.fraction.aspect_ratio_profile_banner, 1, 1) val ratio = context.resources.getFraction(R.fraction.aspect_ratio_profile_banner, 1, 1)
return load(user.getBestProfileBanner(width, (width / ratio).toInt())) return load(user.getBestProfileBanner(width, (width / ratio).toInt()))
} }
internal inline fun <T> configureLoadProfileImage(context: Context, @ImageShapeStyle shapeStyle: Int, internal inline fun <T> configureLoadProfileImage(context: Context, @ImageShapeStyle shapeStyle: Int,
cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, create: () -> DrawableTypeRequest<T> cornerRadius: Float = 0f, cornerRadiusRatio: Float = 0f, create: () -> RequestBuilder<T>
): DrawableRequestBuilder<T> { ): RequestBuilder<T> {
val builder = create() val builder = create()
builder.diskCacheStrategy(DiskCacheStrategy.RESULT) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
builder.centerCrop() .centerCrop()
builder.dontAnimate() .dontAnimate()
when (shapeStyle) { when (shapeStyle) {
ImageShapeStyle.SHAPE_CIRCLE -> { ImageShapeStyle.SHAPE_CIRCLE -> {
builder.bitmapTransform(CropCircleTransformation(context)) builder.circleCrop()
} }
ImageShapeStyle.SHAPE_RECTANGLE -> { ImageShapeStyle.SHAPE_RECTANGLE -> {
builder.bitmapTransform(RoundedRectTransformation(context, cornerRadius, builder.transform(RoundedRectTransformation(context, cornerRadius,
cornerRadiusRatio)) cornerRadiusRatio))
} }
} }

View File

@ -3,6 +3,8 @@ package org.mariotaku.twidere.extension.model
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.text.TextUtils import android.text.TextUtils
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import org.mariotaku.microblog.library.MicroBlog import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.fanfou.FanfouStream import org.mariotaku.microblog.library.fanfou.FanfouStream
@ -21,6 +23,7 @@ import org.mariotaku.restfu.oauth.OAuthAuthorization
import org.mariotaku.restfu.oauth.OAuthEndpoint import org.mariotaku.restfu.oauth.OAuthEndpoint
import org.mariotaku.restfu.oauth.OAuthToken import org.mariotaku.restfu.oauth.OAuthToken
import org.mariotaku.restfu.oauth2.OAuth2Authorization import org.mariotaku.restfu.oauth2.OAuth2Authorization
import org.mariotaku.restfu.okhttp3.OkHttpRestClient
import org.mariotaku.twidere.TwidereConstants.DEFAULT_TWITTER_API_URL_FORMAT import org.mariotaku.twidere.TwidereConstants.DEFAULT_TWITTER_API_URL_FORMAT
import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.annotation.AccountType
import org.mariotaku.twidere.model.account.cred.* import org.mariotaku.twidere.model.account.cred.*

View File

@ -63,7 +63,7 @@ open class BaseDialogFragment : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
requestManager = Glide.with(context)// TODO: Upgrade Glide usage requestManager = Glide.with(context!!)// TODO: Upgrade Glide usage
} }
override fun onStart() { override fun onStart() {

View File

@ -102,7 +102,7 @@ open class BaseFragment : Fragment(), IBaseFragment<BaseFragment> {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
requestManager = Glide.with(context)// TODO: Upgrade Glide usage requestManager = Glide.with(context!!)// TODO: Upgrade Glide usage
} }
override fun onStart() { override fun onStart() {
@ -126,7 +126,7 @@ open class BaseFragment : Fragment(), IBaseFragment<BaseFragment> {
} }
override fun onDestroy() { override fun onDestroy() {
requestManager.onDestroy() // requestManager.onDestroy()
extraFeaturesService.release() extraFeaturesService.release()
super.onDestroy() super.onDestroy()
// DebugModeUtils.watchReferenceLeak(this) // DebugModeUtils.watchReferenceLeak(this)

View File

@ -23,6 +23,7 @@ import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import androidx.palette.graphics.Palette import androidx.palette.graphics.Palette
import android.view.LayoutInflater import android.view.LayoutInflater
@ -30,7 +31,6 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.drawable.GlideDrawable
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import io.nayuki.qrcodegen.QrCode import io.nayuki.qrcodegen.QrCode
import io.nayuki.qrcodegen.QrSegment import io.nayuki.qrcodegen.QrSegment
@ -114,13 +114,13 @@ class UserQrDialogFragment : BaseDialogFragment() {
} }
} }
private fun loadProfileImage(): Promise<GlideDrawable, Exception> { private fun loadProfileImage(): Promise<Drawable, Exception> {
if (context == null || isDetached || dialog == null || (activity?.isFinishing != false)) { if (context == null || isDetached || dialog == null || (activity?.isFinishing != false)) {
return Promise.ofFail(InterruptedException()) return Promise.ofFail(InterruptedException())
} }
val profileImageSize = getString(R.string.profile_image_size) val profileImageSize = getString(R.string.profile_image_size)
val context = context?.applicationContext val context = context?.applicationContext
val requestManager = Glide.with(context) val requestManager = Glide.with(context!!)
val user = this.user val user = this.user
return task { return task {
try { try {

View File

@ -23,8 +23,11 @@ import android.accounts.AccountManager
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.* import com.bumptech.glide.load.model.*
import com.bumptech.glide.load.model.ModelLoader.LoadData
import com.bumptech.glide.signature.ObjectKey
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.mariotaku.twidere.extension.model.authorizationHeader import org.mariotaku.twidere.extension.model.authorizationHeader
import org.mariotaku.twidere.extension.model.getCredentials import org.mariotaku.twidere.extension.model.getCredentials
@ -40,16 +43,6 @@ class AuthenticatedUriLoader(
val client: OkHttpClient val client: OkHttpClient
) : ModelLoader<AuthenticatedUri, InputStream> { ) : ModelLoader<AuthenticatedUri, InputStream> {
override fun getResourceFetcher(model: AuthenticatedUri, width: Int, height: Int): DataFetcher<InputStream> {
val headersBuilder = LazyHeaders.Builder()
val credentials = model.accountKey?.credentials
if (credentials != null && TwidereMediaDownloader.isAuthRequired(credentials, model.uri)) {
headersBuilder.addHeader("Authorization", AuthorizationHeaderFactory(model.uri, credentials))
}
val glideUrl = GlideUrl(model.uri.toString(), headersBuilder.build())
return OkHttpStreamFetcher(client, glideUrl)
}
val UserKey.credentials: Credentials? get() { val UserKey.credentials: Credentials? get() {
val am = AccountManager.get(context) val am = AccountManager.get(context)
return AccountUtils.findByAccountKey(am, this)?.getCredentials(am) return AccountUtils.findByAccountKey(am, this)?.getCredentials(am)
@ -59,10 +52,24 @@ class AuthenticatedUriLoader(
override fun buildHeader() = credentials.authorizationHeader(uri) override fun buildHeader() = credentials.authorizationHeader(uri)
} }
class Factory(val client: OkHttpClient) : ModelLoaderFactory<AuthenticatedUri, InputStream> { class Factory(val context: Context, val client: OkHttpClient) : ModelLoaderFactory<AuthenticatedUri, InputStream> {
override fun build(context: Context, factories: GenericLoaderFactory) = AuthenticatedUriLoader(context, client) override fun build(factory: MultiModelLoaderFactory) = AuthenticatedUriLoader(context, client)
override fun teardown() {} override fun teardown() {}
} }
override fun buildLoadData(model: AuthenticatedUri, width: Int, height: Int, options: Options): LoadData<InputStream>? {
val headersBuilder = LazyHeaders.Builder()
val credentials = model.accountKey?.credentials
if (credentials != null && TwidereMediaDownloader.isAuthRequired(credentials, model.uri)) {
headersBuilder.addHeader("Authorization", AuthorizationHeaderFactory(model.uri, credentials))
}
val glideUrl = GlideUrl(model.uri.toString(), headersBuilder.build())
return LoadData(ObjectKey(model), OkHttpStreamFetcher(client, glideUrl))
}
override fun handles(model: AuthenticatedUri): Boolean {
return true
}
} }

View File

@ -20,8 +20,8 @@
package org.mariotaku.twidere.util.glide package org.mariotaku.twidere.util.glide
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.SimpleTarget import com.bumptech.glide.request.transition.Transition
import nl.komponents.kovenant.Deferred import nl.komponents.kovenant.Deferred
import nl.komponents.kovenant.Promise import nl.komponents.kovenant.Promise
import nl.komponents.kovenant.deferred import nl.komponents.kovenant.deferred
@ -30,18 +30,23 @@ import nl.komponents.kovenant.deferred
* Created by mariotaku on 2017/3/21. * Created by mariotaku on 2017/3/21.
*/ */
class DeferredTarget<R>(private val deferredInstance: Deferred<R, Exception> = deferred()) : SimpleTarget<R>() { class DeferredTarget<R>(private val deferredInstance: Deferred<R, Exception> = deferred()) : CustomTarget<R>() {
val promise: Promise<R, Exception> get() = deferredInstance.promise val promise: Promise<R, Exception> get() = deferredInstance.promise
override fun onLoadFailed(e: Exception, errorDrawable: Drawable?) { override fun onLoadFailed(errorDrawable: Drawable?) {
if (deferredInstance.promise.isDone()) return if (deferredInstance.promise.isDone()) return
deferredInstance.reject(e) deferredInstance.reject(Exception())
} }
override fun onResourceReady(resource: R, glideAnimation: GlideAnimation<in R>) { override fun onResourceReady(resource: R, transition: Transition<in R>?) {
if (deferredInstance.promise.isDone()) return if (deferredInstance.promise.isDone()) return
deferredInstance.resolve(resource) deferredInstance.resolve(resource)
} }
override fun onLoadCleared(placeholder: Drawable?) {
if (deferredInstance.promise.isDone()) return
deferredInstance.reject(Exception())
}
} }

View File

@ -21,8 +21,10 @@ package org.mariotaku.twidere.util.glide
import android.content.Context import android.content.Context
import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher
import com.bumptech.glide.load.Options
import com.bumptech.glide.load.data.DataFetcher import com.bumptech.glide.load.data.DataFetcher
import com.bumptech.glide.load.model.* import com.bumptech.glide.load.model.*
import com.bumptech.glide.signature.ObjectKey
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.mariotaku.twidere.model.media.NoThumborUrl import org.mariotaku.twidere.model.media.NoThumborUrl
import java.io.InputStream import java.io.InputStream
@ -32,15 +34,9 @@ class NoThumborUrlLoader(
val client: OkHttpClient val client: OkHttpClient
) : ModelLoader<NoThumborUrl, InputStream> { ) : ModelLoader<NoThumborUrl, InputStream> {
override fun getResourceFetcher(model: NoThumborUrl, width: Int, height: Int): DataFetcher<InputStream> {
val headersBuilder = LazyHeaders.Builder()
headersBuilder.addHeader(HEADER_NO_THUMBOR, "true")
val glideUrl = GlideUrl(model.url, headersBuilder.build())
return OkHttpStreamFetcher(client, glideUrl)
}
class Factory(val client: OkHttpClient) : ModelLoaderFactory<NoThumborUrl, InputStream> { class Factory(val context: Context, val client: OkHttpClient) : ModelLoaderFactory<NoThumborUrl, InputStream> {
override fun build(context: Context, factories: GenericLoaderFactory) = NoThumborUrlLoader(context, client) override fun build(factory: MultiModelLoaderFactory) = NoThumborUrlLoader(context, client)
override fun teardown() {} override fun teardown() {}
} }
@ -49,4 +45,16 @@ class NoThumborUrlLoader(
const val HEADER_NO_THUMBOR = "X-Twidere-No-Thumbor" const val HEADER_NO_THUMBOR = "X-Twidere-No-Thumbor"
} }
override fun buildLoadData(model: NoThumborUrl, width: Int, height: Int, options: Options): ModelLoader.LoadData<InputStream>? {
val headersBuilder = LazyHeaders.Builder()
headersBuilder.addHeader(HEADER_NO_THUMBOR, "true")
val glideUrl = GlideUrl(model.url, headersBuilder.build())
val fetcher = OkHttpStreamFetcher(client, glideUrl)
return ModelLoader.LoadData(ObjectKey(model), fetcher)
}
override fun handles(model: NoThumborUrl): Boolean {
return true
}
} }

View File

@ -26,6 +26,8 @@ import com.bumptech.glide.load.Transformation
import com.bumptech.glide.load.engine.Resource import com.bumptech.glide.load.engine.Resource
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool
import com.bumptech.glide.load.resource.bitmap.BitmapResource import com.bumptech.glide.load.resource.bitmap.BitmapResource
import java.security.MessageDigest
class RoundedRectTransformation( class RoundedRectTransformation(
private val bitmapPool: BitmapPool, private val bitmapPool: BitmapPool,
@ -37,7 +39,7 @@ class RoundedRectTransformation(
constructor(context: Context, radius: Float, radiusPercent: Float) : constructor(context: Context, radius: Float, radiusPercent: Float) :
this(Glide.get(context).bitmapPool, radius, radiusPercent) this(Glide.get(context).bitmapPool, radius, radiusPercent)
override fun transform(resource: Resource<Bitmap>, outWidth: Int, outHeight: Int): Resource<Bitmap> { override fun transform(context: Context, resource: Resource<Bitmap>, outWidth: Int, outHeight: Int): Resource<Bitmap> {
val source = resource.get() val source = resource.get()
val width = source.width val width = source.width
@ -59,14 +61,26 @@ class RoundedRectTransformation(
radius radius
} }
drawRoundRect(canvas, calculatedRadius, paint) drawRoundRect(canvas, calculatedRadius, paint)
return BitmapResource.obtain(bitmap, bitmapPool) return BitmapResource.obtain(bitmap, bitmapPool)!!
} }
private fun drawRoundRect(canvas: Canvas, radius: Float, paint: Paint) { private fun drawRoundRect(canvas: Canvas, radius: Float, paint: Paint) {
canvas.drawRoundRect(rectF, radius, radius, paint) canvas.drawRoundRect(rectF, radius, radius, paint)
} }
override fun getId(): String { fun getId(): String {
return "RoundedRectTransformation(radius=$radius, radiusPercent=$radius)" return "RoundedRectTransformation(radius=$radius, radiusPercent=$radius)"
} }
override fun equals(o: Any?): Boolean {
return o is RoundedRectTransformation
}
override fun hashCode(): Int {
return getId().hashCode()
}
override fun updateDiskCacheKey(messageDigest: MessageDigest) {
messageDigest.update(getId().toByteArray())
}
} }

View File

@ -23,8 +23,10 @@ import android.content.Context
import android.os.Build import android.os.Build
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.bumptech.glide.GlideBuilder import com.bumptech.glide.GlideBuilder
import com.bumptech.glide.Registry
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.module.GlideModule import com.bumptech.glide.module.GlideModule
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -38,12 +40,13 @@ import org.mariotaku.twidere.util.media.ThumborWrapper
import org.mariotaku.twidere.util.okhttp.ModifyRequestInterceptor import org.mariotaku.twidere.util.okhttp.ModifyRequestInterceptor
import java.io.InputStream import java.io.InputStream
class TwidereGlideModule : GlideModule { @com.bumptech.glide.annotation.GlideModule
class TwidereGlideModule : AppGlideModule() {
override fun applyOptions(context: Context, builder: GlideBuilder) { override fun applyOptions(context: Context, builder: GlideBuilder) {
// Do nothing. // Do nothing.
} }
override fun registerComponents(context: Context, glide: Glide) { override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
val holder = DependencyHolder.get(context) val holder = DependencyHolder.get(context)
val builder = OkHttpClient.Builder() val builder = OkHttpClient.Builder()
val conf = HttpClientFactory.HttpClientConfiguration(holder.preferences) val conf = HttpClientFactory.HttpClientConfiguration(holder.preferences)
@ -56,9 +59,13 @@ class TwidereGlideModule : GlideModule {
} }
builder.addInterceptor(ModifyRequestInterceptor(ThumborModifier(thumbor), UserAgentModifier(userAgent))) builder.addInterceptor(ModifyRequestInterceptor(ThumborModifier(thumbor), UserAgentModifier(userAgent)))
val client = builder.build() val client = builder.build()
glide.register(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(client)) registry.append(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory(client))
glide.register(AuthenticatedUri::class.java, InputStream::class.java, AuthenticatedUriLoader.Factory(client)) registry.append(AuthenticatedUri::class.java, InputStream::class.java, AuthenticatedUriLoader.Factory(context, client))
glide.register(NoThumborUrl::class.java, InputStream::class.java, NoThumborUrlLoader.Factory(client)) registry.append(NoThumborUrl::class.java, InputStream::class.java, NoThumborUrlLoader.Factory(context, client))
}
override fun isManifestParsingEnabled(): Boolean {
return false;
} }
class ThumborModifier(val thumbor: ThumborWrapper) : ModifyRequestInterceptor.RequestModifier { class ThumborModifier(val thumbor: ThumborWrapper) : ModifyRequestInterceptor.RequestModifier {

View File

@ -117,9 +117,9 @@ class CardMediaContainer(context: Context, attrs: AttributeSet? = null) : ViewGr
item.media_url item.media_url
} }
val request = if (withCredentials) { val request = if (withCredentials) {
requestManager.load(AuthenticatedUri(Uri.parse(url), accountKey)).asBitmap() requestManager.load(AuthenticatedUri(Uri.parse(url), accountKey))
} else { } else {
requestManager.load(url).asBitmap() requestManager.load(url)
} }
when (style) { when (style) {
PreviewStyle.ACTUAL_SIZE -> { PreviewStyle.ACTUAL_SIZE -> {
@ -148,7 +148,7 @@ class CardMediaContainer(context: Context, attrs: AttributeSet? = null) : ViewGr
this.visibility = View.VISIBLE this.visibility = View.VISIBLE
findViewById<View>(lp.videoViewId)?.visibility = View.VISIBLE findViewById<View>(lp.videoViewId)?.visibility = View.VISIBLE
} else { } else {
Glide.clear(this) Glide.with(this).clear(this)
this.visibility = View.GONE this.visibility = View.GONE
findViewById<View>(lp.videoViewId)?.visibility = View.GONE findViewById<View>(lp.videoViewId)?.visibility = View.GONE
} }

View File

@ -19,9 +19,11 @@
package org.mariotaku.twidere.view.holder.compose package org.mariotaku.twidere.view.holder.compose
import android.graphics.drawable.Drawable
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.View import android.view.View
import com.bumptech.glide.load.resource.drawable.GlideDrawable import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target import com.bumptech.glide.request.target.Target
import kotlinx.android.synthetic.main.grid_item_media_editor.view.* import kotlinx.android.synthetic.main.grid_item_media_editor.view.*
@ -39,15 +41,15 @@ class MediaPreviewViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
private val removeView = itemView.remove private val removeView = itemView.remove
private val editView = itemView.edit private val editView = itemView.edit
private val requestListener = object : RequestListener<String, GlideDrawable> { private val requestListener = object : RequestListener<Drawable> {
override fun onException(e: Exception?, model: String?, target: Target<GlideDrawable>?,
isFirstResource: Boolean): Boolean { override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?,
dataSource: DataSource?, isFirstResource: Boolean): Boolean {
loadProgress.visibility = View.GONE loadProgress.visibility = View.GONE
return false return false
} }
override fun onResourceReady(resource: GlideDrawable?, model: String?, override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?,
target: Target<GlideDrawable>?, isFromMemoryCache: Boolean,
isFirstResource: Boolean): Boolean { isFirstResource: Boolean): Boolean {
loadProgress.visibility = View.GONE loadProgress.visibility = View.GONE
return false return false