@nativescript-community/ui-image 4.6.6 → 5.0.0

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.
Files changed (55) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -20
  3. package/index-common.d.ts +47 -18
  4. package/index-common.js +5 -69
  5. package/index-common.js.map +1 -1
  6. package/index.android.d.ts +33 -60
  7. package/index.android.js +597 -702
  8. package/index.android.js.map +1 -1
  9. package/index.d.ts +17 -92
  10. package/index.ios.d.ts +5 -10
  11. package/index.ios.js +72 -54
  12. package/index.ios.js.map +1 -1
  13. package/package.json +4 -4
  14. package/platforms/android/include.gradle +21 -16
  15. package/platforms/android/java/com/nativescript/image/CacheKeyStore.java +65 -0
  16. package/platforms/android/java/com/nativescript/image/CapturingEngineKeyFactory.java +43 -0
  17. package/platforms/android/java/com/nativescript/image/CompositeRequestListener.java +58 -0
  18. package/platforms/android/java/com/nativescript/image/ConditionalCrossFadeFactory.java +33 -0
  19. package/platforms/android/java/com/nativescript/image/CustomDataFetcher.java +124 -0
  20. package/platforms/android/java/com/nativescript/image/CustomGlideModule.java +220 -0
  21. package/platforms/android/java/com/nativescript/image/CustomGlideUrl.java +52 -0
  22. package/platforms/android/java/com/nativescript/image/CustomUrlLoader.java +74 -0
  23. package/platforms/android/java/com/nativescript/image/EvictionManager.java +735 -0
  24. package/platforms/android/java/com/nativescript/image/ExtractRequestOptions.java +109 -0
  25. package/platforms/android/java/com/nativescript/image/ImageLoadSourceCallback.java +5 -0
  26. package/platforms/android/java/com/nativescript/image/ImageProgressCallback.java +5 -0
  27. package/platforms/android/java/com/nativescript/image/LoadSourceInterceptor.java +28 -0
  28. package/platforms/android/java/com/nativescript/image/MatrixDrawable.java +200 -0
  29. package/platforms/android/java/com/nativescript/image/MatrixDrawableImageViewTarget.java +154 -0
  30. package/platforms/android/java/com/nativescript/image/MatrixImageView.java +696 -0
  31. package/platforms/android/java/com/nativescript/image/ProgressInterceptor.java +25 -0
  32. package/platforms/android/java/com/nativescript/image/ProgressResponseBody.java +70 -0
  33. package/platforms/android/java/com/nativescript/image/RecordingDigest.java +48 -0
  34. package/platforms/android/java/com/nativescript/image/RecreatedResourceKey.java +95 -0
  35. package/platforms/android/java/com/nativescript/image/SaveKeysRequestListener.java +145 -0
  36. package/platforms/android/java/com/nativescript/image/ScaleUtils.java +129 -0
  37. package/platforms/android/java/com/nativescript/image/SharedPrefCacheKeyStore.java +92 -0
  38. package/platforms/android/native-api-usage.json +39 -37
  39. package/platforms/ios/Podfile +1 -1
  40. package/references.d.ts +0 -1
  41. package/tsconfig.tsbuildinfo +1 -1
  42. package/typings/android.d.ts +4 -27
  43. package/typings/glide.android.d.ts +9395 -0
  44. package/typings/glide.okhttp.android.d.ts +104 -0
  45. package/typings/glide.transform.android.d.ts +540 -0
  46. package/typings/ui_image.android.d.ts +517 -0
  47. package/platforms/android/java/com/nativescript/image/BaseDataSubscriber.java +0 -22
  48. package/platforms/android/java/com/nativescript/image/BaseDataSubscriberListener.java +0 -9
  49. package/platforms/android/java/com/nativescript/image/DraweeView.java +0 -371
  50. package/platforms/android/java/com/nativescript/image/NetworkImageRequest.java +0 -55
  51. package/platforms/android/java/com/nativescript/image/OkHttpNetworkFetcher.java +0 -56
  52. package/platforms/android/java/com/nativescript/image/ScalingBlurPostprocessor.java +0 -64
  53. package/platforms/android/java/com/nativescript/image/ScalingUtils.java +0 -519
  54. package/typings/fresco-processors.d.ts +0 -53
  55. package/typings/fresco.d.ts +0 -12070
