@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
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,437 +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
- const owner = that?.get();
631
- const eventName = ImageBase.fetchingFromEvent;
632
- if (owner?.hasListeners(eventName)) {
633
- let source = 'local';
634
- 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':
635
617
  source = 'network';
636
- }
637
- else if (producerName.indexOf('Cache') !== -1) {
638
- source = 'cache';
639
- }
640
- owner.notify({
641
- eventName,
642
- source
643
- });
618
+ break;
619
+ case 'LOCAL':
620
+ source = 'local';
621
+ break;
644
622
  }
645
- },
646
- onProducerFinishWithFailure(param0, param1, param2, param3) { },
647
- onProducerFinishWithCancellation(param0, param1, param2) { },
648
- onUltimateProducerReached(param0, param1, param2) { },
649
- requiresExtraMap(param0) { return false; },
650
- });
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
+ }
651
632
  }
652
- const options = JSON.stringify({
653
- progressiveRenderingEnabled: this.blurRadius,
654
- localThumbnailPreviewsEnabled: this.blurRadius,
655
- decodeWidth: this.decodeWidth,
656
- decodeHeight: this.decodeHeight,
657
- blurRadius: this.blurRadius,
658
- lowerResSrc: this.lowerResSrc ? getUri(this.lowerResSrc, false) : undefined,
659
- blurDownSampling: this.blurDownSampling,
660
- autoPlayAnimations: this.autoPlayAnimations,
661
- tapToRetryEnabled: this.tapToRetryEnabled,
662
- headers: this.headers
663
- });
664
- view.setUri(uri, options, this.controllerListener, this.requestListener);
665
- // const async = this.loadMode === 'async';
666
- // if (async) {
667
- // const builder = com.facebook.drawee.backends.pipeline.Fresco.newDraweeControllerBuilder();
668
- // builder.setImageRequest(request);
669
- // builder.setCallerContext(src);
670
- // builder.setControllerListener(listener);
671
- // builder.setOldController(this.nativeImageViewProtected.getController());
672
- // if (Trace.isEnabled()) {
673
- // builder.setPerfDataListener(
674
- // new com.facebook.drawee.backends.pipeline.info.ImagePerfDataListener({
675
- // onImageLoadStatusUpdated(param0: com.facebook.drawee.backends.pipeline.info.ImagePerfData, param1: number) {
676
- // CLog(CLogTypes.info, 'onImageLoadStatusUpdated', param0, param1);
677
- // },
678
- // onImageVisibilityUpdated(param0: com.facebook.drawee.backends.pipeline.info.ImagePerfData, param1: number) {
679
- // CLog(CLogTypes.info, 'onImageVisibilityUpdated', param0, param1);
680
- // }
681
- // })
682
- // );
683
- // }
684
- // if (this.lowerResSrc) {
685
- // builder.setLowResImageRequest(com.facebook.imagepipeline.request.ImageRequest.fromUri(getUri(this.lowerResSrc)));
686
- // }
687
- // if (this.autoPlayAnimations) {
688
- // builder.setAutoPlayAnimations(this.autoPlayAnimations);
689
- // }
690
- // if (this.tapToRetryEnabled) {
691
- // builder.setTapToRetryEnabled(this.tapToRetryEnabled);
692
- // }
693
- // const controller = builder.build();
694
- // this.nativeImageViewProtected.setController(controller);
695
- // } else {
696
- // const dataSource = com.facebook.drawee.backends.pipeline.Fresco.getImagePipeline().fetchDecodedImage(request, src);
697
- // const result = com.facebook.datasource.DataSources.waitForFinalResult(dataSource);
698
- // const bitmap = result.get().underlyingBitmap;
699
- // CloseableReference.closeSafely(result);
700
- // dataSource.close();
701
- // }
633
+ return false;
702
634
  }
703
- else {
704
- this.nativeImageViewProtected.setController(null);
705
- 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);
706
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
+ });
707
699
  }
708
700
  }
709
- async initImage() {
710
- // this.nativeImageViewProtected.setImageURI(null);
711
- 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
+ }
712
709
  }
