From 869c7b2d0905b6665f95f55c26310072f652ea15 Mon Sep 17 00:00:00 2001 From: Eduardo Speroni Date: Tue, 28 May 2024 10:22:18 -0300 Subject: [PATCH 1/4] feat: add `sys://` ios images --- packages/core/image-source/index.android.ts | 14 ++++++++--- packages/core/image-source/index.d.ts | 12 +++++++++ packages/core/image-source/index.ios.ts | 28 +++++++++++++++++++-- packages/core/ui/image/image-common.ts | 12 +++++++-- packages/core/utils/common.ts | 8 +++--- 5 files changed, 64 insertions(+), 10 deletions(-) diff --git a/packages/core/image-source/index.android.ts b/packages/core/image-source/index.android.ts index ca89f85247..ca36e9f4bd 100644 --- a/packages/core/image-source/index.android.ts +++ b/packages/core/image-source/index.android.ts @@ -149,6 +149,14 @@ export class ImageSource implements ImageSourceDefinition { return ImageSource.fromFileSync(path); } + static fromSystemImageSync(name: string): ImageSource { + return ImageSource.fromResourceSync(name); + } + + static fromSystemImage(name: string): Promise { + return ImageSource.fromResource(name); + } + static fromDataSync(data: any): ImageSource { const bitmap = android.graphics.BitmapFactory.decodeStream(data); @@ -335,7 +343,7 @@ export class ImageSource implements ImageSourceDefinition { reject(); } }, - }) + }), ); }); } @@ -375,7 +383,7 @@ export class ImageSource implements ImageSourceDefinition { reject(); } }, - }) + }), ); }); } @@ -404,7 +412,7 @@ export class ImageSource implements ImageSourceDefinition { reject(); } }, - }) + }), ); }); } diff --git a/packages/core/image-source/index.d.ts b/packages/core/image-source/index.d.ts index 55037abc92..57e533595e 100644 --- a/packages/core/image-source/index.d.ts +++ b/packages/core/image-source/index.d.ts @@ -54,6 +54,18 @@ export class ImageSource { */ static fromResource(name: string): Promise; + /** + * Loads this instance from the specified system image name. + * @param name the name of the system image + */ + static fromSystemImageSync(name: string): ImageSource; + + /** + * Loads this instance from the specified system image name asynchronously. + * @param name the name of the system image + */ + static fromSystemImage(name: string): Promise; + /** * Loads this instance from the specified file. * @param path The location of the file on the file system. diff --git a/packages/core/image-source/index.ios.ts b/packages/core/image-source/index.ios.ts index fd8fbf6df4..f6d854ec8a 100644 --- a/packages/core/image-source/index.ios.ts +++ b/packages/core/image-source/index.ios.ts @@ -8,7 +8,7 @@ import { Trace } from '../trace'; // Types. import { path as fsPath, knownFolders } from '../file-system'; -import { isFileOrResourcePath, RESOURCE_PREFIX, layout, releaseNativeObject } from '../utils'; +import { isFileOrResourcePath, RESOURCE_PREFIX, layout, releaseNativeObject, SYSTEM_PREFIX } from '../utils'; import { getScaledDimensions } from './image-source-common'; @@ -73,6 +73,27 @@ export class ImageSource implements ImageSourceDefinition { return http.getImage(url); } + static fromSystemImageSync(name: string): ImageSource { + const image = UIImage.systemImageNamed(name); + + return image ? new ImageSource(image) : null; + } + + static fromSystemImage(name: string): Promise { + return new Promise((resolve, reject) => { + try { + const image = UIImage.systemImageNamed(name); + if (image) { + resolve(new ImageSource(image)); + } else { + reject(new Error(`Failed to load system icon with name: ${name}`)); + } + } catch (ex) { + reject(ex); + } + }); + } + static fromResourceSync(name: string): ImageSource { const nativeSource = (UIImage).tns_safeImageNamed(name) || (UIImage).tns_safeImageNamed(`${name}.jpg`); @@ -126,7 +147,10 @@ export class ImageSource implements ImageSourceDefinition { } if (path.indexOf(RESOURCE_PREFIX) === 0) { - return ImageSource.fromResourceSync(path.substr(RESOURCE_PREFIX.length)); + return ImageSource.fromResourceSync(path.slice(RESOURCE_PREFIX.length)); + } + if (path.indexOf(SYSTEM_PREFIX) === 0) { + return ImageSource.fromSystemImageSync(path.slice(SYSTEM_PREFIX.length)); } return ImageSource.fromFileSync(path); diff --git a/packages/core/ui/image/image-common.ts b/packages/core/ui/image/image-common.ts index 91bb9a1f99..73bc24d30d 100644 --- a/packages/core/ui/image/image-common.ts +++ b/packages/core/ui/image/image-common.ts @@ -4,7 +4,7 @@ import { booleanConverter } from '../core/view-base'; import { CoreTypes } from '../../core-types'; import { ImageAsset } from '../../image-asset'; import { ImageSource } from '../../image-source'; -import { isDataURI, isFontIconURI, isFileOrResourcePath, RESOURCE_PREFIX } from '../../utils'; +import { isDataURI, isFontIconURI, isFileOrResourcePath, RESOURCE_PREFIX, SYSTEM_PREFIX } from '../../utils'; import { Color } from '../../color'; import { Style } from '../styling/style'; import { Length } from '../styling/style-properties'; @@ -75,13 +75,21 @@ export abstract class ImageBase extends View implements ImageDefinition { } } else if (isFileOrResourcePath(value)) { if (value.indexOf(RESOURCE_PREFIX) === 0) { - const resPath = value.substr(RESOURCE_PREFIX.length); + const resPath = value.slice(RESOURCE_PREFIX.length); if (sync) { imageLoaded(ImageSource.fromResourceSync(resPath)); } else { this.imageSource = null; ImageSource.fromResource(resPath).then(imageLoaded); } + } else if (value.indexOf(SYSTEM_PREFIX) === 0) { + const sysPath = value.slice(SYSTEM_PREFIX.length); + if (sync) { + imageLoaded(ImageSource.fromSystemImageSync(sysPath)); + } else { + this.imageSource = null; + ImageSource.fromSystemImage(sysPath).then(imageLoaded); + } } else { if (sync) { imageLoaded(ImageSource.fromFileSync(value)); diff --git a/packages/core/utils/common.ts b/packages/core/utils/common.ts index 273f5eb90c..2f8f46379d 100644 --- a/packages/core/utils/common.ts +++ b/packages/core/utils/common.ts @@ -8,6 +8,7 @@ export * from './mainthread-helper'; export * from './macrotask-scheduler'; export const RESOURCE_PREFIX = 'res://'; +export const SYSTEM_PREFIX = 'sys://'; export const FILE_PREFIX = 'file:///'; export function escapeRegexSymbols(source: string): string { @@ -75,7 +76,8 @@ export function isFileOrResourcePath(path: string): boolean { return ( path.indexOf('~/') === 0 || // relative to AppRoot path.indexOf('/') === 0 || // absolute path - path.indexOf(RESOURCE_PREFIX) === 0 + path.indexOf(RESOURCE_PREFIX) === 0 || + path.indexOf(SYSTEM_PREFIX) === 0 ); // resource } @@ -215,7 +217,7 @@ export function queueGC(delay = 900, useThrottle?: boolean) { if (!throttledGC.get(delay)) { throttledGC.set( delay, - throttle(() => GC(), delay) + throttle(() => GC(), delay), ); } throttledGC.get(delay)(); @@ -226,7 +228,7 @@ export function queueGC(delay = 900, useThrottle?: boolean) { if (!debouncedGC.get(delay)) { debouncedGC.set( delay, - debounce(() => GC(), delay) + debounce(() => GC(), delay), ); } debouncedGC.get(delay)(); From de6e7a6190af7da80ed308b842990acff2edfee3 Mon Sep 17 00:00:00 2001 From: Nathan Walker Date: Sun, 16 Jun 2024 14:21:09 -0700 Subject: [PATCH 2/4] feat(ios): SF Symbol effects via symbolEffect property --- apps/toolbox/src/pages/image-handling.ts | 28 ++++++++++++++++++++++- apps/toolbox/src/pages/image-handling.xml | 18 +++++++++++++++ packages/core/references.d.ts | 1 + packages/core/ui/image/image-common.ts | 19 +++++++++++++++ packages/core/ui/image/index.d.ts | 1 + packages/core/ui/image/index.ios.ts | 12 +++++++++- packages/core/ui/index.ts | 2 +- 7 files changed, 78 insertions(+), 3 deletions(-) diff --git a/apps/toolbox/src/pages/image-handling.ts b/apps/toolbox/src/pages/image-handling.ts index 528712f8b1..71d1381b15 100644 --- a/apps/toolbox/src/pages/image-handling.ts +++ b/apps/toolbox/src/pages/image-handling.ts @@ -1,4 +1,4 @@ -import { Observable, EventData, Page, ImageSource, knownFolders, path } from '@nativescript/core'; +import { Observable, EventData, Page, ImageSource, knownFolders, path, ImageSymbolEffect } from '@nativescript/core'; import { create, ImagePickerMediaType } from '@nativescript/imagepicker'; let page: Page; @@ -10,6 +10,32 @@ export function navigatingTo(args: EventData) { export class DemoModel extends Observable { addingPhoto = false; + symbolWiggleEffect: ImageSymbolEffect; + symbolBounceEffect: ImageSymbolEffect; + symbolBreathEffect: ImageSymbolEffect; + symbolRotateEffect: ImageSymbolEffect; + + constructor() { + super(); + if (__APPLE__) { + this.symbolWiggleEffect = { + effect: NSSymbolWiggleEffect.effect(), + start: true, + }; + this.symbolBounceEffect = { + effect: NSSymbolBounceEffect.effect(), + start: true, + }; + this.symbolBreathEffect = { + effect: NSSymbolBreatheEffect.effect(), + start: true, + }; + this.symbolRotateEffect = { + effect: NSSymbolRotateEffect.effect(), + start: true, + }; + } + } pickImage() { const context = create({ diff --git a/apps/toolbox/src/pages/image-handling.xml b/apps/toolbox/src/pages/image-handling.xml index 0b67d295dd..ad735e19b8 100644 --- a/apps/toolbox/src/pages/image-handling.xml +++ b/apps/toolbox/src/pages/image-handling.xml @@ -5,9 +5,27 @@ +