@nativescript-community/ui-image 4.6.5 → 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 +11 -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 -703
  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
package/index.android.js CHANGED
@@ -1,179 +1,198 @@
1
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
1
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
2
2
  export * from './index-common';
3
- import { Application, ImageAsset, ImageSource, Trace, Utils, backgroundInternalProperty, knownFolders, path } from '@nativescript/core';
3
+ import { ImageAsset, ImageSource, Trace, Utils, backgroundInternalProperty, knownFolders, path } from '@nativescript/core';
4
4
  import { isString } from '@nativescript/core/utils/types';
5
5
  import { layout } from '@nativescript/core/utils/layout-helper';
6
- import { CLog, CLogTypes, EventData, ImageBase, ScaleType, aspectRatioProperty, backgroundUriProperty, blurDownSamplingProperty, blurRadiusProperty, fadeDurationProperty, failureImageUriProperty, headersProperty, imageRotationProperty, lowerResSrcProperty, needRequestImage, noRatioEnforceProperty, placeholderImageUriProperty, progressBarColorProperty, roundAsCircleProperty, roundBottomLeftRadiusProperty, roundBottomRightRadiusProperty, roundTopLeftRadiusProperty, roundTopRightRadiusProperty, showProgressBarProperty, srcProperty, stretchProperty, tintColorProperty, wrapNativeException } from './index-common';
6
+ import { CLog, CLogTypes, ImageBase, ScaleType, aspectRatioProperty, backgroundUriProperty, blurDownSamplingProperty, blurRadiusProperty, decodeHeightProperty, decodeWidthProperty, fadeDurationProperty, failureImageUriProperty, headersProperty, imageRotationProperty, lowerResSrcProperty, needRequestImage, noRatioEnforceProperty, placeholderImageUriProperty, roundAsCircleProperty, roundBottomLeftRadiusProperty, roundBottomRightRadiusProperty, roundTopLeftRadiusProperty, roundTopRightRadiusProperty, srcProperty, stretchProperty, tintColorProperty, wrapNativeException } from './index-common';
7
7
  let initialized = false;
8
- let initializeConfig;
8
+ let glideInstance;
9
+ // global signature to invalidate all cache if needed by plugin
10
+ let signature;
11
+ const globalSignatureKey = 'v1';
9
12
  export function initialize(config) {
10
13
  if (!initialized) {
11
14
  const context = Utils.android.getApplicationContext();
12
15
  if (!context) {
13
- initializeConfig = config;
14
16
  return;
15
17
  }
16
- let builder;
17
- const useOkhttp = config?.useOkhttp !== false;
18
- if (useOkhttp) {
19
- //@ts-ignore
20
- let client;
21
- //@ts-ignore
22
- if (useOkhttp instanceof okhttp3.OkHttpClient) {
23
- client = useOkhttp;
24
- }
25
- else {
26
- //@ts-ignore
27
- client = new okhttp3.OkHttpClient();
28
- }
29
- builder = com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory.newBuilder(context, client);
30
- builder.setNetworkFetcher(new com.nativescript.image.OkHttpNetworkFetcher(client));
31
- }
32
- else {
33
- builder = com.facebook.imagepipeline.core.ImagePipelineConfig.newBuilder(context);
18
+ if (config?.usePersistentCacheKeyStore) {
19
+ const sharedStore = new com.nativescript.image.SharedPrefCacheKeyStore(context.getApplicationContext());
20
+ com.nativescript.image.EvictionManager.get().setPersistentStore(sharedStore);
34
21
  }
35
- builder.setDownsampleEnabled(config?.isDownsampleEnabled === true);
36
- if (config?.leakTracker) {
37
- builder.setCloseableReferenceLeakTracker(config.leakTracker);
38
- }
39
- // builder.experiment().setNativeCodeDisabled(true);
40
- const imagePipelineConfig = builder.build();
41
- com.facebook.drawee.backends.pipeline.Fresco.initialize(context, imagePipelineConfig);
22
+ // bumping `v1` will invalidate all cache
23
+ signature = new com.bumptech.glide.signature.ObjectKey(config?.globalSignatureKey ?? globalSignatureKey);
42
24
  initialized = true;
43
- initializeConfig = null;
44
- }
45
- }
46
- let imagePineLine;
47
- export function getImagePipeline() {
48
- if (!imagePineLine) {
49
- if (Application.android.nativeApp) {
50
- const nativePipe = com.facebook.drawee.backends.pipeline.Fresco.getImagePipeline();
51
- imagePineLine = new ImagePipeline();
52
- imagePineLine.android = nativePipe;
53
- }
54
- }
55
- return imagePineLine;
56
- }
57
- export function shutDown() {
58
- if (!initialized) {
59
- return;
60
- }
61
- initialized = false;
62
- com.facebook.drawee.view.SimpleDraweeView.shutDown();
63
- com.facebook.drawee.backends.pipeline.Fresco.shutDown();
64
- }
65
- function getUri(src, asNative = true) {
66
- let uri;
67
- let imagePath;
68
- if (src instanceof ImageAsset) {
69
- imagePath = src.android;
70
- }
71
- else {
72
- imagePath = src;
73
- }
74
- if (Utils.isFileOrResourcePath(imagePath)) {
75
- if (imagePath.indexOf(Utils.RESOURCE_PREFIX) === 0) {
76
- const resName = imagePath.substring(Utils.RESOURCE_PREFIX.length);
77
- const identifier = Utils.android.resources.getDrawableId(resName);
78
- if (0 < identifier) {
79
- const netUri = new android.net.Uri.Builder().scheme(com.facebook.common.util.UriUtil.LOCAL_RESOURCE_SCHEME).path(java.lang.String.valueOf(identifier)).build();
80
- if (asNative) {
81
- return netUri;
82
- }
83
- uri = netUri.toString();
84
- }
85
- }
86
- else if (imagePath.indexOf('~/') === 0) {
87
- uri = `file:${path.join(knownFolders.currentApp().path, imagePath.replace('~/', ''))}`;
88
- }
89
- else if (imagePath.indexOf('/') === 0) {
90
- uri = `file:${imagePath}`;
91
- }
25
+ glideInstance = com.bumptech.glide.Glide.get(context);
26
+ com.nativescript.image.EvictionManager.get().clearAll();
27
+ // this is needed for further buildKey to trigger ...
28
+ com.bumptech.glide.Glide.with(context)
29
+ .load('toto?ts=' + Date().valueOf())
30
+ .apply(new com.bumptech.glide.request.RequestOptions().signature(new com.bumptech.glide.signature.ObjectKey(Date().valueOf())))
31
+ .preload();
32
+ // com.nativescript.image.EngineKeyFactoryMethodDumper.dumpKeyFactoryMethods(glideInstance);
33
+ // com.nativescript.image.ForcePreloadTest.forcePreloadAfterInjection(context, 'https://example.com/test-image.png');
92
34
  }
93
- else {
94
- uri = imagePath;
95
- }
96
- return asNative ? android.net.Uri.parse(uri) : uri;
97
- }
98
- function isVectorDrawable(context, resId) {
99
- const resources = context.getResources();
100
- // VectorDrawable resources are usually stored as "drawable" in XML format
101
- const value = new android.util.TypedValue();
102
- resources.getValue(resId, value, true);
103
- if (value.string.toString().endsWith('.xml')) {
104
- // It's most likely a VectorDrawable
105
- return true;
106
- }
107
- // If it's not a vector, it's probably a BitmapDrawable or another type
108
- return false;
109
- }
110
- function getBitmapFromVectorDrawable(context, drawableId) {
111
- const drawable = Utils.android.getApplicationContext().getDrawable(drawableId);
112
- const bitmap = android.graphics.Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), android.graphics.Bitmap.Config.ARGB_8888);
113
- const canvas = new android.graphics.Canvas(bitmap);
114
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
115
- drawable.draw(canvas);
116
- console.log('getBitmapFromVectorDrawable', bitmap, bitmap.getWidth(), bitmap.getHeight);
117
- return new android.graphics.drawable.BitmapDrawable(context.getResources(), bitmap);
118
35
  }