713
- updateHierarchy() {
714
- if (!this.mCanUpdateHierarchy) {
715
- 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) {
716
719
  return;
717
720
  }
718
- if (this.nativeImageViewProtected) {
719
- let failureImageDrawable;
720
- let placeholderImageDrawable;
721
- let backgroundDrawable;
722
- if (this.failureImageUri) {
723
- failureImageDrawable = this.getDrawable(this.failureImageUri);
724
- }
725
- if (this.placeholderImageUri) {
726
- placeholderImageDrawable = this.getDrawable(this.placeholderImageUri);
727
- }
728
- if (this.backgroundUri) {
729
- backgroundDrawable = this.getDrawable(this.backgroundUri);
730
- }
731
- const builder = new GenericDraweeHierarchyBuilder();
732
- if (this.failureImageUri && failureImageDrawable) {
733
- builder.setFailureImage(failureImageDrawable, this.stretch);
734
- }
735
- if (this.tintColor) {
736
- builder.setActualImageColorFilter(new android.graphics.PorterDuffColorFilter(this.tintColor.android, android.graphics.PorterDuff.Mode.MULTIPLY));
737
- }
738
- if (this.placeholderImageUri && placeholderImageDrawable) {
739
- 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;
740
729
  }
741
- if (this.stretch) {
742
- 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
+ }
743
744
  }
744
- builder.setFadeDuration(this.fadeDuration || 0);
745
- if (this.backgroundUri && backgroundDrawable) {
746
- builder.setBackground(backgroundDrawable);
745
+ else if (src instanceof ImageSource) {
746
+ drawable = new android.graphics.drawable.BitmapDrawable(Utils.android.getApplicationContext().getResources(), src.android);
747
747
  }
748
- if (this.showProgressBar) {
749
- builder.setProgressBarImage(this.progressBarColor?.hex, this.stretch);
748
+ if (drawable) {
749
+ view.setImageDrawable(drawable);
750
+ this.notifyFinalImageSet(drawable);
751
+ return;
750
752
  }
751
- if (this.roundAsCircle) {
752
- builder.setRoundingParamsAsCircle();
753
+ const uri = getUri(src);
754
+ if (!uri) {
755
+ console.error(`Error: 'src' not valid: ${src}`);
756
+ return;
753
757
  }
754
- const topLeftRadius = this.roundTopLeftRadius || 0;
755
- const topRightRadius = this.roundTopRightRadius || 0;
756
- const bottomRightRadius = this.roundBottomRightRadius || 0;
757
- const bottomLeftRadius = this.roundBottomLeftRadius || 0;
758
- if (topLeftRadius || topRightRadius || bottomRightRadius || bottomLeftRadius) {
759
- 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;
760
765
  }
761
- this.nativeImageViewProtected.setHierarchy(builder.build());
762
- if (!this.mNeedRequestImage) {
763
- this.nativeImageViewProtected.setController(this.nativeImageViewProtected.getController());
766
+ else {
767
+ com.bumptech.glide.Glide.with(this._context).clear(view);
764
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();
765
788
  }
766
789
  }
767
790
  getDrawable(path) {
768
- let drawable;
769
791
  if (typeof path === 'string') {
770
792
  if (Utils.isFontIconURI(path)) {
771
793
  const fontIconCode = path.split('//')[1];
772
794
  if (fontIconCode !== undefined) {
773
- // support sync mode only
774
795
  const font = this.style.fontInternal;
775
796
  const color = this.style.color;
776
- 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);
777
798
  }
778
799
  }
779
800
  else if (Utils.isFileOrResourcePath(path)) {
780
801
  if (path.indexOf(Utils.RESOURCE_PREFIX) === 0) {
781
- return this.getDrawableFromResource(path); // number!
802
+ return this.getDrawableFromResource(path);
782
803
  }
783
804
  else {
784
- drawable = this.getDrawableFromLocalFile(path);
805
+ return this.getDrawableFromLocalFile(path);
785
806
  }
786
807
  }
787
808
  }
788
- else {
789
- 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);
790
811
  }
791
- return drawable;
812
+ return null;
792
813
  }
793
814
  getDrawableFromLocalFile(localFilePath) {
794
815
  const img = ImageSource.fromFileSync(localFilePath);
795
- let drawable = null;
796
816
  if (img) {
797
- 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);
798
818
  }
799
- return drawable;
819
+ return null;
800
820
  }
801
821
  getDrawableFromResource(resourceName) {
802
822
  const application = Utils.android.getApplication();
803
823
  const resources = application.getResources();
804
824
  const identifier = resources.getIdentifier(resourceName.substring(Utils.RESOURCE_PREFIX.length), 'drawable', application.getPackageName());
805
- // we return the identifier to allow Fresco to handle memory / caching
806
825
  return identifier;
807
- // return Utils.android.getApplicationContext().getDrawable(identifier);
808
826
  }
809
827
  startAnimating() {
810
- if (this.nativeImageViewProtected) {
811
- const controller = this.nativeImageViewProtected.getController();
812
- if (controller) {
813
- const animatable = controller.getAnimatable();
814
- if (animatable) {
815
- animatable.start();
816
- }
817
- }
828
+ const drawable = this.nativeViewProtected.getDrawable();
829
+ if (drawable && drawable instanceof android.graphics.drawable.Animatable) {
830
+ drawable.start();
818
831
  }
819
832
  }
820
833
  stopAnimating() {
821
- if (this.nativeImageViewProtected) {
822
- const controller = this.nativeImageViewProtected.getController();
823
- if (controller) {
824
- const animatable = controller.getAnimatable();
825
- if (animatable) {
826
- animatable.stop();
827
- }
828
- }
834
+ const drawable = this.nativeViewProtected.getDrawable();
835
+ if (drawable && drawable instanceof android.graphics.drawable.Animatable) {
836
+ drawable.stop();
829
837
  }
830
838
  }
831
839
  }
@@ -857,19 +865,19 @@ __decorate([
857
865
  needUpdateHierarchy
858
866
  ], Img.prototype, _j, null);
859
867
  __decorate([
860
- needUpdateHierarchy(true)
868
+ needRequestImage
861
869
  ], Img.prototype, _k, null);
862
870
  __decorate([
863
- needUpdateHierarchy
871
+ needRequestImage
864
872
  ], Img.prototype, _l, null);
865
873
  __decorate([
866
- needUpdateHierarchy
874
+ needRequestImage
867
875
  ], Img.prototype, _m, null);
868
876
  __decorate([
869
- needUpdateHierarchy
877
+ needRequestImage
870
878
  ], Img.prototype, _o, null);
871
879
  __decorate([
872
- needUpdateHierarchy
880
+ needRequestImage
873
881
  ], Img.prototype, _p, null);
874
882
  __decorate([
875
883
  needRequestImage
@@ -880,145 +888,32 @@ __decorate([
880
888
  __decorate([
881
889
  needRequestImage
882
890
  ], Img.prototype, _s, null);
883
- __decorate([
884
- needRequestImage
885
- ], Img.prototype, _t, null);
886
- __decorate([
887
- needRequestImage
888
- ], Img.prototype, _u, null);
889
- __decorate([
890
- needRequestImage
891
- ], Img.prototype, _v, null);
892
- class GenericDraweeHierarchyBuilder {
893
- constructor() {
894
- const res = Utils.android.getApplicationContext().getResources();
895
- this.nativeBuilder = new com.facebook.drawee.generic.GenericDraweeHierarchyBuilder(res);
896
- }
897
- setPlaceholderImage(drawable, scaleType) {
898
- if (!this.nativeBuilder) {
899
- return this;
900
- }
901
- if (scaleType) {
902
- this.nativeBuilder.setPlaceholderImage(drawable, getScaleType(scaleType));
903
- }
904
- else {
905
- this.nativeBuilder.setPlaceholderImage(drawable);
906
- }
907
- return this;
908
- }
909
- setActualImageColorFilter(filter) {
910
- if (!this.nativeBuilder) {
911
- return this;
912
- }
913
- this.nativeBuilder.setActualImageColorFilter(filter);
914
- return this;
915
- }
916
- setFailureImage(drawable, scaleType) {
917
- if (!this.nativeBuilder) {
918
- return null;
919
- }
920
- if (scaleType) {
921
- this.nativeBuilder.setFailureImage(drawable, getScaleType(scaleType));
922
- }
923
- else {
924
- this.nativeBuilder.setFailureImage(drawable);
925
- }
926
- return this;
927
- }
928
- setActualImageScaleType(scaleType, imageRotation = 0) {
929
- if (!this.nativeBuilder) {
930
- return this;
931
- }
932
- const nativeScaleType = getScaleType(scaleType);
933
- if (imageRotation !== 0 && nativeScaleType['setImageRotation']) {
934
- nativeScaleType['setImageRotation'](imageRotation);
935
- }
936
- this.nativeBuilder.setActualImageScaleType(nativeScaleType);
937
- return this;
938
- }
939
- build() {
940
- if (!this.nativeBuilder) {
941
- return null;
942
- }
943
- return this.nativeBuilder.build();
944
- }
945
- setFadeDuration(duration) {
946
- if (!this.nativeBuilder) {
947
- return null;
948
- }
949
- this.nativeBuilder.setFadeDuration(duration);
950
- return this;
951
- }
952
- setBackground(drawable) {
953
- if (!this.nativeBuilder) {
954
- return this;
955
- }
956
- this.nativeBuilder.setBackground(drawable);
957
- return this;
958
- }
959
- setProgressBarImage(color, stretch) {
960
- if (!this.nativeBuilder) {
961
- return null;
962
- }
963
- const drawable = new com.facebook.drawee.drawable.ProgressBarDrawable();
964
- if (color) {
965
- drawable.setColor(android.graphics.Color.parseColor(color));
966
- }
967
- this.nativeBuilder.setProgressBarImage(drawable, getScaleType(stretch));
968
- return this;
969
- }
970
- setRoundingParamsAsCircle() {
971
- if (!this.nativeBuilder) {
972
- return this;
973
- }
974
- const params = com.facebook.drawee.generic.RoundingParams.asCircle();
975
- this.nativeBuilder.setRoundingParams(params);
976
- return this;
977
- }
978
- setCornersRadii(topLeft, topRight, bottomRight, bottomLeft) {
979
- if (!this.nativeBuilder) {
980
- return this;
981
- }
982
- const params = new com.facebook.drawee.generic.RoundingParams();
983
- params.setCornersRadii(topLeft, topRight, bottomRight, bottomLeft);
984
- this.nativeBuilder.setRoundingParams(params);
985
- return this;
986
- }
987
- }
988
891
  function getScaleType(scaleType) {
989
892
  if (isString(scaleType)) {
990
893
  switch (scaleType) {
991
894
  case ScaleType.Center:
992
- //@ts-ignore
993
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenter();
895
+ return android.widget.ImageView.ScaleType.CENTER;
994
896
  case ScaleType.AspectFill:
995
897
  case ScaleType.CenterCrop:
996
- //@ts-ignore
997
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenterCrop();
898
+ return android.widget.ImageView.ScaleType.CENTER_CROP;
998
899
  case ScaleType.CenterInside:
999
- //@ts-ignore
1000
- return new com.nativescript.image.ScalingUtils.ScaleTypeCenterInside();
900
+ return android.widget.ImageView.ScaleType.CENTER_INSIDE;
1001
901
  case ScaleType.FitCenter:
1002
902
  case ScaleType.AspectFit:
1003
- //@ts-ignore
1004
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitCenter();
903
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1005
904
  case ScaleType.FitEnd:
1006
- //@ts-ignore
1007
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitEnd();
905
+ return android.widget.ImageView.ScaleType.FIT_END;
1008
906
  case ScaleType.FitStart:
1009
- //@ts-ignore
1010
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitStart();
907
+ return android.widget.ImageView.ScaleType.FIT_START;
1011
908
  case ScaleType.Fill:
1012
909
  case ScaleType.FitXY:
1013
- //@ts-ignore
1014
- return new com.nativescript.image.ScalingUtils.ScaleTypeFitXY();
910
+ return android.widget.ImageView.ScaleType.FIT_XY;
1015
911
  case ScaleType.FocusCrop:
1016
- //@ts-ignore
1017
- return new com.nativescript.image.ScalingUtils.ScaleTypeFocusCrop();
912
+ return android.widget.ImageView.ScaleType.CENTER_CROP;
1018
913
  default:
1019
- break;
914
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1020
915
  }
1021
916
  }
1022
- return null;
917
+ return android.widget.ImageView.ScaleType.FIT_CENTER;
1023
918
  }
1024
919
  //# sourceMappingURL=index.android.js.map