@@ -0,0 +1,220 @@
1
+ package com.nativescript.image;
2
+
3
+ import android.content.Context;
4
+ import android.util.Log;
5
+ import androidx.annotation.NonNull;
6
+ import com.bumptech.glide.Glide;
7
+ import com.bumptech.glide.GlideBuilder;
8
+ import com.bumptech.glide.Registry;
9
+ import com.bumptech.glide.annotation.GlideModule;
10
+ import com.bumptech.glide.load.Key;
11
+ import com.bumptech.glide.load.Options;
12
+ import com.bumptech.glide.load.engine.cache.MemorySizeCalculator;
13
+ import com.bumptech.glide.load.engine.cache.DiskCache;
14
+ import com.bumptech.glide.load.engine.cache.DiskLruCacheWrapper;
15
+ import com.bumptech.glide.load.engine.cache.MemoryCache;
16
+ import com.bumptech.glide.load.engine.cache.LruResourceCache;
17
+ import com.bumptech.glide.load.engine.CapturingEngineKeyFactory;
18
+ import com.bumptech.glide.load.model.GlideUrl;
19
+ import com.bumptech.glide.module.AppGlideModule;
20
+ import com.bumptech.glide.RequestBuilder;
21
+ import com.bumptech.glide.signature.ObjectKey;
22
+ import okhttp3.OkHttpClient;
23
+ import java.io.InputStream;
24
+ import java.lang.reflect.Field;
25
+ import java.lang.reflect.Modifier;
26
+
27
+ @GlideModule
28
+ public class CustomGlideModule extends AppGlideModule {
29
+ private static final String TAG = "MyAppGlideModule";
30
+ private static final String INJECT_TAG = "EngineKeyFactoryInject";
31
+
32
+ @Override
33
+ public void applyOptions(@NonNull Context context, @NonNull GlideBuilder builder) {
34
+
35
+ // Use our custom memory cache wrapper
36
+ MemorySizeCalculator calculator = new MemorySizeCalculator.Builder(context)
37
+ .setMemoryCacheScreens(2)
38
+ .build();
39
+ LruResourceCache memoryCache = new LruResourceCache(calculator.getMemoryCacheSize());
40
+ EvictionManager.get().setMemoryCache(memoryCache);
41
+ builder.setMemoryCache(memoryCache);
42
+ // Set a disk cache factory that also registers the disk cache instance with
43
+ // EvictionManager.
44
+ builder.setDiskCache(new DiskCache.Factory() {
45
+ @Override
46
+ public DiskCache build() {
47
+ DiskCache dc = DiskLruCacheWrapper.create(context.getCacheDir(), 250 * 1024 * 1024);
48
+ EvictionManager.get().setDiskCache(dc);
49
+ return dc;
50
+ }
51
+ });
52
+ }
53
+
54
+ @Override
55
+ public void registerComponents(@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
56
+
57
+ // Create base OkHttp client
58
+ OkHttpClient client = new OkHttpClient.Builder().build();
59
+
60
+ // SINGLE LOADER: CustomUrlLoader handles both CustomGlideUrl and GlideUrl
61
+ // This replaces both the old CustomUrlLoader and UrlTrackingModelLoader
62
+ registry.replace(
63
+ GlideUrl.class,
64
+ InputStream.class,
65
+ new CustomUrlLoader.Factory(client));
66
+ // Listener: called when an EngineKey is created. Update the stored keys to
67
+ // include engineKey.
68
+ CapturingEngineKeyFactory.Listener listener = (engineKey, model) -> {
69
+ // Log.i("JS", "CapturingEngineKeyFactory.Listener 1" + engineKey + " " + model);
70
+ if (model == null)
71
+ return;
72
+ String id = String.valueOf(model);
73
+
74
+ // Read either persistent or in-memory stored keys
75
+ CacheKeyStore.StoredKeys s = EvictionManager.get().getKeyStore().get(id);
76
+ if (s == null) {
77
+ // if key store exists but no entry, create minimal
78
+ s = new CacheKeyStore.StoredKeys(
79
+ new com.bumptech.glide.signature.ObjectKey(id),
80
+ new com.bumptech.glide.signature.ObjectKey("signature-none"),
81
+ com.bumptech.glide.request.target.Target.SIZE_ORIGINAL,
82
+ com.bumptech.glide.request.target.Target.SIZE_ORIGINAL,
83
+ null,
84
+ null,
85
+ android.graphics.Bitmap.class,
86
+ new Options(),
87
+ null,
88
+ null);
89
+ }
90
+
91
+ // Build an updated StoredKeys that preserves everything and sets engineKey
92
+ CacheKeyStore.StoredKeys updated = new CacheKeyStore.StoredKeys(
93
+ s.sourceKey,
94
+ s.signature,
95
+ s.width,
96
+ s.height,
97
+ s.transformation, // may be null; preserved for in-process fallback
98
+ s.transformationKeyBytes, // raw bytes if recorded (preferred)
99
+ s.decodedResourceClass,
100
+ s.options,
101
+ s.optionsKeyBytes,
102
+ engineKey // set the captured engineKey
103
+ );
104
+
105
+ // Put updated entry into the in-memory store so later EvictionManager can
106
+ // remove memory entry.
107
+ EvictionManager.get().getKeyStore().put(id, updated);
108
+ };
109
+
110
+ // Create the capturing factory
111
+ // instantiate the capturing factory (public class in
112
+ // com.bumptech.glide.load.engine)
113
+ Object capturingFactory = new com.bumptech.glide.load.engine.CapturingEngineKeyFactory(listener);
114
+
115
+ // inject it into Glide's Engine reflectively, passing it as Object (no
116
+ // EngineKeyFactory compile-time ref)
117
+ try {
118
+ injectEngineKeyFactoryIntoGlide(glide, capturingFactory);
119
+ Log.i(TAG, "Injected capturing EngineKeyFactory into Glide engine");
120
+ } catch (Exception e) {
121
+ Log.w(TAG, "Failed to inject capturing EngineKeyFactory", e);
122
+ }
123
+
124
+ }
125
+
126
+ /**
127
+ * Reflectively find Glide.engine and replace its EngineKeyFactory-typed field
128
+ * with capturingFactory.
129
+ * This tries to be resilient across minor Glide 5.x binary differences.
130
+ */
131
+ private void injectEngineKeyFactoryIntoGlide(Object glideInstance, Object capturingFactory) throws Exception {
132
+ if (glideInstance == null) {
133
+ throw new IllegalArgumentException("glideInstance == null");
134
+ }
135
+ // 1) find Engine field on Glide
136
+ Field engineField = null;
137
+ for (Field f : glideInstance.getClass().getDeclaredFields()) {
138
+ if (f.getType().getName().contains("Engine")) {
139
+ engineField = f;
140
+ break;
141
+ }
142
+ }
143
+ if (engineField == null) {
144
+ throw new NoSuchFieldException("Could not find Engine field on Glide");
145
+ }
146
+ engineField.setAccessible(true);
147
+ Object engineInstance = engineField.get(glideInstance);
148
+ if (engineInstance == null) {
149
+ throw new IllegalStateException("Glide.engine is null");
150
+ }
151
+
152
+ // 2) find the keyFactory-like field on Engine
153
+ Field targetField = null;
154
+ Class<?> engineClass = engineInstance.getClass();
155
+ Class<?> cur = engineClass;
156
+ while (cur != null && targetField == null) {
157
+ for (Field f : cur.getDeclaredFields()) {
158
+ String typeName = f.getType().getName();
159
+ if (typeName.contains("EngineKeyFactory") || typeName.endsWith("EngineKeyFactory")
160
+ || f.getName().toLowerCase().contains("keyfactory")) {
161
+ targetField = f;
162
+ break;
163
+ }
164
+ }
165
+ cur = cur.getSuperclass();
166
+ }
167
+ if (targetField == null) {
168
+ throw new NoSuchFieldException(
169
+ "Could not find EngineKeyFactory-like field in Engine class: " + engineClass.getName());
170
+ }
171
+
172
+ targetField.setAccessible(true);
173
+
174
+ // Log current value
175
+ Object before = targetField.get(engineInstance);
176
+ int beforeHash = System.identityHashCode(before);
177
+ String beforeClass = (before == null) ? "null" : before.getClass().getName();
178
+
179
+ // If field is final, try to remove final modifier so setting works reliably
180
+ try {
181
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
182
+ modifiersField.setAccessible(true);
183
+ int mods = targetField.getModifiers();
184
+ if (Modifier.isFinal(mods)) {
185
+ modifiersField.setInt(targetField, mods & ~Modifier.FINAL);
186
+ }
187
+ } catch (NoSuchFieldException nsf) {
188
+ // Android ART may not expose 'modifiers' the same way; ignore if not available
189
+ Log.i(INJECT_TAG, "Could not access Field.modifiers to clear final; continuing");
190
+ } catch (Throwable t) {
191
+ Log.w(INJECT_TAG, "Failed to clear final modifier (continuing attempt to set field)", t);
192
+ }
193
+
194
+ // 3) set the new factory instance
195
+ try {
196
+ targetField.set(engineInstance, capturingFactory);
197
+ } catch (IllegalAccessException | IllegalArgumentException iae) {
198
+ // Log and rethrow so caller can inspect
199
+ Log.w(INJECT_TAG, "targetField.set(...) failed", iae);
200
+ throw iae;
201
+ }
202
+
203
+ // 4) read back and log to verify
204
+ Object after = targetField.get(engineInstance);
205
+ int afterHash = System.identityHashCode(after);
206
+ String afterClass = (after == null) ? "null" : after.getClass().getName();
207
+
208
+ // quick verification: are they the same instance we tried to set?
209
+ boolean sameInstance = (after == capturingFactory);
210
+ if (!sameInstance) {
211
+ throw new IllegalStateException(
212
+ "Injection did not set the expected capturingFactory instance. afterClass=" + afterClass);
213
+ }
214
+ }
215
+
216
+ @Override
217
+ public boolean isManifestParsingEnabled() {
218
+ return false;
219
+ }
220
+ }
@@ -0,0 +1,52 @@
1
+ package com.nativescript.image;
2
+
3
+ import com.bumptech.glide.load.model.GlideUrl;
4
+ import com.bumptech.glide.load.model.LazyHeaders;
5
+ import java.util.Map;
6
+
7
+ /**
8
+ * Custom GlideUrl with progress and load source callbacks.
9
+ * Headers are automatically included in cache key by Glide's LazyHeaders.
10
+ */
11
+ public class CustomGlideUrl extends GlideUrl {
12
+ private final ImageProgressCallback progressCallback;
13
+ private final ImageLoadSourceCallback loadSourceCallback;
14
+
15
+ public CustomGlideUrl(String url,
16
+ Map<String, String> headers,
17
+ ImageProgressCallback progressCallback,
18
+ ImageLoadSourceCallback loadSourceCallback) {
19
+ // Use LazyHeaders.Builder - Glide automatically includes these in cache key!
20
+ super(url, buildLazyHeaders(headers));
21
+ this.progressCallback = progressCallback;
22
+ this.loadSourceCallback = loadSourceCallback;
23
+ }
24
+
25
+ private static LazyHeaders buildLazyHeaders(Map<String, String> headers) {
26
+ LazyHeaders.Builder builder = new LazyHeaders.Builder();
27
+
28
+ if (headers != null) {
29
+ for (Map.Entry<String, String> entry : headers.entrySet()) {
30
+ builder.addHeader(entry.getKey(), entry.getValue());
31
+ }
32
+ }
33
+
34
+ return builder.build();
35
+ }
36
+
37
+ public ImageProgressCallback getProgressCallback() {
38
+ return progressCallback;
39
+ }
40
+
41
+ public ImageLoadSourceCallback getLoadSourceCallback() {
42
+ return loadSourceCallback;
43
+ }
44
+
45
+ public boolean hasProgressListener() {
46
+ return progressCallback != null;
47
+ }
48
+
49
+ public boolean hasLoadSourceListener() {
50
+ return loadSourceCallback != null;
51
+ }
52
+ }
@@ -0,0 +1,74 @@
1
+ package com.nativescript.image;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import androidx.annotation.Nullable;
5
+ import com.bumptech.glide.load.Options;
6
+ import com.bumptech.glide.load.data.DataFetcher;
7
+ import com.bumptech.glide.load.model.GlideUrl;
8
+ import com.bumptech.glide.load.model.ModelLoader;
9
+ import com.bumptech.glide.load.model.ModelLoaderFactory;
10
+ import com.bumptech.glide.load.model.MultiModelLoaderFactory;
11
+ import okhttp3.Call;
12
+ import okhttp3.OkHttpClient;
13
+ import java.io.InputStream;
14
+ import android.util.Log;
15
+
16
+ /**
17
+ * Unified ModelLoader that handles both CustomGlideUrl and standard GlideUrl.
18
+ * This eliminates the need for UrlTrackingModelLoader.
19
+ */
20
+ public class CustomUrlLoader implements ModelLoader<GlideUrl, InputStream> {
21
+ private final Call.Factory client;
22
+
23
+ public CustomUrlLoader(Call.Factory client) {
24
+ this.client = client;
25
+ }
26
+
27
+ @Nullable
28
+ @Override
29
+ public LoadData<InputStream> buildLoadData(
30
+ @NonNull GlideUrl model,
31
+ int width,
32
+ int height,
33
+ @NonNull Options options) {
34
+
35
+ // Create the appropriate data fetcher
36
+ DataFetcher<InputStream> fetcher;
37
+
38
+ if (model instanceof CustomGlideUrl) {
39
+ // Use CustomDataFetcher for CustomGlideUrl (supports progress/load source)
40
+ fetcher = new CustomDataFetcher(client, (CustomGlideUrl) model);
41
+ } else {
42
+ // Use standard OkHttp fetcher for regular GlideUrl
43
+ fetcher = new com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher(
44
+ client,
45
+ model);
46
+ }
47
+
48
+ return new LoadData<>(model, fetcher);
49
+ }
50
+
51
+ @Override
52
+ public boolean handles(@NonNull GlideUrl model) {
53
+ // Handles both CustomGlideUrl and standard GlideUrl
54
+ return true;
55
+ }
56
+
57
+ public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
58
+ private final OkHttpClient client;
59
+
60
+ public Factory(OkHttpClient client) {
61
+ this.client = client;
62
+ }
63
+
64
+ @NonNull
65
+ @Override
66
+ public ModelLoader<GlideUrl, InputStream> build(MultiModelLoaderFactory multiFactory) {
67
+ return new CustomUrlLoader(client);
68
+ }
69
+
70
+ @Override
71
+ public void teardown() {
72
+ }
73
+ }
74
+ }