119
36
  export class ImagePipeline {
120
37
  toUri(value) {
121
38
  if (value instanceof android.net.Uri) {
122
- return value;
39
+ return value.toString();
123
40
  }
124
- return android.net.Uri.parse(value);
41
+ return value;
125
42
  }
126
43
  getCacheKey(uri, context) {
127
- // iOS only
128
44
  return uri;
129
45
  }
130
46
  isInDiskCache(uri) {
131
- return this._android.isInDiskCacheSync(this.toUri(uri));
47
+ const url = this.toUri(uri);
48
+ return new Promise((resolve, reject) => {
49
+ com.nativescript.image.EvictionManager.get().isInDiskCacheAsync(url, new com.nativescript.image.EvictionManager.DiskPresenceCallback({
50
+ onResult(source, transform) {
51
+ resolve(source || transform);
52
+ }
53
+ }));
54
+ });
132
55
  }
133
56
  isInBitmapMemoryCache(uri) {
134
- return this._android.isInBitmapMemoryCache(this.toUri(uri));
57
+ // Still not directly accessible, but we can check if it's registered
58
+ const url = this.toUri(uri);
59
+ return com.nativescript.image.EvictionManager.get().isInMemoryCache(url);
135
60
  }
136
61
  evictFromMemoryCache(uri) {
137
- this._android.evictFromMemoryCache(this.toUri(uri));
62
+ const url = this.toUri(uri);
63
+ return new Promise((resolve, reject) => {
64
+ com.nativescript.image.EvictionManager.get().evictMemoryForId(url, new com.nativescript.image.EvictionManager.EvictionCallback({
65
+ onComplete(success, error) {
66
+ if (success) {
67
+ resolve();
68
+ }
69
+ else {
70
+ if (Trace.isEnabled()) {
71
+ CLog(CLogTypes.error, error);
72
+ }
73
+ reject(error);
74
+ }
75
+ }
76
+ }));
77
+ });
138
78
  }
139
- async evictFromDiskCache(uri) {
140
- this._android.evictFromDiskCache(this.toUri(uri));
79
+ evictFromDiskCache(uri) {
80
+ const url = this.toUri(uri);
81
+ return new Promise((resolve, reject) => {
82
+ com.nativescript.image.EvictionManager.get().evictDiskForId(url, new com.nativescript.image.EvictionManager.EvictionCallback({
83
+ onComplete(success, error) {
84
+ if (success) {
85
+ resolve();
86
+ }
87
+ else {
88
+ if (Trace.isEnabled()) {
89
+ CLog(CLogTypes.error, error);
90
+ }
91
+ reject(error);
92
+ }
93
+ }
94
+ }));
95
+ });
141
96
  }
142
- async evictFromCache(uri) {
143
- this._android.evictFromCache(this.toUri(uri));
97
+ evictFromCache(uri) {
98
+ const url = this.toUri(uri);
99
+ return new Promise((resolve, reject) => {
100
+ com.nativescript.image.EvictionManager.get().evictAllForId(url, new com.nativescript.image.EvictionManager.EvictionCallback({
101
+ onComplete(success, error) {
102
+ if (success) {
103
+ resolve();
104
+ }
105
+ else {
106
+ if (Trace.isEnabled()) {
107
+ CLog(CLogTypes.error, error);
108
+ }
109
+ reject(error);
110
+ }
111
+ }
112
+ }));
113
+ });
144
114
  }
145
115
  clearCaches() {
146
- this._android.clearCaches();
116
+ return new Promise((resolve, reject) => {
117
+ com.nativescript.image.EvictionManager.get().clearAll(new com.nativescript.image.EvictionManager.EvictionCallback({
118
+ onComplete(success, error) {
119
+ if (success) {
120
+ resolve();
121
+ }
122
+ else {
123
+ if (Trace.isEnabled()) {
124
+ CLog(CLogTypes.error, error);
125
+ }
126
+ reject(error);
127
+ }
128
+ }
129
+ }));
130
+ });
147
131
  }
148
132
  clearMemoryCaches() {
149
- this._android.clearMemoryCaches();
133
+ return new Promise((resolve, reject) => {
134
+ com.nativescript.image.EvictionManager.get().clearMemory(new com.nativescript.image.EvictionManager.EvictionCallback({
135
+ onComplete(success, error) {
136
+ if (success) {
137
+ resolve();
138
+ }
139
+ else {
140
+ if (Trace.isEnabled()) {
141
+ CLog(CLogTypes.error, error);
142
+ }
143
+ reject(error);
144
+ }
145
+ }
146
+ }));
147
+ });
150
148
  }
151
149
  clearDiskCaches() {
152
- this._android.clearDiskCaches();
150
+ return new Promise((resolve, reject) => {
151
+ com.nativescript.image.EvictionManager.get().clearDiskCache(new com.nativescript.image.EvictionManager.EvictionCallback({
152
+ onComplete(success, error) {
153
+ if (success) {
154
+ resolve();
155
+ }
156
+ else {
157
+ if (Trace.isEnabled()) {
158
+ CLog(CLogTypes.error, error);
159
+ }
160
+ reject(error);
161
+ }
162
+ }
163
+ }));
164
+ });
153
165
  }
154
166
  prefetchToDiskCache(uri) {
155
167
  return this.prefetchToCache(uri, true);
156
168
  }
157
169
  prefetchToMemoryCache(uri) {
158
- return this.prefetchToCache(uri, false);
170
+ return new Promise((resolve, reject) => {
171
+ try {
172
+ const context = Utils.android.getApplicationContext();
173
+ const requestManager = com.bumptech.glide.Glide.with(context);
174
+ // Preload into memory cache
175
+ requestManager.asBitmap().load(uri).preload();
176
+ // Give Glide time to load into memory
177
+ setTimeout(() => resolve(), 100);
178
+ }
179
+ catch (error) {
180
+ reject(error);
181
+ }
182
+ });
159
183
  }
160
184
  prefetchToCache(uri, toDiskCache) {
161
185
  return new Promise((resolve, reject) => {
162
186
  try {
163
- const nativeUri = android.net.Uri.parse(uri);
164
- const request = com.facebook.imagepipeline.request.ImageRequestBuilder.newBuilderWithSource(nativeUri).build();
165
- let datasource;
187
+ const context = Utils.android.getApplicationContext();
188
+ const requestManager = com.bumptech.glide.Glide.with(context);
166
189
  if (toDiskCache) {
167
- datasource = this._android.prefetchToDiskCache(request, uri);
190
+ requestManager.downloadOnly().load(uri).submit();
168
191
  }
169
192
  else {
170
- datasource = this._android.prefetchToBitmapCache(request, uri);
193
+ requestManager.asBitmap().load(uri).submit();
171
194
  }
172
- // initializeBaseDataSubscriber();
173
- datasource.subscribe(new com.nativescript.image.BaseDataSubscriber(new com.nativescript.image.BaseDataSubscriberListener({
174
- onFailure: reject,
175
- onNewResult: resolve
176
- })), com.facebook.common.executors.CallerThreadExecutor.getInstance());
195
+ resolve();
177
196
  }
178
197
  catch (error) {
179
198
  reject(error);
@@ -181,49 +200,55 @@ export class ImagePipeline {
181
200
  });
182
201
  }
183
202
  get android() {
184
- return this._android;
185
- }
186
- set android(value) {
187
- this._android = value;
188
- }
189
- fetchImage() {
190
- // ImagePipeline imagePipeline = Fresco.getImagePipeline();
191
- // ImageRequest imageRequest = ImageRequestBuilder
192
- // .newBuilderWithSource(imageUri)
193
- // .setRequestPriority(Priority.HIGH)
194
- // .setLowestPermittedRequestLevel(ImageRequest.RequestLevel.FULL_FETCH)
195
- // .build();
196
- // DataSource<CloseableReference<CloseableImage>> dataSource =
197
- // imagePipeline.fetchDecodedImage(imageRequest, mContext);
198
- // try {
199
- // dataSource.subscribe(new BaseBitmapDataSubscriber() {
200
- // @Override
201
- // public void onNewResultImpl(Bitmap bitmap) {
202
- // if (bitmap == null) {
203
- // Log.d(TAG, "Bitmap data source returned success, but bitmap null.");
204
- // return;
205
- // }
206
- // // The bitmap provided to this method is only guaranteed to be around
207
- // // for the lifespan of this method. The image pipeline frees the
208
- // // bitmap's memory after this method has completed.
209
- // //
210
- // // This is fine when passing the bitmap to a system process as
211
- // // Android automatically creates a copy.
212
- // //
213
- // // If you need to keep the bitmap around, look into using a
214
- // // BaseDataSubscriber instead of a BaseBitmapDataSubscriber.
215
- // }
216
- // @Override
217
- // public void onFailureImpl(DataSource dataSource) {
218
- // // No cleanup required here
219
- // }
220
- // }, CallerThreadExecutor.getInstance());
221
- // } finally {
222
- // if (dataSource != null) {
223
- // dataSource.close();
224
- // }
225
- // }
203
+ return glideInstance;
204
+ }
205
+ }
206
+ let imagePipeLine;
207
+ export function getImagePipeline() {
208
+ if (!imagePipeLine) {
209
+ imagePipeLine = new ImagePipeline();
210
+ }
211
+ return imagePipeLine;
212
+ }
213
+ export function shutDown() {
214
+ if (!initialized) {
215
+ return;
216
+ }
217
+ initialized = false;
218
+ // Glide cleanup
219
+ const context = Utils.android.getApplicationContext();
220
+ if (context) {
221
+ com.bumptech.glide.Glide.get(context).clearMemory();
222
+ }
223
+ }
224
+ function getUri(src, asNative = true) {
225
+ let uri;
226
+ let imagePath;
227
+ if (src instanceof ImageAsset) {
228
+ imagePath = src.android;
229
+ }
230
+ else {
231
+ imagePath = src;
232
+ }
233
+ if (Utils.isFileOrResourcePath(imagePath)) {
234
+ if (imagePath.indexOf(Utils.RESOURCE_PREFIX) === 0) {
235
+ const resName = imagePath.substring(Utils.RESOURCE_PREFIX.length);
236
+ const identifier = Utils.android.resources.getDrawableId(resName);
237
+ if (0 < identifier) {
238
+ return `android.resource://${Utils.android.getApplicationContext().getPackageName()}/${identifier}`;
239
+ }
240
+ }
241
+ else if (imagePath.indexOf('~/') === 0) {
242
+ uri = `file://${path.join(knownFolders.currentApp().path, imagePath.replace('~/', ''))}`;
243
+ }
244
+ else if (imagePath.indexOf('/') === 0) {
245
+ uri = `file://${imagePath}`;
246
+ }
226
247
  }
248
+ else {
249
+ uri = imagePath;
250
+ }
251
+ return uri;
227
252
  }
228
253
  export class ImageError {
229
254
  constructor(throwable) {
@@ -242,42 +267,22 @@ export class ImageError {
242
267
  }
243
268
  }
244
269
  export class ImageInfo {
245
- constructor(imageInfo) {
246
- this._nativeImageInfo = imageInfo;
270
+ constructor(width, height) {
271
+ this._width = width;
272
+ this._height = height;
247
273
  }
248
274
  getHeight() {
249
- return this._nativeImageInfo.getHeight();
275
+ return this._height;
250
276
  }
251
277
  getWidth() {
252
- return this._nativeImageInfo.getWidth();
278
+ return this._width;
253
279
  }
254
280
  getQualityInfo() {
255
- return this._nativeImageInfo.getQualityInfo();
256
- }
257
- }
258
- export class FinalEventData extends EventData {
259
- get imageInfo() {
260
- return this._imageInfo;
261
- }
262
- set imageInfo(value) {
263
- this._imageInfo = value;
264
- }
265
- get animatable() {
266
- return this._animatable;
267
- }
268
- set animatable(value) {
269
- this._animatable = value;
270
- }
271
- get android() {
272
- return this._animatable;
273
- }
274
- }
275
- export class IntermediateEventData extends EventData {
276
- get imageInfo() {
277
- return this._imageInfo;
278
- }
279
- set imageInfo(value) {
280
- this._imageInfo = value;
281
+ return {
282
+ getQuality: () => 1,
283
+ isOfFullQuality: () => true,
284
+ isOfGoodEnoughQuality: () => true
285
+ };
281
286
  }
282
287
  }
283
288
  export const needUpdateHierarchy = function (targetOrNeedsLayout, propertyKey, descriptor) {
@@ -313,13 +318,15 @@ export const needUpdateHierarchy = function (targetOrNeedsLayout, propertyKey, d
313
318
  export class Img extends ImageBase {
314
319
  constructor() {
315
320
  super(...arguments);
316
- this.isLoading = false;
317
321
  this.mCanUpdateHierarchy = true;
318
322
  this.mNeedUpdateHierarchy = false;
319
323
  this.mNeedUpdateLayout = false;
324
+ this.currentTarget = null;
325
+ this.isNetworkRequest = false;
326
+ this.progressCallback = null;
327
+ this.loadSourceCallback = null;
320
328
  }
321
329
  onResumeNativeUpdates() {
322
- // {N} suspends properties update on `_suspendNativeUpdates`. So we only need to do this in onResumeNativeUpdates
323
330
  this.mCanUpdateHierarchy = false;
324
331
  super.onResumeNativeUpdates();
325
332
  this.mCanUpdateHierarchy = true;
@@ -334,40 +341,13 @@ export class Img extends ImageBase {
334
341
  }
335
342
  createNativeView() {
336
343
  if (!initialized) {
337
- initialize(initializeConfig);
344
+ initialize();
338
345
  }
339
- const view = new com.nativescript.image.DraweeView(this._context);
340
- // (view as any).setClipToBounds(false);
341
- return view;
346
+ return new com.nativescript.image.MatrixImageView(this._context);
342
347
  }
343
- updateViewSize(imageInfo) {
344
- const draweeView = this.nativeImageViewProtected;
345
- if (!draweeView) {
346
- return;
347
- }
348
- if (imageInfo != null) {
349
- draweeView.imageWidth = imageInfo.getWidth();
350
- draweeView.imageHeight = imageInfo.getHeight();
351
- }
352
- if (!this.aspectRatio && imageInfo != null) {
353
- const ratio = imageInfo.getWidth() / imageInfo.getHeight();
354
- draweeView.setAspectRatio(ratio);
355
- }
356
- else if (this.aspectRatio) {
357
- draweeView.setAspectRatio(this.aspectRatio);
358
- }
359
- else {
360
- draweeView.setAspectRatio(0);
361
- }
362
- }
363
- // public initNativeView(): void {
364
- // this.initDrawee();
365
- // this.updateHierarchy();
366
- // }
367
348
  disposeNativeView() {
368
- this.controllerListener = null;
369
- this.requestListener = null;
370
- // this.nativeImageViewProtected.setImageURI(null, null);
349
+ this.progressCallback = null;
350
+ this.loadSourceCallback = null;
371
351
  }
372
352
  get cacheKey() {
373
353
  const src = this.src;
@@ -381,10 +361,7 @@ export class Img extends ImageBase {
381
361
  const imagePipeLine = getImagePipeline();
382
362
  const cacheKey = this.cacheKey;
383
363
  if (cacheKey) {
384
- // const isInCache = imagePipeLine.isInBitmapMemoryCache(uri);
385
- // // if (isInCache) {
386
364
  await imagePipeLine.evictFromCache(cacheKey);
387
- // }
388
365
  }
389
366
  this.handleImageSrc(null);
390
367
  this.initImage();
@@ -395,438 +372,468 @@ export class Img extends ImageBase {
395
372
  [_b = failureImageUriProperty.setNative]() {
396
373
  this.updateHierarchy();
397
374
  }
398
- [_c = stretchProperty.setNative]() {
399
- this.updateHierarchy();
375
+ [stretchProperty.setNative]() {
376
+ // Scale type
377
+ if (this.stretch) {
378
+ const scaleType = getScaleType(this.stretch);
379
+ if (scaleType) {
380
+ this.nativeViewProtected.setScaleType(scaleType);
381
+ }
382
+ }
400
383
  }
401
- [_d = fadeDurationProperty.setNative]() {
384
+ [_c = fadeDurationProperty.setNative]() {
402
385
  this.updateHierarchy();
403
386
  }
404
- [_e = backgroundUriProperty.setNative]() {
387
+ [_d = backgroundUriProperty.setNative]() {
405
388
  this.updateHierarchy();
406
389
  }
407
- [_f = showProgressBarProperty.setNative]() {
390
+ [_e = roundAsCircleProperty.setNative](value) {
408
391
  this.updateHierarchy();
409
392
  }
410
- [_g = progressBarColorProperty.setNative]() {
393
+ [_f = roundTopLeftRadiusProperty.setNative]() {
411
394
  this.updateHierarchy();
412
395
  }
413
- [_h = roundAsCircleProperty.setNative]() {
414
- this.updateHierarchy();
396
+ [imageRotationProperty.setNative](value) {
397
+ this.nativeImageViewProtected?.setImageRotation(value);
415
398
  }
416
- [_j = roundTopLeftRadiusProperty.setNative]() {
399
+ [_g = roundTopRightRadiusProperty.setNative]() {
417
400
  this.updateHierarchy();
418
401
  }
419
- [_k = imageRotationProperty.setNative](value) {
420
- const scaleType = this.nativeImageViewProtected.getHierarchy().getActualImageScaleType();
421
- scaleType['setImageRotation']?.(value);
422
- this.nativeImageViewProtected.invalidate();
423
- }
424
- [_l = roundTopRightRadiusProperty.setNative]() {
402
+ [_h = roundBottomLeftRadiusProperty.setNative]() {
425
403
  this.updateHierarchy();
426
404
  }
427
- [_m = roundBottomLeftRadiusProperty.setNative]() {
405
+ [_j = roundBottomRightRadiusProperty.setNative]() {
428
406
  this.updateHierarchy();
429
407
  }
430
- [_o = roundBottomRightRadiusProperty.setNative]() {
431
- this.updateHierarchy();
408
+ [tintColorProperty.setNative](value) {
409
+ if (this.nativeImageViewProtected) {
410
+ this.nativeImageViewProtected.setColorFilter(value?.android ?? -1, android.graphics.PorterDuff.Mode.MULTIPLY);
411
+ }
432
412
  }
433
- [_p = tintColorProperty.setNative](value) {
434
- this.updateHierarchy();
413
+ [_k = blurRadiusProperty.setNative](value) {
414
+ this.initImage();
435
415
  }
436
- [_q = blurRadiusProperty.setNative]() {
416
+ [_l = srcProperty.setNative]() {
437
417
  this.initImage();
438
418
  }
439
- [_r = srcProperty.setNative]() {
419
+ [_m = decodeWidthProperty.setNative]() {
440
420
  this.initImage();
441
421
  }
442
- [_s = lowerResSrcProperty.setNative]() {
422
+ [_o = decodeHeightProperty.setNative]() {
443
423
  this.initImage();
444
424
  }
445
- [_t = blurDownSamplingProperty.setNative]() {
425
+ [_p = lowerResSrcProperty.setNative]() {
446
426
  this.initImage();
447
427
  }
448
- [_u = aspectRatioProperty.setNative]() {
428
+ [_q = blurDownSamplingProperty.setNative]() {
449
429
  this.initImage();
450
430
  }
451
- [_v = headersProperty.setNative](value) {
431
+ [_r = aspectRatioProperty.setNative](value) {
432
+ if (this.nativeViewProtected) {
433
+ this.nativeViewProtected.setAspectRatio(value || 0);
434
+ }
435
+ }
436
+ [_s = headersProperty.setNative](value) {
452
437
  this.initImage();
453
438
  }
454
439
  [backgroundInternalProperty.setNative](value) {
455
440
  super[backgroundInternalProperty.setNative](value);
456
- this.nativeViewProtected.setClipToOutline(value?.hasBorderRadius());
441
+ if (this.nativeViewProtected) {
442
+ this.nativeViewProtected.setClipToOutline(value?.hasBorderRadius());
443
+ }
457
444
  }
458
445
  [noRatioEnforceProperty.setNative](value) {
459
- this.nativeViewProtected.noRatioEnforce = value;
446
+ if (this.nativeViewProtected) {
447
+ this.nativeViewProtected.setNoRatioEnforce(value);
448
+ }
460
449
  }
461
- async handleImageSrc(src) {
450
+ loadImageWithGlide(uri) {
462
451
  const view = this.nativeViewProtected;
463
- if (view) {
464
- if (src instanceof Promise) {
465
- this.handleImageSrc(await src);
466
- return;
467
- }
468
- else if (typeof src === 'function') {
469
- const newSrc = src();
470
- if (newSrc instanceof Promise) {
471
- await newSrc;
472
- }
473
- this.handleImageSrc(newSrc);
474
- return;
475
- }
476
- if (src) {
477
- let drawable;
478
- if (typeof src === 'string') {
479
- // disabled for now: loading vector drawables
480
- // if (src.indexOf(Utils.RESOURCE_PREFIX) === 0) {
481
- // const identifier = Utils.android.resources.getDrawableId(src.substring(Utils.RESOURCE_PREFIX.length));
482
- // if (identifier >= 0 && isVectorDrawable(this._context, identifier)) {
483
- // drawable = getBitmapFromVectorDrawable(this._context, identifier);
484
- // }
485
- // } else
486
- if (Utils.isFontIconURI(src)) {
487
- const fontIconCode = src.split('//')[1];
488
- if (fontIconCode !== undefined) {
489
- // support sync mode only
490
- const font = this.style.fontInternal;
491
- const color = this.style.color;
492
- drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android);
493
- }
452
+ const context = this._context;
453
+ // Determine if this is a network request
454
+ this.isNetworkRequest = typeof uri === 'string' && (uri.startsWith('http://') || uri.startsWith('https://'));
455
+ let requestBuilder;
456
+ let loadModel = uri;
457
+ // Create callbacks separately based on what's needed
458
+ const needsProgress = this.isNetworkRequest && this.hasListeners(ImageBase.progressEvent);
459
+ const needsLoadSource = this.isNetworkRequest && this.hasListeners('loadSource');
460
+ // Create progress callback if needed (only for network requests with listener)
461
+ if (needsProgress) {
462
+ const owner = new WeakRef(this);
463
+ this.progressCallback = new com.nativescript.image.ImageProgressCallback({
464
+ onProgress(url, bytesRead, totalBytes) {
465
+ const instance = owner.get();
466
+ if (instance) {
467
+ const progress = totalBytes > 0 ? bytesRead / totalBytes : 0;
468
+ instance.notifyProgress({
469
+ loaded: bytesRead,
470
+ total: totalBytes,
471
+ progress,
472
+ finished: bytesRead >= totalBytes
473
+ });
494
474
  }
495
475
  }
496
- else if (src instanceof ImageSource) {
497
- drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), src.android);
498
- this.updateViewSize(src.android);
499
- }
500
- if (drawable) {
501
- const hierarchy = this.nativeImageViewProtected.getHierarchy();
502
- hierarchy.setImage(drawable, 1, hierarchy.getFadeDuration() === 0);
503
- return;
504
- }
505
- const uri = getUri(src);
506
- if (!uri) {
507
- console.error(`Error: 'src' not valid: ${src}`);
508
- return;
476
+ });
477
+ }
478
+ // Create load source callback if needed (separate from progress)
479
+ if (needsLoadSource) {
480
+ const owner = new WeakRef(this);
481
+ this.loadSourceCallback = new com.nativescript.image.ImageLoadSourceCallback({
482
+ onLoadStarted(url, source) {
483
+ const instance = owner.get();
484
+ if (instance) {
485
+ instance.notifyLoadSource(source);
486
+ }
509
487
  }
510
- if (this.noCache) {
511
- // testing if is in cache is slow so lets remove without testing
512
- // const imagePipeLine = getImagePipeline();
513
- // const isInCache = imagePipeLine.isInBitmapMemoryCache(uri) || imagePipeLine.isInDiskCache(uri);
514
- // if (isInCache) {
515
- getImagePipeline().evictFromCache(uri);
516
- // }
488
+ });
489
+ }
490
+ // Use CustomGlideUrl if we need headers, progress, or load source
491
+ if (this.isNetworkRequest && (this.headers || this.progressCallback || this.loadSourceCallback)) {
492
+ const headersMap = new java.util.HashMap();
493
+ if (this.headers) {
494
+ for (const key in this.headers) {
495
+ headersMap.put(key, this.headers[key]);
517
496
  }
518
- this.isLoading = true;
519
- if (!this.controllerListener) {
520
- const that = new WeakRef(this);
521
- this.controllerListener = new com.facebook.drawee.controller.ControllerListener({
522
- onFinalImageSet(id, imageInfo, animatable) {
523
- if (Trace.isEnabled()) {
524
- CLog(CLogTypes.info, 'onFinalImageSet', id, imageInfo, animatable);
525
- }
526
- const owner = that?.get();
527
- if (owner) {
528
- owner.updateViewSize(imageInfo);
529
- owner.isLoading = false;
530
- const eventName = ImageBase.finalImageSetEvent;
531
- if (owner.hasListeners(eventName)) {
532
- const info = new ImageInfo(imageInfo);
533
- owner.notify({
534
- eventName,
535
- imageInfo: info,
536
- animatable: animatable
537
- });
538
- }
539
- }
540
- },
541
- onFailure(id, throwable) {
542
- if (Trace.isEnabled()) {
543
- CLog(CLogTypes.info, 'onFailure', id, throwable.getLocalizedMessage());
544
- }
545
- const owner = that?.get();
546
- if (owner) {
547
- // const nView = nativeView.nativeViewProtected;
548
- owner.isLoading = false;
549
- const eventName = ImageBase.failureEvent;
550
- if (owner.hasListeners(eventName)) {
551
- const imageError = new ImageError(throwable);
552
- owner.notify({
553
- eventName,
554
- error: wrapNativeException(throwable)
555
- });
556
- }
557
- }
558
- },
559
- onIntermediateImageFailed(id, throwable) {
560
- if (Trace.isEnabled()) {
561
- CLog(CLogTypes.info, 'onIntermediateImageFailed', id, throwable);
562
- }
563
- const owner = that?.get();
564
- if (owner) {
565
- const eventName = ImageBase.intermediateImageFailedEvent;
566
- if (owner.hasListeners(eventName)) {
567
- owner.notify({
568
- eventName,
569
- error: wrapNativeException(throwable)
570
- });
571
- }
572
- }
573
- },
574
- onIntermediateImageSet(id, imageInfo) {
575
- if (Trace.isEnabled()) {
576
- CLog(CLogTypes.info, 'onIntermediateImageSet', id, imageInfo);
577
- }
578
- const owner = that?.get();
579
- if (owner) {
580
- owner.updateViewSize(imageInfo);
581
- const eventName = ImageBase.intermediateImageSetEvent;
582
- if (owner.hasListeners(eventName)) {
583
- const info = new ImageInfo(imageInfo);
584
- owner.notify({
585
- eventName,
586
- imageInfo: info
587
- });
588
- }
589
- }
590
- },
591
- onRelease(id) {
592
- if (Trace.isEnabled()) {
593
- CLog(CLogTypes.info, 'onRelease', id);
594
- }
595
- const owner = that?.get();
596
- if (owner) {
597
- const eventName = ImageBase.releaseEvent;
598
- if (owner.hasListeners(eventName)) {
599
- owner.notify({
600
- eventName
601
- });
602
- }
603
- }
604
- },
605
- onSubmit(id, callerContext) {
606
- if (Trace.isEnabled()) {
607
- CLog(CLogTypes.info, 'onSubmit', id, callerContext);
608
- }
609
- const owner = that?.get();
610
- const eventName = ImageBase.submitEvent;
611
- if (owner?.hasListeners(eventName)) {
612
- owner.notify({
613
- eventName
614
- });
615
- }
616
- }
617
- });
497
+ }
498
+ loadModel = new com.nativescript.image.CustomGlideUrl(uri, headersMap, this.progressCallback, // Can be null
499
+ this.loadSourceCallback // Can be null
500
+ );
501
+ }
502
+ requestBuilder = com.bumptech.glide.Glide.with(context).load(loadModel).signature(new com.bumptech.glide.signature.ObjectKey(Date().valueOf()));
503
+ // Apply transformations (blur, rounded corners, etc.)
504
+ const transformations = [];
505
+ if (this.blurRadius) {
506
+ transformations.push(new jp.wasabeef.glide.transformations.BlurTransformation(Math.round(this.blurRadius), this.blurDownSampling || 1));
507
+ }
508
+ if (this.roundAsCircle) {
509
+ transformations.push(new jp.wasabeef.glide.transformations.CropCircleTransformation());
510
+ }
511
+ else {
512
+ const topLeft = Utils.layout.toDevicePixels(this.roundTopLeftRadius || 0);
513
+ const topRight = Utils.layout.toDevicePixels(this.roundTopRightRadius || 0);
514
+ const bottomRight = Utils.layout.toDevicePixels(this.roundBottomRightRadius || 0);
515
+ const bottomLeft = Utils.layout.toDevicePixels(this.roundBottomLeftRadius || 0);
516
+ if (topLeft || topRight || bottomRight || bottomLeft) {
517
+ const radius = Math.max(topLeft, topRight, bottomRight, bottomLeft);
518
+ transformations.push(new jp.wasabeef.glide.transformations.RoundedCornersTransformation(Math.round(radius), 0, jp.wasabeef.glide.transformations.RoundedCornersTransformation.CornerType.ALL));
519
+ }
520
+ }
521
+ // Tint color
522
+ if (this.tintColor) {
523
+ transformations.push(new jp.wasabeef.glide.transformations.ColorFilterTransformation(this.tintColor.android));
524
+ }
525
+ let multiTransform;
526
+ if (transformations.length > 0) {
527
+ multiTransform = new com.bumptech.glide.load.MultiTransformation(java.util.Arrays.asList(transformations));
528
+ requestBuilder = requestBuilder.transform(multiTransform);
529
+ }
530
+ // Placeholder
531
+ if (this.placeholderImageUri) {
532
+ const placeholder = this.getDrawable(this.placeholderImageUri);
533
+ if (placeholder) {
534
+ requestBuilder = requestBuilder.placeholder(placeholder);
535
+ }
536
+ }
537
+ // Error image
538
+ if (this.failureImageUri) {
539
+ const error = this.getDrawable(this.failureImageUri);
540
+ if (error) {
541
+ requestBuilder = requestBuilder.error(error);
542
+ }
543
+ }
544
+ // Thumbnail
545
+ if (this.lowerResSrc) {
546
+ const lowerResUri = getUri(this.lowerResSrc);
547
+ if (lowerResUri) {
548
+ const thumbnailRequest = com.bumptech.glide.Glide.with(context).load(lowerResUri);
549
+ requestBuilder = requestBuilder.thumbnail(thumbnailRequest);
550
+ }
551
+ }
552
+ // Fade duration + conditional crossfade
553
+ if (this.fadeDuration > 0) {
554
+ const factory = new com.nativescript.image.ConditionalCrossFadeFactory(this.fadeDuration, !this.alwaysFade);
555
+ requestBuilder = requestBuilder.transition(com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade(factory));
556
+ }
557
+ // Cache settings
558
+ if (this.noCache) {
559
+ requestBuilder = requestBuilder.skipMemoryCache(true).diskCacheStrategy(com.bumptech.glide.load.engine.DiskCacheStrategy.NONE);
560
+ }
561
+ // Decode size
562
+ if (this.decodeWidth || this.decodeHeight) {
563
+ const Target = com.bumptech.glide.request.target.Target;
564
+ const width = this.decodeWidth || Target.SIZE_ORIGINAL;
565
+ const height = this.decodeHeight || Target.SIZE_ORIGINAL;
566
+ if (width === Target.SIZE_ORIGINAL) {
567
+ requestBuilder = requestBuilder.override(height);
568
+ }
569
+ else if (height === Target.SIZE_ORIGINAL) {
570
+ requestBuilder = requestBuilder.override(width);
571
+ }
572
+ else {
573
+ requestBuilder = requestBuilder.override(width, height);
574
+ }
575
+ }
576
+ const owner = new WeakRef(this);
577
+ const sourceKey = new com.bumptech.glide.signature.ObjectKey(uri);
578
+ const objectArr = Array.create(com.bumptech.glide.request.RequestListener, 2);
579
+ const ro = new com.bumptech.glide.request.RequestOptions().signature(signature);
580
+ objectArr[0] = new com.nativescript.image.SaveKeysRequestListener(uri, uri, sourceKey, signature, this.decodeWidth || com.bumptech.glide.request.target.Target.SIZE_ORIGINAL, this.decodeHeight || com.bumptech.glide.request.target.Target.SIZE_ORIGINAL, multiTransform, ro, null);
581
+ objectArr[1] = new com.bumptech.glide.request.RequestListener({
582
+ onLoadFailed(e, model, target, isFirstResource) {
583
+ const instance = owner.get();
584
+ if (instance) {
585
+ instance.progressCallback = null; // Clean up
586
+ instance.loadSourceCallback = null;
587
+ instance.notifyFailure(e);
618
588
  }
619
- if (!this.requestListener && this.hasListeners(ImageBase.fetchingFromEvent)) {
620
- const that = new WeakRef(this);
621
- this.requestListener = new com.facebook.imagepipeline.listener.RequestListener({
622
- onRequestStart(request, callerContext, requestId, isPrefetch) {
623
- },
624
- onRequestSuccess(param0, param1, param2) { },
625
- onRequestFailure(param0, param1, param2, param3) { },
626
- onRequestCancellation(param0) { },
627
- onProducerStart(param0, param1) { },
628
- onProducerEvent(param0, param1, param2) { },
629
- onProducerFinishWithSuccess(requestId, producerName, extraMap) {
630
- console.log('onProducerFinishWithSuccess', producerName);
631
- const owner = that?.get();
632
- const eventName = ImageBase.fetchingFromEvent;
633
- if (owner?.hasListeners(eventName)) {
634
- let source = 'local';
635
- if (producerName.indexOf('Network') !== -1) {
589
+ return false;
590
+ },
591
+ onResourceReady(resource, model, target, dataSource, isFirstResource) {
592
+ const instance = owner.get();
593
+ if (instance) {
594
+ instance.progressCallback = null; // Clean up
595
+ instance.loadSourceCallback = null;
596
+ instance.notifyFinalImageSet(resource, dataSource);
597
+ // Handle auto-play for animated drawables
598
+ if (!instance.autoPlayAnimations && resource instanceof android.graphics.drawable.Animatable) {
599
+ setTimeout(() => {
600
+ resource.stop();
601
+ }, 0);
602
+ }
603
+ // Notify load source for cache hits (network notified by interceptor)
604
+ let source = 'local';
605
+ if (dataSource) {
606
+ try {
607
+ const sourceName = dataSource.name ? dataSource.name() : String(dataSource);
608
+ switch ((sourceName || '').toUpperCase()) {
609
+ case 'MEMORY_CACHE':
610
+ source = 'memory';
611
+ break;
612
+ case 'DATA_DISK_CACHE':
613
+ case 'RESOURCE_DISK_CACHE':
614
+ source = 'disk';
615
+ break;
616
+ case 'REMOTE':
636
617
  source = 'network';
637
- }
638
- else if (producerName.indexOf('Cache') !== -1) {
639
- source = 'cache';
640
- }
641
- owner.notify({
642
- eventName,
643
- source
644
- });
618
+ break;
619
+ case 'LOCAL':
620
+ source = 'local';
621
+ break;
645
622
  }
646
- },
647
- onProducerFinishWithFailure(param0, param1, param2, param3) { },
648
- onProducerFinishWithCancellation(param0, param1, param2) { },
649
- onUltimateProducerReached(param0, param1, param2) { },
650
- requiresExtraMap(param0) { return false; },
651
- });
623
+ }
624
+ catch (err) {
625
+ source = 'unknown';
626
+ }
627
+ }
628
+ // Only notify if not network (network already notified by interceptor)
629
+ if (source !== 'network' && instance.hasListeners('loadSource')) {
630
+ instance.notifyLoadSource(source);
631
+ }
652
632
  }
653
- const options = JSON.stringify({
654
- progressiveRenderingEnabled: this.blurRadius,
655
- localThumbnailPreviewsEnabled: this.blurRadius,
656
- decodeWidth: this.decodeWidth,
657
- decodeHeight: this.decodeHeight,
658
- blurRadius: this.blurRadius,
659
- lowerResSrc: this.lowerResSrc ? getUri(this.lowerResSrc, false) : undefined,
660
- blurDownSampling: this.blurDownSampling,
661
- autoPlayAnimations: this.autoPlayAnimations,
662
- tapToRetryEnabled: this.tapToRetryEnabled,
663
- headers: this.headers
664
- });
665
- view.setUri(uri, options, this.controllerListener, this.requestListener);
666
- // const async = this.loadMode === 'async';
667
- // if (async) {
668
- // const builder = com.facebook.drawee.backends.pipeline.Fresco.newDraweeControllerBuilder();
669
- // builder.setImageRequest(request);
670
- // builder.setCallerContext(src);
671
- // builder.setControllerListener(listener);
672
- // builder.setOldController(this.nativeImageViewProtected.getController());
673
- // if (Trace.isEnabled()) {
674
- // builder.setPerfDataListener(
675
- // new com.facebook.drawee.backends.pipeline.info.ImagePerfDataListener({
676
- // onImageLoadStatusUpdated(param0: com.facebook.drawee.backends.pipeline.info.ImagePerfData, param1: number) {
677
- // CLog(CLogTypes.info, 'onImageLoadStatusUpdated', param0, param1);
678
- // },
679
- // onImageVisibilityUpdated(param0: com.facebook.drawee.backends.pipeline.info.ImagePerfData, param1: number) {
680
- // CLog(CLogTypes.info, 'onImageVisibilityUpdated', param0, param1);
681
- // }
682
- // })
683
- // );
684
- // }
685
- // if (this.lowerResSrc) {
686
- // builder.setLowResImageRequest(com.facebook.imagepipeline.request.ImageRequest.fromUri(getUri(this.lowerResSrc)));
687
- // }
688
- // if (this.autoPlayAnimations) {
689
- // builder.setAutoPlayAnimations(this.autoPlayAnimations);
690
- // }
691
- // if (this.tapToRetryEnabled) {
692
- // builder.setTapToRetryEnabled(this.tapToRetryEnabled);
693
- // }
694
- // const controller = builder.build();
695
- // this.nativeImageViewProtected.setController(controller);
696
- // } else {
697
- // const dataSource = com.facebook.drawee.backends.pipeline.Fresco.getImagePipeline().fetchDecodedImage(request, src);
698
- // const result = com.facebook.datasource.DataSources.waitForFinalResult(dataSource);
699
- // const bitmap = result.get().underlyingBitmap;
700
- // CloseableReference.closeSafely(result);
701
- // dataSource.close();
702
- // }
633
+ return false;
703
634
  }
704
- else {
705
- this.nativeImageViewProtected.setController(null);
706
- this.nativeImageViewProtected.setImageBitmap(null);
635
+ });
636
+ this.currentTarget = new com.nativescript.image.MatrixDrawableImageViewTarget(view);
637
+ requestBuilder.signature(signature).listener(new com.nativescript.image.CompositeRequestListener(objectArr)).into(this.currentTarget);
638
+ }
639
+ notifyLoadSource(source) {
640
+ const eventName = ImageBase.loadSourceEvent;
641
+ if (this.hasListeners(eventName)) {
642
+ this.notify({
643
+ eventName,
644
+ source // 'network', 'memory', 'disk', 'local'
645
+ });
646
+ }
647
+ }
648
+ notifyProgress(payload) {
649
+ const eventName = ImageBase.progressEvent;
650
+ if (this.hasListeners(eventName)) {
651
+ this.notify({
652
+ eventName,
653
+ current: payload.loaded,
654
+ total: payload.total,
655
+ progress: payload.progress,
656
+ finished: payload.finished
657
+ });
658
+ }
659
+ }
660
+ notifyFinalImageSet(drawable, dataSource) {
661
+ let sourceLabel = 'local';
662
+ if (dataSource) {
663
+ try {
664
+ sourceLabel = dataSource.name ? dataSource.name() : String(dataSource);
665
+ }
666
+ catch (err) {
667
+ sourceLabel = String(dataSource);
707
668
  }
669
+ switch ((sourceLabel || '').toUpperCase()) {
670
+ case 'MEMORY_CACHE':
671
+ sourceLabel = 'memory';
672
+ break;
673
+ case 'DATA_DISK_CACHE':
674
+ case 'RESOURCE_DISK_CACHE':
675
+ sourceLabel = 'disk';
676
+ break;
677
+ case 'REMOTE':
678
+ sourceLabel = 'network';
679
+ break;
680
+ case 'LOCAL':
681
+ sourceLabel = 'local';
682
+ break;
683
+ default:
684
+ break;
685
+ }
686
+ }
687
+ const eventName = ImageBase.finalImageSetEvent;
688
+ if (this.hasListeners(eventName)) {
689
+ const width = drawable ? drawable.getIntrinsicWidth() : 0;
690
+ const height = drawable ? drawable.getIntrinsicHeight() : 0;
691
+ const info = new ImageInfo(width, height);
692
+ this.notify({
693
+ eventName,
694
+ imageInfo: info,
695
+ animatable: this.getAnimatable(drawable),
696
+ android: drawable,
697
+ source: sourceLabel
698
+ });
708
699
  }
709
700
  }
710
- async initImage() {
711
- // this.nativeImageViewProtected.setImageURI(null);
712
- this.handleImageSrc(this.src);
701
+ notifyFailure(error) {
702
+ const eventName = ImageBase.failureEvent;
703
+ if (this.hasListeners(eventName)) {
704
+ this.notify({
705
+ eventName,
706
+ error: error instanceof java.lang.Throwable ? wrapNativeException(error) : error
707
+ });
708
+ }
713
709
  }
714
- updateHierarchy() {
715
- if (!this.mCanUpdateHierarchy) {
716
- this.mNeedUpdateHierarchy = true;
710
+ getAnimatable(drawable) {
711
+ if (drawable && drawable instanceof android.graphics.drawable.Animatable) {
712
+ return drawable;
713
+ }
714
+ return null;
715
+ }
716
+ async handleImageSrc(src) {
717
+ const view = this.nativeViewProtected;
718
+ if (!view) {
717
719
  return;
718
720
  }
719
- if (this.nativeImageViewProtected) {
720
- let failureImageDrawable;
721
- let placeholderImageDrawable;
722
- let backgroundDrawable;
723
- if (this.failureImageUri) {
724
- failureImageDrawable = this.getDrawable(this.failureImageUri);
725
- }
726
- if (this.placeholderImageUri) {
727
- placeholderImageDrawable = this.getDrawable(this.placeholderImageUri);
728
- }
729
- if (this.backgroundUri) {
730
- backgroundDrawable = this.getDrawable(this.backgroundUri);
731
- }
732
- const builder = new GenericDraweeHierarchyBuilder();
733
- if (this.failureImageUri && failureImageDrawable) {
734
- builder.setFailureImage(failureImageDrawable, this.stretch);
735
- }
736
- if (this.tintColor) {
737
- builder.setActualImageColorFilter(new android.graphics.PorterDuffColorFilter(this.tintColor.android, android.graphics.PorterDuff.Mode.MULTIPLY));
738
- }
739
- if (this.placeholderImageUri && placeholderImageDrawable) {
740
- builder.setPlaceholderImage(placeholderImageDrawable, this.stretch);
721
+ if (src instanceof Promise) {
722
+ this.handleImageSrc(await src);
723
+ return;
724
+ }
725
+ else if (typeof src === 'function') {
726
+ const newSrc = src();
727
+ if (newSrc instanceof Promise) {
728
+ await newSrc;
741
729
  }
742
- if (this.stretch) {
743
- builder.setActualImageScaleType(this.stretch, this.imageRotation);
730
+ this.handleImageSrc(newSrc);
731
+ return;
732
+ }
733
+ if (src) {
734
+ let drawable;
735
+ if (typeof src === 'string') {
736
+ if (Utils.isFontIconURI(src)) {
737
+ const fontIconCode = src.split('//')[1];
738
+ if (fontIconCode !== undefined) {
739
+ const font = this.style.fontInternal;
740
+ const color = this.style.color;
741
+ drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android);
742
+ }
743
+ }
744
744
  }
745
- builder.setFadeDuration(this.fadeDuration || 0);
746
- if (this.backgroundUri && backgroundDrawable) {
747
- builder.setBackground(backgroundDrawable);
745
+ else if (src instanceof ImageSource) {
746
+ drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), src.android);
748
747
  }
749
- if (this.showProgressBar) {
750
- builder.setProgressBarImage(this.progressBarColor?.hex, this.stretch);
748
+ if (drawable) {
749
+ view.setImageDrawable(drawable);
750
+ this.notifyFinalImageSet(drawable);
751
+ return;
751
752
  }
752
- if (this.roundAsCircle) {
753
- builder.setRoundingParamsAsCircle();
753
+ const uri = getUri(src);
754
+ if (!uri) {
755
+ console.error(`Error: 'src' not valid: ${src}`);
756
+ return;
754
757
  }
755
- const topLeftRadius = this.roundTopLeftRadius || 0;
756
- const topRightRadius = this.roundTopRightRadius || 0;
757
- const bottomRightRadius = this.roundBottomRightRadius || 0;
758
- const bottomLeftRadius = this.roundBottomLeftRadius || 0;
759
- if (topLeftRadius || topRightRadius || bottomRightRadius || bottomLeftRadius) {
760
- builder.setCornersRadii(Utils.layout.toDevicePixels(topLeftRadius), Utils.layout.toDevicePixels(topRightRadius), Utils.layout.toDevicePixels(bottomRightRadius), Utils.layout.toDevicePixels(bottomLeftRadius));
758
+ this.loadImageWithGlide(uri);
759
+ }
760
+ else {
761
+ // Clear existing request before removing the drawable
762
+ if (this.currentTarget) {
763
+ com.bumptech.glide.Glide.with(this._context).clear(this.currentTarget);
764
+ this.currentTarget = null;
761
765
  }
762
- this.nativeImageViewProtected.setHierarchy(builder.build());
763
- if (!this.mNeedRequestImage) {
764
- this.nativeImageViewProtected.setController(this.nativeImageViewProtected.getController());
766
+ else {
767
+ com.bumptech.glide.Glide.with(this._context).clear(view);
765
768
  }
769
+ view.setImageDrawable(null);
770
+ }
771
+ }
772
+ async initImage() {
773
+ try {
774
+ await this.handleImageSrc(this.src);
775
+ }
776
+ catch (error) {
777
+ console.error(error, error.stack);
778
+ }
779
+ }
780
+ updateHierarchy() {
781
+ if (!this.mCanUpdateHierarchy) {
782
+ this.mNeedUpdateHierarchy = true;
783
+ return;
784
+ }
785
+ // Force reload with new settings
786
+ if (this.nativeImageViewProtected && this.src) {
787
+ this.initImage();
766
788
  }
767
789
  }
768
790
  getDrawable(path) {
769
- let drawable;
770
791
  if (typeof path === 'string') {
771
792
  if (Utils.isFontIconURI(path)) {
772
793
  const fontIconCode = path.split('//')[1];
773
794
  if (fontIconCode !== undefined) {
774
- // support sync mode only
775
795
  const font = this.style.fontInternal;
776
796
  const color = this.style.color;
777
- drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android);
797
+ return new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), ImageSource.fromFontIconCodeSync(fontIconCode, font, color).android);
778
798
  }
779
799
  }
780
800
  else if (Utils.isFileOrResourcePath(path)) {
781
801
  if (path.indexOf(Utils.RESOURCE_PREFIX) === 0) {
782
- return this.getDrawableFromResource(path); // number!
802
+ return this.getDrawableFromResource(path);
783
803
  }
784
804
  else {
785
- drawable = this.getDrawableFromLocalFile(path);
805
+ return this.getDrawableFromLocalFile(path);
786
806
  }
787
807
  }
788
808
  }
789
- else {
790
- drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), path.android);
809
+ else if (path instanceof ImageSource) {
810
+ return new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), path.android);
791
811
  }
792
- return drawable;
812
+ return null;
793
813
  }
794
814
  getDrawableFromLocalFile(localFilePath) {
795
815
  const img = ImageSource.fromFileSync(localFilePath);
796
- let drawable = null;
797
816
  if (img) {
798
- drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), img.android);
817
+ return new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), img.android);
799
818
  }
800
- return drawable;
819
+ return null;
801
820
  }
802
821
  getDrawableFromResource(resourceName) {
803
822
  const application = Utils.android.getApplication();
804
823
  const resources = application.getResources();
805
824
  const identifier = resources.getIdentifier(resourceName.substring(Utils.RESOURCE_PREFIX.length), 'drawable', application.getPackageName());
806
- // we return the identifier to allow Fresco to handle memory / caching
807
825
  return identifier;
808
- // return Utils.android.getApplicationContext().getDrawable(identifier);
809
826
  }
810
827
  startAnimating() {
811
- if (this.nativeImageViewProtected) {
812
- const controller = this.nativeImageViewProtected.getController();
813
- if (controller) {
814
- const animatable = controller.getAnimatable();
815
- if (animatable) {
816
- animatable.start();
817
- }
818
- }
828
+ const drawable = this.nativeViewProtected.getDrawable();
829
+ if (drawable && drawable instanceof android.graphics.drawable.Animatable) {
830
+ drawable.start();
819
831
  }
820
832
  }
821
833
  stopAnimating() {
822
- if (this.nativeImageViewProtected) {
823
- const controller = this.nativeImageViewProtected.getController();
824
- if (controller) {
825
- const animatable = controller.getAnimatable();
826
- if (animatable) {
827
- animatable.stop();
828
- }
829
- }
834
+ const drawable = this.nativeViewProtected.getDrawable();
835
+ if (drawable && drawable instanceof android.graphics.drawable.Animatable) {
836
+ drawable.stop();
830
837
  }
831
838
  }
832
839
  }
@@ -858,19 +865,19 @@ __decorate([
858
865
  needUpdateHierarchy
859
866
  ], Img.prototype, _j, null);
860
867
  __decorate([
861
- needUpdateHierarchy(true)
868
+ needRequestImage
862
869
  ], Img.prototype, _k, null);
863
870
  __decorate([
864
- needUpdateHierarchy
871
+ needRequestImage
865
872
  ], Img.prototype, _l, null);
866
873
  __decorate([
867
- needUpdateHierarchy
874
+ needRequestImage
868
875
  ], Img.prototype, _m, null);
869
876
  __decorate([
870
- needUpdateHierarchy
877
+ needRequestImage
871
878
  ], Img.prototype, _o, null);
872
879
  __decorate([
873
- needUpdateHierarchy
880
+ needRequestImage
874
881
  ], Img.prototype, _p, null);
875
882
  __decorate([
876
883
  needRequestImage
@@ -881,145 +888,32 @@ __decorate([
881
888
  __decorate([
882
889
  needRequestImage
883
890
  ], Img.prototype, _s, null);
884
- __decorate([
885
- needRequestImage
886
- ], Img.prototype, _t, null);
887
- __decorate([
888
- needRequestImage
889
- ], Img.prototype, _u, null);
890
- __decorate([
891
- needRequestImage
892
- ], Img.prototype, _v, null);
893
- class GenericDraweeHierarchyBuilder {
894
- constructor() {
895
- const res = Utils.android.getApplicationContext().getResources();
896
- this.nativeBuilder = new com.facebook.drawee.generic.GenericDraweeHierarchyBuilder(res);
897
- }
898
- setPlaceholderImage(drawable, scaleType) {
899
- if (!this.nativeBuilder) {
900
- return this;
901
- }
902
- if (scaleType) {
903
- this.nativeBuilder.setPlaceholderImage(drawable, getScaleType(scaleType));
904
- }
905
- else {
906
- this.nativeBuilder.setPlaceholderImage(drawable);
907
- }
908
- return this;
909
- }
910
- setActualImageColorFilter(filter) {
911
- if (!this.nativeBuilder) {
912
- return this;
913
- }
914
- this.nativeBuilder.setActualImageColorFilter(filter);
915
- return this;
916
- }
917
- setFailureImage(drawable, scaleType) {
918
- if (!this.nativeBuilder) {
919
- return null;
920
- }
921
- if (scaleType) {
922
- this.nativeBuilder.setFailureImage(drawable, getScaleType(scaleType));
923
- }
924
- else {
925
- this.nativeBuilder.setFailureImage(drawable);
926
- }
927
- return this;
928
- }
929
- setActualImageScaleType(scaleType, imageRotation = 0) {
930
- if (!this.nativeBuilder) {
931
- return this;
932
- }
933
- const nativeScaleType = getScaleType(scaleType);
934
- if (imageRotation !== 0 && nativeScaleType['setImageRotation']) {
935
- nativeScaleType['setImageRotation'](imageRotation);
936
- }
937
- this.nativeBuilder.setActualImageScaleType(nativeScaleType);
938
- return this;
939
- }
940
- build() {
941
- if (!this.nativeBuilder) {
942
- return null;
943
- }
944
- return this.nativeBuilder.build();
945
- }
946
- setFadeDuration(duration) {
947
- if (!this.nativeBuilder) {
948
- return null;
949
- }
950
- this.nativeBuilder.setFadeDuration(duration);
951
- return this;
952
- }
953
- setBackground(drawable) {
954
- if (!this.nativeBuilder) {
955
- return this;
956
- }
957
- this.nativeBuilder.setBackground(drawable);
958
- return this;
959
- }
960
- setProgressBarImage(color, stretch) {
961
- if (!this.nativeBuilder) {
962
- return null;
963
- }
964
- const drawable = new com.facebook.drawee.drawable.ProgressBarDrawable();
965
- if (color) {
966
- drawable.setColor(android.graphics.Color.parseColor(color));
967
- }
968
- this.nativeBuilder.setProgressBarImage(drawable, getScaleType(stretch));
969
- return this;
970
- }
971
- setRoundingParamsAsCircle() {
972
- if (!this.nativeBuilder) {
973
- return this;
974
- }
975
- const params = com.facebook.drawee.generic.RoundingParams.asCircle();
976
- this.nativeBuilder.setRoundingParams(params);
977
- return this;
978
- }
979
- setCornersRadii(topLeft, topRight, bottomRight, bottomLeft) {
980
- if (!this.nativeBuilder) {
981
- return this;
982
- }
983
- const params = new com.facebook.drawee.generic.RoundingParams();
984
- params.setCornersRadii(topLeft, topRight, bottomRight, bottomLeft);
985
- this.nativeBuilder.setRoundingParams(params);
986
- return this;
987
- }
988
- }
989
891
  function getScaleType(scaleType) {
990
892
  if (isString(scaleType)) {
991
893
  switch (scaleType) {
992
894
  case ScaleType.Center:
993
- //@ts-ignore
994
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenter();
895
+ return android.widget.ImageView.ScaleType.CENTER;
995
896
  case ScaleType.AspectFill:
996
897
  case ScaleType.CenterCrop:
997
- //@ts-ignore
998
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenterCrop();
898
+ return android.widget.ImageView.ScaleType.CENTER_CROP;
999
899
  case ScaleType.CenterInside:
1000
- //@ts-ignore
1001
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenterInside();
900
+ return android.widget.ImageView.ScaleType.CENTER_INSIDE;
1002
901
  case ScaleType.FitCenter:
1003
902
  case ScaleType.AspectFit:
1004
- //@ts-ignore
1005
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitCenter();
903
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1006
904
  case ScaleType.FitEnd:
1007
- //@ts-ignore
1008
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitEnd();
905
+ return android.widget.ImageView.ScaleType.FIT_END;
1009
906
  case ScaleType.FitStart:
1010
- //@ts-ignore
1011
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitStart();
907
+ return android.widget.ImageView.ScaleType.FIT_START;
1012
908
  case ScaleType.Fill:
1013
909
  case ScaleType.FitXY:
1014
- //@ts-ignore
1015
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitXY();
910
+ return android.widget.ImageView.ScaleType.FIT_XY;
1016
911
  case ScaleType.FocusCrop:
1017
- //@ts-ignore
1018
- return new com.nativescript.image.ScalingUtils.ScaleTypeFocusCrop();
912
+ return android.widget.ImageView.ScaleType.CENTER_CROP;
1019
913
  default:
1020
- break;
914
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1021
915
  }
1022
916
  }
1023
- return null;
917
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1024
918
  }
1025
919
  //# sourceMappingURL=index.android.js.map