@amazon-devices/expo-image 2.0.1758683737
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +2 -0
- package/CHANGELOG.md +285 -0
- package/CMakeLists.txt +91 -0
- package/LICENSE +7 -0
- package/README.kepler.md +123 -0
- package/README.md +54 -0
- package/THIRD_PARTY_NOTICES.txt +24 -0
- package/android/build.gradle +124 -0
- package/android/proguard-rules.pro +28 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/java/expo/modules/image/Exceptions.kt +9 -0
- package/android/src/main/java/expo/modules/image/ExpoImageAppGlideModule.kt +19 -0
- package/android/src/main/java/expo/modules/image/ExpoImageModule.kt +192 -0
- package/android/src/main/java/expo/modules/image/ExpoImageView.kt +220 -0
- package/android/src/main/java/expo/modules/image/ExpoImageViewWrapper.kt +652 -0
- package/android/src/main/java/expo/modules/image/GlideModel.kt +73 -0
- package/android/src/main/java/expo/modules/image/ImageUtils.kt +50 -0
- package/android/src/main/java/expo/modules/image/ImageViewWrapperTarget.kt +313 -0
- package/android/src/main/java/expo/modules/image/ResourceIdHelper.kt +47 -0
- package/android/src/main/java/expo/modules/image/ThumbnailRequestCoordinatorExtension.kt +21 -0
- package/android/src/main/java/expo/modules/image/YogaUtils.kt +20 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurHashFetcher.kt +32 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashDecoder.kt +189 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoader.kt +30 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModelLoaderFactory.kt +14 -0
- package/android/src/main/java/expo/modules/image/blurhash/BlurhashModule.kt +17 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64DataFetcher.kt +27 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoader.kt +24 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64ModelLoaderFactory.kt +12 -0
- package/android/src/main/java/expo/modules/image/dataurls/Base64Module.kt +16 -0
- package/android/src/main/java/expo/modules/image/drawing/OutlineProvider.kt +201 -0
- package/android/src/main/java/expo/modules/image/enums/ContentFit.kt +89 -0
- package/android/src/main/java/expo/modules/image/enums/ImageCacheType.kt +14 -0
- package/android/src/main/java/expo/modules/image/enums/Priority.kt +15 -0
- package/android/src/main/java/expo/modules/image/events/GlideRequestListener.kt +64 -0
- package/android/src/main/java/expo/modules/image/events/OkHttpProgressListener.kt +26 -0
- package/android/src/main/java/expo/modules/image/okhttp/ExpoImageOkHttpClientGlideModule.kt +80 -0
- package/android/src/main/java/expo/modules/image/okhttp/GlideUrlWrapperLoader.kt +55 -0
- package/android/src/main/java/expo/modules/image/records/CachePolicy.kt +10 -0
- package/android/src/main/java/expo/modules/image/records/ContentPosition.kt +89 -0
- package/android/src/main/java/expo/modules/image/records/ImageTransition.kt +8 -0
- package/android/src/main/java/expo/modules/image/records/SourceMap.kt +160 -0
- package/android/src/main/java/expo/modules/image/records/events.kt +25 -0
- package/android/src/main/java/expo/modules/image/svg/SVGDecoder.kt +33 -0
- package/android/src/main/java/expo/modules/image/svg/SVGDrawableTranscoder.kt +37 -0
- package/android/src/main/java/expo/modules/image/svg/SVGModule.kt +26 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashDecoder.kt +365 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashFetcher.kt +31 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoader.kt +26 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModelLoaderFactory.kt +14 -0
- package/android/src/main/java/expo/modules/image/thumbhash/ThumbhashModule.kt +17 -0
- package/build/ExpoImage.d.ts +15 -0
- package/build/ExpoImage.d.ts.map +1 -0
- package/build/ExpoImage.js +75 -0
- package/build/ExpoImage.js.map +1 -0
- package/build/ExpoImage.kepler.d.ts +23 -0
- package/build/ExpoImage.kepler.d.ts.map +1 -0
- package/build/ExpoImage.kepler.js +71 -0
- package/build/ExpoImage.kepler.js.map +1 -0
- package/build/ExpoImage.web.d.ts +9 -0
- package/build/ExpoImage.web.d.ts.map +1 -0
- package/build/ExpoImage.web.js +90 -0
- package/build/ExpoImage.web.js.map +1 -0
- package/build/ExpoImageModules.d.ts +3 -0
- package/build/ExpoImageModules.d.ts.map +1 -0
- package/build/ExpoImageModules.js +4 -0
- package/build/ExpoImageModules.js.map +1 -0
- package/build/ExpoImageModules.kepler.d.ts +6 -0
- package/build/ExpoImageModules.kepler.d.ts.map +1 -0
- package/build/ExpoImageModules.kepler.js +5 -0
- package/build/ExpoImageModules.kepler.js.map +1 -0
- package/build/Image.d.ts +30 -0
- package/build/Image.d.ts.map +1 -0
- package/build/Image.js +49 -0
- package/build/Image.js.map +1 -0
- package/build/Image.types.d.ts +374 -0
- package/build/Image.types.d.ts.map +1 -0
- package/build/Image.types.js +2 -0
- package/build/Image.types.js.map +1 -0
- package/build/ImageBackground.d.ts +6 -0
- package/build/ImageBackground.d.ts.map +1 -0
- package/build/ImageBackground.js +13 -0
- package/build/ImageBackground.js.map +1 -0
- package/build/ImageViewNativeComponent.d.ts +20 -0
- package/build/ImageViewNativeComponent.d.ts.map +1 -0
- package/build/ImageViewNativeComponent.js +42 -0
- package/build/ImageViewNativeComponent.js.map +1 -0
- package/build/NativeImageLoaderKepler.d.ts +18 -0
- package/build/NativeImageLoaderKepler.d.ts.map +1 -0
- package/build/NativeImageLoaderKepler.js +3 -0
- package/build/NativeImageLoaderKepler.js.map +1 -0
- package/build/fabric/registerNativeComponent.d.ts +15 -0
- package/build/fabric/registerNativeComponent.d.ts.map +1 -0
- package/build/fabric/registerNativeComponent.js +47 -0
- package/build/fabric/registerNativeComponent.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +4 -0
- package/build/index.js.map +1 -0
- package/build/utils/AssetSourceResolver.web.d.ts +24 -0
- package/build/utils/AssetSourceResolver.web.d.ts.map +1 -0
- package/build/utils/AssetSourceResolver.web.js +67 -0
- package/build/utils/AssetSourceResolver.web.js.map +1 -0
- package/build/utils/blurhash/base83.d.ts +3 -0
- package/build/utils/blurhash/base83.d.ts.map +1 -0
- package/build/utils/blurhash/base83.js +103 -0
- package/build/utils/blurhash/base83.js.map +1 -0
- package/build/utils/blurhash/decode.d.ts +7 -0
- package/build/utils/blurhash/decode.d.ts.map +1 -0
- package/build/utils/blurhash/decode.js +92 -0
- package/build/utils/blurhash/decode.js.map +1 -0
- package/build/utils/blurhash/error.d.ts +4 -0
- package/build/utils/blurhash/error.d.ts.map +1 -0
- package/build/utils/blurhash/error.js +8 -0
- package/build/utils/blurhash/error.js.map +1 -0
- package/build/utils/blurhash/useBlurhash.d.ts +8 -0
- package/build/utils/blurhash/useBlurhash.d.ts.map +1 -0
- package/build/utils/blurhash/useBlurhash.js +64 -0
- package/build/utils/blurhash/useBlurhash.js.map +1 -0
- package/build/utils/blurhash/utils.d.ts +5 -0
- package/build/utils/blurhash/utils.d.ts.map +1 -0
- package/build/utils/blurhash/utils.js +21 -0
- package/build/utils/blurhash/utils.js.map +1 -0
- package/build/utils/resolveAssetSource.d.ts +3 -0
- package/build/utils/resolveAssetSource.d.ts.map +1 -0
- package/build/utils/resolveAssetSource.js +3 -0
- package/build/utils/resolveAssetSource.js.map +1 -0
- package/build/utils/resolveAssetSource.web.d.ts +9 -0
- package/build/utils/resolveAssetSource.web.d.ts.map +1 -0
- package/build/utils/resolveAssetSource.web.js +31 -0
- package/build/utils/resolveAssetSource.web.js.map +1 -0
- package/build/utils/resolveHashString.d.ts +14 -0
- package/build/utils/resolveHashString.d.ts.map +1 -0
- package/build/utils/resolveHashString.js +31 -0
- package/build/utils/resolveHashString.js.map +1 -0
- package/build/utils/resolveHashString.web.d.ts +20 -0
- package/build/utils/resolveHashString.web.d.ts.map +1 -0
- package/build/utils/resolveHashString.web.js +31 -0
- package/build/utils/resolveHashString.web.js.map +1 -0
- package/build/utils/resolveSources.d.ts +8 -0
- package/build/utils/resolveSources.d.ts.map +1 -0
- package/build/utils/resolveSources.js +45 -0
- package/build/utils/resolveSources.js.map +1 -0
- package/build/utils/thumbhash/thumbhash.d.ts +66 -0
- package/build/utils/thumbhash/thumbhash.d.ts.map +1 -0
- package/build/utils/thumbhash/thumbhash.js +338 -0
- package/build/utils/thumbhash/thumbhash.js.map +1 -0
- package/build/utils.d.ts +17 -0
- package/build/utils.d.ts.map +1 -0
- package/build/utils.js +85 -0
- package/build/utils.js.map +1 -0
- package/build/web/AnimationManager.d.ts +37 -0
- package/build/web/AnimationManager.d.ts.map +1 -0
- package/build/web/AnimationManager.js +155 -0
- package/build/web/AnimationManager.js.map +1 -0
- package/build/web/ColorTintFilter.d.ts +12 -0
- package/build/web/ColorTintFilter.d.ts.map +1 -0
- package/build/web/ColorTintFilter.js +30 -0
- package/build/web/ColorTintFilter.js.map +1 -0
- package/build/web/ImageWrapper.d.ts +5 -0
- package/build/web/ImageWrapper.d.ts.map +1 -0
- package/build/web/ImageWrapper.js +44 -0
- package/build/web/ImageWrapper.js.map +1 -0
- package/build/web/ImageWrapper.types.d.ts +29 -0
- package/build/web/ImageWrapper.types.d.ts.map +1 -0
- package/build/web/ImageWrapper.types.js +2 -0
- package/build/web/ImageWrapper.types.js.map +1 -0
- package/build/web/getImageWrapperEventHandler.d.ts +8 -0
- package/build/web/getImageWrapperEventHandler.d.ts.map +1 -0
- package/build/web/getImageWrapperEventHandler.js +25 -0
- package/build/web/getImageWrapperEventHandler.js.map +1 -0
- package/build/web/hooks.d.ts +13 -0
- package/build/web/hooks.d.ts.map +1 -0
- package/build/web/hooks.js +58 -0
- package/build/web/hooks.js.map +1 -0
- package/build/web/imageStyles.d.ts +2 -0
- package/build/web/imageStyles.d.ts.map +1 -0
- package/build/web/imageStyles.js +137 -0
- package/build/web/imageStyles.js.map +1 -0
- package/build/web/positioning.d.ts +11 -0
- package/build/web/positioning.d.ts.map +1 -0
- package/build/web/positioning.js +35 -0
- package/build/web/positioning.js.map +1 -0
- package/build/web/useSourceSelection.d.ts +14 -0
- package/build/web/useSourceSelection.d.ts.map +1 -0
- package/build/web/useSourceSelection.js +98 -0
- package/build/web/useSourceSelection.js.map +1 -0
- package/expo-module.config.json +9 -0
- package/ios/Blurhash.swift +326 -0
- package/ios/BlurhashLoader.swift +52 -0
- package/ios/ContentFit.swift +55 -0
- package/ios/ContentPosition.swift +108 -0
- package/ios/ExpoImage.podspec +30 -0
- package/ios/ImageCachePolicy.swift +24 -0
- package/ios/ImageCacheType.swift +21 -0
- package/ios/ImageModule.swift +127 -0
- package/ios/ImagePriority.swift +22 -0
- package/ios/ImageSource.swift +44 -0
- package/ios/ImageTransition.swift +67 -0
- package/ios/ImageUtils.swift +227 -0
- package/ios/ImageView.swift +469 -0
- package/ios/Loaders/PhotoLibraryAssetLoader.swift +146 -0
- package/ios/Thumbhash.swift +550 -0
- package/ios/ThumbhashLoader.swift +53 -0
- package/jest.config.js +3 -0
- package/kepler/ExpoImage.cpp +63 -0
- package/kepler/ExpoImage.h +29 -0
- package/kepler/ExpoImageCacheHandler.cpp +15 -0
- package/kepler/ExpoImageCacheHandler.h +28 -0
- package/kepler/ExpoImageComponent.cpp +579 -0
- package/kepler/ExpoImageComponent.h +199 -0
- package/kepler/ImageWrapper/BlurhashImageWrapper.cpp +37 -0
- package/kepler/ImageWrapper/BlurhashImageWrapper.h +23 -0
- package/kepler/ImageWrapper/CacheImageWrapper.cpp +80 -0
- package/kepler/ImageWrapper/CacheImageWrapper.h +41 -0
- package/kepler/ImageWrapper/HashImageWrapper.cpp +21 -0
- package/kepler/ImageWrapper/HashImageWrapper.h +22 -0
- package/kepler/ImageWrapper/ImageWrapper.cpp +24 -0
- package/kepler/ImageWrapper/ImageWrapper.h +33 -0
- package/kepler/ImageWrapper/LocalImageWrapper.cpp +61 -0
- package/kepler/ImageWrapper/LocalImageWrapper.h +30 -0
- package/kepler/ImageWrapper/ThumbhashImageWrapper.cpp +33 -0
- package/kepler/ImageWrapper/ThumbhashImageWrapper.h +20 -0
- package/kepler/KeplerImageViewComponent.h +64 -0
- package/kepler/KeplerInit.cpp +35 -0
- package/kepler/blurhash/common.h +32 -0
- package/kepler/blurhash/decode.cpp +187 -0
- package/kepler/blurhash/decode.h +58 -0
- package/kepler/contentposition/ImageContentPosition.cpp +86 -0
- package/kepler/contentposition/ImageContentPosition.h +48 -0
- package/kepler/enums/ImageContentFit.h +17 -0
- package/kepler/enums/ImagePriority.h +17 -0
- package/kepler/managers/ExpoImageManager.cpp +38 -0
- package/kepler/managers/ExpoImageManager.h +23 -0
- package/kepler/test/ExpoImage.cpp +73 -0
- package/kepler/test/ExpoImageComponent.cpp +290 -0
- package/kepler/test/blurhash/decode.cpp +39 -0
- package/kepler/test/contentposition/ImageContentPosition.cpp +100 -0
- package/kepler/test/managers/ExpoImageManager.cpp +39 -0
- package/kepler/test/thumbhash/decode.cpp +18 -0
- package/kepler/test/utils/LoaderDelegate.cpp +130 -0
- package/kepler/thumbhash/decode.cpp +166 -0
- package/kepler/thumbhash/decode.h +22 -0
- package/kepler/utils/PlaceholderImageLoaderDelegate.cpp +26 -0
- package/kepler/utils/PlaceholderImageLoaderDelegate.h +26 -0
- package/kepler/utils/PrefetchImageLoaderDelegate.cpp +55 -0
- package/kepler/utils/PrefetchImageLoaderDelegate.h +35 -0
- package/kepler/utils/SourceImageLoaderDelegate.cpp +47 -0
- package/kepler/utils/SourceImageLoaderDelegate.h +42 -0
- package/kepler/utils/SourceImageLoaderDelegateEmitter.cpp +15 -0
- package/kepler/utils/SourceImageLoaderDelegateEmitter.h +28 -0
- package/kepler-compatibility.json +8 -0
- package/package.json +1 -0
- package/react-native.config.js +22 -0
- package/src/ExpoImage.kepler.tsx +119 -0
- package/src/ExpoImage.tsx +119 -0
- package/src/ExpoImage.web.tsx +155 -0
- package/src/ExpoImageModules.kepler.ts +7 -0
- package/src/ExpoImageModules.ts +4 -0
- package/src/Image.tsx +82 -0
- package/src/Image.types.ts +450 -0
- package/src/ImageBackground.tsx +18 -0
- package/src/ImageViewNativeComponent.ts +59 -0
- package/src/NativeImageLoaderKepler.ts +22 -0
- package/src/fabric/registerNativeComponent.ts +70 -0
- package/src/index.ts +3 -0
- package/src/utils/AssetSourceResolver.web.ts +88 -0
- package/src/utils/blurhash/base83.ts +104 -0
- package/src/utils/blurhash/decode.ts +114 -0
- package/src/utils/blurhash/error.ts +7 -0
- package/src/utils/blurhash/useBlurhash.tsx +81 -0
- package/src/utils/blurhash/utils.ts +21 -0
- package/src/utils/resolveAssetSource.tsx +3 -0
- package/src/utils/resolveAssetSource.web.ts +40 -0
- package/src/utils/resolveHashString.tsx +36 -0
- package/src/utils/resolveHashString.web.tsx +33 -0
- package/src/utils/resolveSources.tsx +48 -0
- package/src/utils/thumbhash/thumbhash.ts +387 -0
- package/src/utils.ts +109 -0
- package/src/web/AnimationManager.tsx +224 -0
- package/src/web/ColorTintFilter.tsx +36 -0
- package/src/web/ImageWrapper.tsx +85 -0
- package/src/web/ImageWrapper.types.ts +36 -0
- package/src/web/getImageWrapperEventHandler.ts +29 -0
- package/src/web/hooks.ts +72 -0
- package/src/web/imageStyles.tsx +136 -0
- package/src/web/positioning.ts +48 -0
- package/src/web/useSourceSelection.ts +151 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,652 @@
|
|
|
1
|
+
package expo.modules.image
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.app.Activity
|
|
5
|
+
import android.content.Context
|
|
6
|
+
import android.graphics.drawable.Animatable
|
|
7
|
+
import android.graphics.drawable.Drawable
|
|
8
|
+
import android.os.Build
|
|
9
|
+
import android.os.Handler
|
|
10
|
+
import android.view.View
|
|
11
|
+
import android.widget.FrameLayout
|
|
12
|
+
import androidx.core.view.AccessibilityDelegateCompat
|
|
13
|
+
import androidx.core.view.ViewCompat
|
|
14
|
+
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
|
|
15
|
+
import androidx.core.view.isVisible
|
|
16
|
+
import com.bumptech.glide.Glide
|
|
17
|
+
import com.bumptech.glide.RequestManager
|
|
18
|
+
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
|
19
|
+
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy
|
|
20
|
+
import com.bumptech.glide.request.RequestOptions
|
|
21
|
+
import com.bumptech.glide.request.target.Target.SIZE_ORIGINAL
|
|
22
|
+
import com.facebook.yoga.YogaConstants
|
|
23
|
+
import expo.modules.image.enums.ContentFit
|
|
24
|
+
import expo.modules.image.enums.Priority
|
|
25
|
+
import expo.modules.image.events.GlideRequestListener
|
|
26
|
+
import expo.modules.image.events.OkHttpProgressListener
|
|
27
|
+
import expo.modules.image.okhttp.GlideUrlWrapper
|
|
28
|
+
import expo.modules.image.records.CachePolicy
|
|
29
|
+
import expo.modules.image.records.ContentPosition
|
|
30
|
+
import expo.modules.image.records.ImageErrorEvent
|
|
31
|
+
import expo.modules.image.records.ImageLoadEvent
|
|
32
|
+
import expo.modules.image.records.ImageProgressEvent
|
|
33
|
+
import expo.modules.image.records.ImageTransition
|
|
34
|
+
import expo.modules.image.records.SourceMap
|
|
35
|
+
import expo.modules.kotlin.AppContext
|
|
36
|
+
import expo.modules.kotlin.viewevent.EventDispatcher
|
|
37
|
+
import expo.modules.kotlin.views.ExpoView
|
|
38
|
+
import jp.wasabeef.glide.transformations.BlurTransformation
|
|
39
|
+
import java.lang.Float.max
|
|
40
|
+
import java.lang.ref.WeakReference
|
|
41
|
+
import kotlin.math.abs
|
|
42
|
+
import kotlin.math.min
|
|
43
|
+
|
|
44
|
+
@SuppressLint("ViewConstructor")
|
|
45
|
+
class ExpoImageViewWrapper(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
|
46
|
+
private val activity: Activity
|
|
47
|
+
get() = appContext.currentActivity ?: throw MissingActivity()
|
|
48
|
+
|
|
49
|
+
internal val requestManager = getOrCreateRequestManager(appContext, activity)
|
|
50
|
+
private val progressListener = OkHttpProgressListener(WeakReference(this))
|
|
51
|
+
|
|
52
|
+
private val firstView = ExpoImageView(activity)
|
|
53
|
+
private val secondView = ExpoImageView(activity)
|
|
54
|
+
|
|
55
|
+
private val mainHandler = Handler(context.mainLooper)
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @returns the view which is currently active or will be used when both views are empty
|
|
59
|
+
*/
|
|
60
|
+
private val activeView: ExpoImageView
|
|
61
|
+
get() {
|
|
62
|
+
if (secondView.drawable != null) {
|
|
63
|
+
return secondView
|
|
64
|
+
}
|
|
65
|
+
return firstView
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private var firstTarget = ImageViewWrapperTarget(WeakReference(this))
|
|
69
|
+
private var secondTarget = ImageViewWrapperTarget(WeakReference(this))
|
|
70
|
+
|
|
71
|
+
internal val onLoadStart by EventDispatcher<Unit>()
|
|
72
|
+
internal val onProgress by EventDispatcher<ImageProgressEvent>()
|
|
73
|
+
internal val onError by EventDispatcher<ImageErrorEvent>()
|
|
74
|
+
internal val onLoad by EventDispatcher<ImageLoadEvent>()
|
|
75
|
+
|
|
76
|
+
internal var sources: List<SourceMap> = emptyList()
|
|
77
|
+
private val bestSource: SourceMap?
|
|
78
|
+
get() = getBestSource(sources)
|
|
79
|
+
|
|
80
|
+
internal var placeholders: List<SourceMap> = emptyList()
|
|
81
|
+
private val bestPlaceholder: SourceMap?
|
|
82
|
+
get() = getBestSource(placeholders)
|
|
83
|
+
|
|
84
|
+
internal var blurRadius: Int? = null
|
|
85
|
+
set(value) {
|
|
86
|
+
if (field != value) {
|
|
87
|
+
shouldRerender = true
|
|
88
|
+
}
|
|
89
|
+
field = value
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
internal var transition: ImageTransition? = null
|
|
93
|
+
|
|
94
|
+
internal var contentFit: ContentFit = ContentFit.Cover
|
|
95
|
+
set(value) {
|
|
96
|
+
field = value
|
|
97
|
+
activeView.contentFit = value
|
|
98
|
+
transformationMatrixChanged = true
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
internal var placeholderContentFit: ContentFit = ContentFit.ScaleDown
|
|
102
|
+
set(value) {
|
|
103
|
+
field = value
|
|
104
|
+
activeView.placeholderContentFit = value
|
|
105
|
+
transformationMatrixChanged = true
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
internal var contentPosition: ContentPosition = ContentPosition.center
|
|
109
|
+
set(value) {
|
|
110
|
+
field = value
|
|
111
|
+
activeView.contentPosition = value
|
|
112
|
+
transformationMatrixChanged = true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
internal var borderStyle: String? = null
|
|
116
|
+
set(value) {
|
|
117
|
+
field = value
|
|
118
|
+
activeView.setBorderStyle(value)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
internal var backgroundColor: Int? = null
|
|
122
|
+
set(value) {
|
|
123
|
+
field = value
|
|
124
|
+
activeView.setBackgroundColor(value)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
internal var tintColor: Int? = null
|
|
128
|
+
set(value) {
|
|
129
|
+
field = value
|
|
130
|
+
activeView.setTintColor(value)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
internal var isFocusableProp: Boolean = false
|
|
134
|
+
set(value) {
|
|
135
|
+
field = value
|
|
136
|
+
activeView.isFocusable = value
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
internal var accessible: Boolean = false
|
|
140
|
+
set(value) {
|
|
141
|
+
field = value
|
|
142
|
+
setIsScreenReaderFocusable(activeView, value)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
internal var accessibilityLabel: String? = null
|
|
146
|
+
set(value) {
|
|
147
|
+
field = value
|
|
148
|
+
activeView.contentDescription = accessibilityLabel
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
var recyclingKey: String? = null
|
|
152
|
+
set(value) {
|
|
153
|
+
clearViewBeforeChangingSource = field != null && value != null && value != field
|
|
154
|
+
field = value
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
internal var allowDownscaling: Boolean = true
|
|
158
|
+
set(value) {
|
|
159
|
+
field = value
|
|
160
|
+
shouldRerender = true
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
internal var priority: Priority = Priority.NORMAL
|
|
164
|
+
internal var cachePolicy: CachePolicy = CachePolicy.DISK
|
|
165
|
+
|
|
166
|
+
private var borderRadius = FloatArray(9) { YogaConstants.UNDEFINED }
|
|
167
|
+
private var borderWidth = FloatArray(9) { YogaConstants.UNDEFINED }
|
|
168
|
+
private var borderColor = Array(9) { YogaConstants.UNDEFINED to YogaConstants.UNDEFINED }
|
|
169
|
+
|
|
170
|
+
fun setBorderRadius(index: Int, radius: Float) {
|
|
171
|
+
borderRadius[index] = radius
|
|
172
|
+
activeView.setBorderRadius(index, radius)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
fun setBorderWidth(index: Int, width: Float) {
|
|
176
|
+
borderWidth[index] = width
|
|
177
|
+
activeView.setBorderWidth(index, width)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
fun setBorderColor(index: Int, rgb: Float, alpha: Float) {
|
|
181
|
+
borderColor[index] = rgb to alpha
|
|
182
|
+
activeView.setBorderColor(index, rgb, alpha)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Whether the image should be loaded again
|
|
187
|
+
*/
|
|
188
|
+
private var shouldRerender = false
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Currently loaded source
|
|
192
|
+
*/
|
|
193
|
+
private var loadedSource: GlideModel? = null
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Whether the transformation matrix should be reapplied
|
|
197
|
+
*/
|
|
198
|
+
private var transformationMatrixChanged = false
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Whether the view content should be cleared to blank when the source was changed.
|
|
202
|
+
*/
|
|
203
|
+
private var clearViewBeforeChangingSource = false
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Copies saved props to the provided view.
|
|
207
|
+
* It ensures that the view state is up to date.
|
|
208
|
+
*/
|
|
209
|
+
private fun copyProps(view: ExpoImageView) {
|
|
210
|
+
view.contentFit = contentFit
|
|
211
|
+
view.contentPosition = contentPosition
|
|
212
|
+
view.setBorderStyle(borderStyle)
|
|
213
|
+
view.setBackgroundColor(backgroundColor)
|
|
214
|
+
view.setTintColor(tintColor)
|
|
215
|
+
view.isFocusable = isFocusableProp
|
|
216
|
+
view.contentDescription = accessibilityLabel
|
|
217
|
+
borderColor.forEachIndexed { index, (rgb, alpha) ->
|
|
218
|
+
view.setBorderColor(index, rgb, alpha)
|
|
219
|
+
}
|
|
220
|
+
borderRadius.forEachIndexed { index, value ->
|
|
221
|
+
view.setBorderRadius(index, value)
|
|
222
|
+
}
|
|
223
|
+
borderWidth.forEachIndexed { index, value ->
|
|
224
|
+
view.setBorderWidth(index, value)
|
|
225
|
+
}
|
|
226
|
+
setIsScreenReaderFocusable(view, accessible)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Allows `isScreenReaderFocusable` to be set on apis below level 28
|
|
231
|
+
*/
|
|
232
|
+
private fun setIsScreenReaderFocusable(view: View, value: Boolean) {
|
|
233
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
234
|
+
view.isScreenReaderFocusable = value
|
|
235
|
+
} else {
|
|
236
|
+
ViewCompat.setAccessibilityDelegate(
|
|
237
|
+
this,
|
|
238
|
+
object : AccessibilityDelegateCompat() {
|
|
239
|
+
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfoCompat) {
|
|
240
|
+
info.isScreenReaderFocusable = value
|
|
241
|
+
super.onInitializeAccessibilityNodeInfo(host, info)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* When a new resource is available, this method tries to handle it.
|
|
250
|
+
* It decides where provided bitmap should be displayed and clears the previous target/image.
|
|
251
|
+
*/
|
|
252
|
+
fun onResourceReady(
|
|
253
|
+
target: ImageViewWrapperTarget,
|
|
254
|
+
resource: Drawable,
|
|
255
|
+
isPlaceholder: Boolean = false
|
|
256
|
+
) =
|
|
257
|
+
// The "onResourceReady" function will be triggered when the new resource is available by the Glide.
|
|
258
|
+
// According to the Glide documentation (https://bumptech.github.io/glide/doc/debugging.html#you-cant-start-or-clear-loads-in-requestlistener-or-target-callbacks),
|
|
259
|
+
// it's not advisable to clear the Glide target within the stack frame.
|
|
260
|
+
// To avoid this, a new runnable is posted to the front of the main queue, which can then clean or create targets.
|
|
261
|
+
// This ensures that the "onResourceReady" frame of the Glide code will be discarded, and the internal state can be altered once again.
|
|
262
|
+
// Normally, using "postAtFrontOfQueue" can lead to issues such as message queue starvation, ordering problems, and other unexpected consequences.
|
|
263
|
+
// However, in this case, it is safe to use as long as nothing else is added to the queue.
|
|
264
|
+
// The intention is simply to wait for the Glide code to finish before the content of the underlying views is changed during the same rendering tick.
|
|
265
|
+
mainHandler.postAtFrontOfQueue {
|
|
266
|
+
val transitionDuration = (transition?.duration ?: 0).toLong()
|
|
267
|
+
|
|
268
|
+
// If provided resource is a placeholder, but the target doesn't have a source, we treat it as a normal image.
|
|
269
|
+
if (!isPlaceholder || !target.hasSource) {
|
|
270
|
+
val (newView, previousView) = if (firstView.drawable == null) {
|
|
271
|
+
firstView to secondView
|
|
272
|
+
} else {
|
|
273
|
+
secondView to firstView
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
val clearPreviousView = {
|
|
277
|
+
previousView
|
|
278
|
+
.recycleView()
|
|
279
|
+
?.apply {
|
|
280
|
+
// When the placeholder is loaded, one target is displayed in both views.
|
|
281
|
+
// So we just have to move the reference to a new view instead of clearing the target.
|
|
282
|
+
if (this != target) {
|
|
283
|
+
clear(requestManager)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
configureView(newView, target, resource, isPlaceholder)
|
|
289
|
+
if (transitionDuration <= 0) {
|
|
290
|
+
clearPreviousView()
|
|
291
|
+
newView.alpha = 1f
|
|
292
|
+
newView.bringToFront()
|
|
293
|
+
} else {
|
|
294
|
+
newView.bringToFront()
|
|
295
|
+
previousView.alpha = 1f
|
|
296
|
+
newView.alpha = 0f
|
|
297
|
+
previousView.animate().apply {
|
|
298
|
+
duration = transitionDuration
|
|
299
|
+
alpha(0f)
|
|
300
|
+
withEndAction {
|
|
301
|
+
clearPreviousView()
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
newView.animate().apply {
|
|
305
|
+
duration = transitionDuration
|
|
306
|
+
alpha(1f)
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
} else {
|
|
310
|
+
// We don't want to show the placeholder if something is currently displayed.
|
|
311
|
+
// There is one exception - when we're displaying a different placeholder.
|
|
312
|
+
if ((firstView.drawable != null && !firstView.isPlaceholder) || secondView.drawable != null) {
|
|
313
|
+
return@postAtFrontOfQueue
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
firstView
|
|
317
|
+
.recycleView()
|
|
318
|
+
?.apply {
|
|
319
|
+
// The current target is already bound to the view. We don't want to cancel it in that case.
|
|
320
|
+
if (this != target) {
|
|
321
|
+
clear(requestManager)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
configureView(firstView, target, resource, isPlaceholder)
|
|
326
|
+
if (transitionDuration > 0) {
|
|
327
|
+
firstView.bringToFront()
|
|
328
|
+
firstView.alpha = 0f
|
|
329
|
+
secondView.isVisible = false
|
|
330
|
+
firstView.animate().apply {
|
|
331
|
+
duration = transitionDuration
|
|
332
|
+
alpha(1f)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
private fun configureView(
|
|
339
|
+
view: ExpoImageView,
|
|
340
|
+
target: ImageViewWrapperTarget,
|
|
341
|
+
resource: Drawable,
|
|
342
|
+
isPlaceholder: Boolean
|
|
343
|
+
) {
|
|
344
|
+
view.let {
|
|
345
|
+
it.setImageDrawable(resource)
|
|
346
|
+
|
|
347
|
+
it.isPlaceholder = isPlaceholder
|
|
348
|
+
it.placeholderContentFit = target.placeholderContentFit ?: ContentFit.ScaleDown
|
|
349
|
+
copyProps(it)
|
|
350
|
+
|
|
351
|
+
it.isVisible = true
|
|
352
|
+
|
|
353
|
+
it.currentTarget = target
|
|
354
|
+
|
|
355
|
+
// The view isn't layout when it's invisible.
|
|
356
|
+
// Therefore, we have to set the correct size manually.
|
|
357
|
+
it.layout(0, 0, width, height)
|
|
358
|
+
|
|
359
|
+
it.applyTransformationMatrix()
|
|
360
|
+
}
|
|
361
|
+
target.isUsed = true
|
|
362
|
+
|
|
363
|
+
if (resource is Animatable) {
|
|
364
|
+
resource.start()
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
private fun getBestSource(sources: List<SourceMap>): SourceMap? {
|
|
369
|
+
if (sources.isEmpty()) {
|
|
370
|
+
return null
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (sources.size == 1) {
|
|
374
|
+
return sources.first()
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
val targetPixelCount = width * height
|
|
378
|
+
if (targetPixelCount == 0) {
|
|
379
|
+
return null
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
var bestSource: SourceMap? = null
|
|
383
|
+
var bestFit = Double.MAX_VALUE
|
|
384
|
+
|
|
385
|
+
sources.forEach {
|
|
386
|
+
val fit = abs(1 - (it.pixelCount / targetPixelCount))
|
|
387
|
+
if (fit < bestFit) {
|
|
388
|
+
bestFit = fit
|
|
389
|
+
bestSource = it
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return bestSource
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
|
397
|
+
super.onSizeChanged(w, h, oldw, oldh)
|
|
398
|
+
rerenderIfNeeded(
|
|
399
|
+
shouldRerenderBecauseOfResize = allowDownscaling &&
|
|
400
|
+
contentFit != ContentFit.Fill &&
|
|
401
|
+
contentFit != ContentFit.None
|
|
402
|
+
)
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
private fun createPropOptions(): RequestOptions {
|
|
406
|
+
return RequestOptions()
|
|
407
|
+
.apply {
|
|
408
|
+
priority(this@ExpoImageViewWrapper.priority.toGlidePriority())
|
|
409
|
+
|
|
410
|
+
if (cachePolicy != CachePolicy.MEMORY_AND_DISK && cachePolicy != CachePolicy.MEMORY) {
|
|
411
|
+
skipMemoryCache(true)
|
|
412
|
+
}
|
|
413
|
+
if (cachePolicy == CachePolicy.NONE || cachePolicy == CachePolicy.MEMORY) {
|
|
414
|
+
diskCacheStrategy(DiskCacheStrategy.NONE)
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
blurRadius?.let {
|
|
418
|
+
transform(BlurTransformation(min(it, 25), 4))
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
fun onViewDestroys() {
|
|
424
|
+
firstView.setImageDrawable(null)
|
|
425
|
+
secondView.setImageDrawable(null)
|
|
426
|
+
|
|
427
|
+
requestManager.clear(firstTarget)
|
|
428
|
+
requestManager.clear(secondTarget)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
internal fun rerenderIfNeeded(shouldRerenderBecauseOfResize: Boolean = false) {
|
|
432
|
+
val bestSource = bestSource
|
|
433
|
+
val bestPlaceholder = bestPlaceholder
|
|
434
|
+
|
|
435
|
+
val sourceToLoad = bestSource?.createGlideModel(context)
|
|
436
|
+
val placeholder = bestPlaceholder?.createGlideModel(context)
|
|
437
|
+
// We only clean the image when the source is set to null and we don't have a placeholder or the view is empty.
|
|
438
|
+
if (width == 0 || height == 0 || (bestSource == null || sourceToLoad == null) && placeholder == null) {
|
|
439
|
+
firstView.recycleView()
|
|
440
|
+
secondView.recycleView()
|
|
441
|
+
|
|
442
|
+
requestManager.clear(firstTarget)
|
|
443
|
+
requestManager.clear(secondTarget)
|
|
444
|
+
|
|
445
|
+
shouldRerender = false
|
|
446
|
+
loadedSource = null
|
|
447
|
+
transformationMatrixChanged = false
|
|
448
|
+
clearViewBeforeChangingSource = false
|
|
449
|
+
return
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
val shouldRerender = sourceToLoad != loadedSource || shouldRerender || (sourceToLoad == null && placeholder != null)
|
|
453
|
+
if (shouldRerender || shouldRerenderBecauseOfResize) {
|
|
454
|
+
if (clearViewBeforeChangingSource) {
|
|
455
|
+
val activeView = if (firstView.drawable != null) {
|
|
456
|
+
firstView
|
|
457
|
+
} else {
|
|
458
|
+
secondView
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
activeView
|
|
462
|
+
.recycleView()
|
|
463
|
+
?.apply {
|
|
464
|
+
clear(requestManager)
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
this.shouldRerender = false
|
|
469
|
+
loadedSource = sourceToLoad
|
|
470
|
+
val options = bestSource?.createOptions(context)
|
|
471
|
+
val propOptions = createPropOptions()
|
|
472
|
+
|
|
473
|
+
val model = sourceToLoad?.glideData
|
|
474
|
+
if (model is GlideUrlWrapper) {
|
|
475
|
+
model.progressListener = progressListener
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
onLoadStart.invoke(Unit)
|
|
479
|
+
val newTarget = if (secondTarget.isUsed) {
|
|
480
|
+
firstTarget
|
|
481
|
+
} else {
|
|
482
|
+
secondTarget
|
|
483
|
+
}
|
|
484
|
+
newTarget.hasSource = sourceToLoad != null
|
|
485
|
+
|
|
486
|
+
val downsampleStrategy = if (allowDownscaling) {
|
|
487
|
+
object : DownsampleStrategy() {
|
|
488
|
+
var wasTriggered = false
|
|
489
|
+
override fun getScaleFactor(
|
|
490
|
+
sourceWidth: Int,
|
|
491
|
+
sourceHeight: Int,
|
|
492
|
+
requestedWidth: Int,
|
|
493
|
+
requestedHeight: Int
|
|
494
|
+
): Float {
|
|
495
|
+
// The method is invoked twice per asset, but we only need to preserve the original dimensions for the first call.
|
|
496
|
+
// As Glide uses Android downsampling, it can only adjust dimensions by a factor of two,
|
|
497
|
+
// and hence two distinct scaling factors are computed to achieve greater accuracy.
|
|
498
|
+
if (!wasTriggered) {
|
|
499
|
+
newTarget.sourceWidth = sourceWidth
|
|
500
|
+
newTarget.sourceHeight = sourceHeight
|
|
501
|
+
wasTriggered = true
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// The size of the container is unknown, we don't know what to do, so we just run the default scale.
|
|
505
|
+
if (requestedWidth == SIZE_ORIGINAL || requestedHeight == SIZE_ORIGINAL) {
|
|
506
|
+
return 1f
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
val aspectRation = calculateScaleFactor(
|
|
510
|
+
sourceWidth.toFloat(),
|
|
511
|
+
sourceHeight.toFloat(),
|
|
512
|
+
requestedWidth.toFloat(),
|
|
513
|
+
requestedHeight.toFloat()
|
|
514
|
+
)
|
|
515
|
+
|
|
516
|
+
// We don't want to upscale the image
|
|
517
|
+
return min(1f, aspectRation)
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
private fun calculateScaleFactor(
|
|
521
|
+
sourceWidth: Float,
|
|
522
|
+
sourceHeight: Float,
|
|
523
|
+
requestedWidth: Float,
|
|
524
|
+
requestedHeight: Float
|
|
525
|
+
): Float = when (contentFit) {
|
|
526
|
+
ContentFit.Contain -> min(
|
|
527
|
+
requestedWidth / sourceWidth,
|
|
528
|
+
requestedHeight / sourceHeight
|
|
529
|
+
)
|
|
530
|
+
ContentFit.Cover -> max(
|
|
531
|
+
requestedWidth / sourceWidth,
|
|
532
|
+
requestedHeight / sourceHeight
|
|
533
|
+
)
|
|
534
|
+
ContentFit.Fill, ContentFit.None -> 1f
|
|
535
|
+
ContentFit.ScaleDown -> if (requestedWidth < sourceWidth || requestedHeight < sourceHeight) {
|
|
536
|
+
// The container is smaller than the image — scale it down and behave like `contain`
|
|
537
|
+
min(
|
|
538
|
+
requestedWidth / sourceWidth,
|
|
539
|
+
requestedHeight / sourceHeight
|
|
540
|
+
)
|
|
541
|
+
} else {
|
|
542
|
+
// The container is bigger than the image — don't scale it and behave like `none`
|
|
543
|
+
1f
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
override fun getSampleSizeRounding(
|
|
548
|
+
sourceWidth: Int,
|
|
549
|
+
sourceHeight: Int,
|
|
550
|
+
requestedWidth: Int,
|
|
551
|
+
requestedHeight: Int
|
|
552
|
+
) = SampleSizeRounding.QUALITY
|
|
553
|
+
}
|
|
554
|
+
} else {
|
|
555
|
+
DownsampleStrategy.NONE
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
val request = requestManager
|
|
559
|
+
.asDrawable()
|
|
560
|
+
.load(model)
|
|
561
|
+
.apply {
|
|
562
|
+
if (placeholder != null) {
|
|
563
|
+
thumbnail(requestManager.load(placeholder.glideData))
|
|
564
|
+
val newPlaceholderContentFit = if (bestPlaceholder.isBlurhash() || bestPlaceholder.isThumbhash()) {
|
|
565
|
+
contentFit
|
|
566
|
+
} else {
|
|
567
|
+
placeholderContentFit
|
|
568
|
+
}
|
|
569
|
+
newTarget.placeholderContentFit = newPlaceholderContentFit
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
.apply {
|
|
573
|
+
options?.let {
|
|
574
|
+
apply(it)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
.downsample(downsampleStrategy)
|
|
578
|
+
.addListener(GlideRequestListener(WeakReference(this)))
|
|
579
|
+
.encodeQuality(100)
|
|
580
|
+
.apply(propOptions)
|
|
581
|
+
|
|
582
|
+
request.into(newTarget)
|
|
583
|
+
} else {
|
|
584
|
+
// In the case where the source didn't change, but the transformation matrix has to be
|
|
585
|
+
// recalculated, we can apply the new transformation right away.
|
|
586
|
+
// When the source and the matrix is different, we don't want to do anything.
|
|
587
|
+
// We don't want to changed the transformation of the currently displayed image.
|
|
588
|
+
// The new matrix will be applied when new resource is loaded.
|
|
589
|
+
if (transformationMatrixChanged) {
|
|
590
|
+
activeView.applyTransformationMatrix()
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
transformationMatrixChanged = false
|
|
594
|
+
clearViewBeforeChangingSource = false
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
init {
|
|
598
|
+
val matchParent = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
|
|
599
|
+
|
|
600
|
+
layoutParams = matchParent
|
|
601
|
+
|
|
602
|
+
firstView.isVisible = true
|
|
603
|
+
secondView.isVisible = true
|
|
604
|
+
|
|
605
|
+
// We need to add a `FrameLayout` to allow views to overflow.
|
|
606
|
+
// With the `LinearLayout` is impossible to render two views on each other.
|
|
607
|
+
val layout = FrameLayout(context).apply {
|
|
608
|
+
layoutParams = matchParent
|
|
609
|
+
addView(
|
|
610
|
+
firstView,
|
|
611
|
+
matchParent
|
|
612
|
+
)
|
|
613
|
+
addView(
|
|
614
|
+
secondView,
|
|
615
|
+
matchParent
|
|
616
|
+
)
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
addView(layout, matchParent)
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
companion object {
|
|
623
|
+
private var requestManager: RequestManager? = null
|
|
624
|
+
private var appContextRef: WeakReference<AppContext?> = WeakReference(null)
|
|
625
|
+
private var activityRef: WeakReference<Activity?> = WeakReference(null)
|
|
626
|
+
|
|
627
|
+
fun getOrCreateRequestManager(
|
|
628
|
+
appContext: AppContext,
|
|
629
|
+
activity: Activity
|
|
630
|
+
): RequestManager = synchronized(Companion) {
|
|
631
|
+
val cachedRequestManager = requestManager
|
|
632
|
+
?: return createNewRequestManager(activity).also {
|
|
633
|
+
requestManager = it
|
|
634
|
+
appContextRef = WeakReference(appContext)
|
|
635
|
+
activityRef = WeakReference(activity)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Request manager was created using different activity or app context
|
|
639
|
+
if (appContextRef.get() != appContext || activityRef.get() != activity) {
|
|
640
|
+
return createNewRequestManager(activity).also {
|
|
641
|
+
requestManager = it
|
|
642
|
+
appContextRef = WeakReference(appContext)
|
|
643
|
+
activityRef = WeakReference(activity)
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
return cachedRequestManager
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
private fun createNewRequestManager(activity: Activity): RequestManager = Glide.with(activity)
|
|
651
|
+
}
|
|
652
|
+
}
|