diff --git a/desktop/angular/src/app/shared/pipes/common-pipes.module.ts b/desktop/angular/src/app/shared/pipes/common-pipes.module.ts
index c64df8a1..3350d6bd 100644
--- a/desktop/angular/src/app/shared/pipes/common-pipes.module.ts
+++ b/desktop/angular/src/app/shared/pipes/common-pipes.module.ts
@@ -5,6 +5,7 @@ import { ToAppProfilePipe } from "./to-profile.pipe";
import { DurationPipe } from "./duration.pipe";
import { RoundPipe } from "./round.pipe";
import { ToSecondsPipe } from "./to-seconds.pipe";
+import { HttpImgSrcPipe } from "./http-img-src.pipe";
@NgModule({
declarations: [
@@ -13,7 +14,8 @@ import { ToSecondsPipe } from "./to-seconds.pipe";
ToAppProfilePipe,
DurationPipe,
RoundPipe,
- ToSecondsPipe
+ ToSecondsPipe,
+ HttpImgSrcPipe
],
exports: [
TimeAgoPipe,
@@ -21,7 +23,8 @@ import { ToSecondsPipe } from "./to-seconds.pipe";
ToAppProfilePipe,
DurationPipe,
RoundPipe,
- ToSecondsPipe
+ ToSecondsPipe,
+ HttpImgSrcPipe
]
})
export class CommonPipesModule { }
diff --git a/desktop/angular/src/app/shared/pipes/http-img-src.pipe.ts b/desktop/angular/src/app/shared/pipes/http-img-src.pipe.ts
new file mode 100644
index 00000000..c3aae731
--- /dev/null
+++ b/desktop/angular/src/app/shared/pipes/http-img-src.pipe.ts
@@ -0,0 +1,80 @@
+
+import { Pipe, PipeTransform } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
+import { Observable, of } from 'rxjs';
+import { map, catchError, tap } from 'rxjs/operators';
+
+//**
+// * This pipe fetches an image from a given URL and returns a SafeUrl for use in Angular templates.
+// * It caches the image to avoid multiple requests for the same URL.
+// * If the image fails to load, it returns null and logs an error message.
+// *
+// * The pipe uses Angular's HttpClient to make the HTTP request and DomSanitizer to sanitize the URL.
+// *
+// * This pipe is useful for forcing usage of the HTTP interceptor in Tauri instead of the WebView
+// * (for example, to use the Tauri API for HTTP requests)
+// *
+// * @example
+// *
+// **/
+
+@Pipe({
+ name: 'httpImgSrc'
+})
+export class HttpImgSrcPipe implements PipeTransform {
+ private static cache = new Map();
+
+ constructor(private http: HttpClient, private sanitizer: DomSanitizer) { }
+
+ transform(url: string | SafeUrl | undefined): Observable {
+ if (!url) {
+ return of(null);
+ }
+
+ if (this.isSafeUrl(url)) {
+ //console.log('[Pipe httpImgSrc] URL is already a SafeUrl:', url);
+ return of(url);
+ }
+
+ if (typeof url !== 'string') {
+ //console.error('[Pipe httpImgSrc] Invalid URL:', url);
+ return of(null);
+ }
+
+ if (HttpImgSrcPipe.cache.has(url)) {
+ //console.log('[Pipe httpImgSrc] Returning cached image:', url);
+ return of(HttpImgSrcPipe.cache.get(url) as SafeUrl | null);
+ }
+
+ return this.http.get(url, { responseType: 'blob' }).pipe(
+ //tap(blob => console.log('[Pipe httpImgSrc] Successfully loaded image:', url, 'Size:', blob.size, 'Type:', blob.type)),
+ map(blob => URL.createObjectURL(blob)),
+ map(objectUrl => {
+ const safeUrl = this.sanitizer.bypassSecurityTrustUrl(objectUrl);
+
+ if (HttpImgSrcPipe.cache.size > 1000) {
+ // Very simple cache eviction strategy: clear the cache if it exceeds 1000 items.
+ // Normally it should never exceed this size, but just in case.
+ // TODO: Implement a more sophisticated cache eviction strategy if needed.
+ console.warn('[Pipe httpImgSrc] Cache size exceeded 1000 items. Clearing images cache.');
+ HttpImgSrcPipe.cache.clear();
+ }
+
+ HttpImgSrcPipe.cache.set(url, safeUrl);
+ return safeUrl;
+ }),
+ catchError(() => {
+ console.error('[Pipe httpImgSrc] Failed to load image:', url);
+ HttpImgSrcPipe.cache.set(url, null);
+ return of(null);
+ })
+ );
+ }
+ // Type guard for SafeUrl
+ private isSafeUrl(value: any): value is SafeUrl {
+ // SafeUrl is an object with an internal property changing per Angular versions
+ // But it’s always object-like, not a string, and created by DomSanitizer
+ return typeof value === 'object' && value !== null && value.changingThisBreaksApplicationSecurity !== undefined;
+ }
+}
diff --git a/desktop/angular/src/app/shared/pipes/index.ts b/desktop/angular/src/app/shared/pipes/index.ts
index 6eddfdd2..52f68966 100644
--- a/desktop/angular/src/app/shared/pipes/index.ts
+++ b/desktop/angular/src/app/shared/pipes/index.ts
@@ -4,3 +4,4 @@ export * from './to-profile.pipe';
export * from './duration.pipe';
export * from './to-seconds.pipe';
export * from './round.pipe';
+export * from './http-img-src.pipe'