Content-Length: 735055 | pFad | http://github.com/NativeScript/NativeScript/pull/10569/files

1B feat(ios): SF Symbol scale support via iosSymbolScale by NathanWalker · Pull Request #10569 · NativeScript/NativeScript · GitHub
Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios): SF Symbol scale support via iosSymbolScale #10569

Merged
merged 6 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/toolbox/src/pages/image-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export function navigatingTo(args: EventData) {

export class DemoModel extends Observable {
addingPhoto = false;
symbolWiggleEffect: ImageSymbolEffects.Wiggle;
symbolBounceEffect: ImageSymbolEffects.Bounce;
symbolBreathEffect: ImageSymbolEffects.Breathe;
symbolRotateEffect: ImageSymbolEffects.Rotate;
symbolWiggleEffect = ImageSymbolEffects.Wiggle;
symbolBounceEffect = ImageSymbolEffects.Bounce;
symbolBreathEffect = ImageSymbolEffects.Breathe;
symbolRotateEffect = ImageSymbolEffects.Rotate;

pickImage() {
const context = create({
Expand Down
21 changes: 14 additions & 7 deletions apps/toolbox/src/pages/image-handling.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,23 @@
<ios>
<!-- SF Symbols with Effects -->
<ContentView height="1" width="100%" backgroundColor="#efefef" margin="10"></ContentView>
<GridLayout rows="auto,auto,auto" columns="*,*">
<Image src="sys://photo.on.rectangle.angled" width="100" tintColor="green" symbolEffect="{{symbolWiggleEffect}}" padding="8"/>
<Image col="1" src="sys://steeringwheel.and.hands" width="100" tintColor="black" symbolEffect="{{symbolWiggleEffect}}" padding="8" />
<GridLayout rows="auto,auto,auto,auto,auto" columns="*,*">
<Image src="sys://photo.on.rectangle.angled" width="100" tintColor="green" iosSymbolEffect="{{symbolBounceEffect}}" padding="8"/>
<Image col="1" src="sys://photo.on.rectangle.angled" width="100" tintColor="green" iosSymbolEffect="{{symbolBounceEffect}}" iosSymbolScale="small" padding="8" />

<Image row="1" src="sys://airpods.pro.chargingcase.wireless.radiowaves.left.and.right.fill" width="100" symbolEffect="{{symbolBounceEffect}}" padding="8" />
<Image row="1" col="1" src="sys://lungs.fill" width="100" symbolEffect="{{symbolBreathEffect}}" padding="8" />
<Image row="1" src="sys://photo.on.rectangle.angled" width="100" tintColor="green" iosSymbolEffect="{{symbolBounceEffect}}" iosSymbolScale="medium" padding="8"/>
<Image row="1" col="1" src="sys://photo.on.rectangle.angled" width="100" tintColor="green" iosSymbolEffect="{{symbolBounceEffect}}" iosSymbolScale="large" padding="8"/>

<Image row="2" src="sys://airpods.pro.chargingcase.wireless.radiowaves.left.and.right.fill" width="100" iosSymbolEffect="{{symbolBounceEffect}}" padding="8" />
<Image row="2" col="1" src="sys://lungs.fill" width="100" iosSymbolEffect="{{symbolBreathEffect}}" padding="8" />


<Image row="3" src="sys://clock.arrow.trianglehead.2.counterclockwise.rotate.90" width="100" iosSymbolEffect="{{symbolRotateEffect}}" padding="8" />
<Image row="3" col="1" src="sys://square.and.arrow.up" width="100" iosSymbolEffect="{{symbolWiggleEffect}}" padding="8" />

<Image row="4" src="sys://steeringwheel.and.hands" width="100" tintColor="black" iosSymbolEffect="{{symbolWiggleEffect}}" padding="8" />
<Image row="4" col="1" src="sys://steeringwheel.and.hands" width="100" tintColor="black" iosSymbolEffect="{{symbolWiggleEffect}}" iosSymbolScale="large" padding="8" />

<Image row="2" src="sys://clock.arrow.trianglehead.2.counterclockwise.rotate.90" width="100" symbolEffect="{{symbolRotateEffect}}" padding="8" />
<Image row="2" col="1" src="sys://square.and.arrow.up" width="100" symbolEffect="{{symbolWiggleEffect}}" padding="8" />
</GridLayout>
</ios>

Expand Down
6 changes: 5 additions & 1 deletion packages/core/image-source/index.android.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Definitions.
import { ImageSource as ImageSourceDefinition } from '.';
import { ImageSource as ImageSourceDefinition, iosSymbolScaleType } from '.';
import { ImageAsset } from '../image-asset';
import * as httpModule from '../http';

Expand Down Expand Up @@ -149,6 +149,10 @@ export class ImageSource implements ImageSourceDefinition {
return ImageSource.fromFileSync(path);
}

static iosSymbolScaleFor(scale: iosSymbolScaleType): number {
return 0;
}

static fromSystemImageSync(name: string): ImageSource {
return ImageSource.fromResourceSync(name);
}
Expand Down
16 changes: 14 additions & 2 deletions packages/core/image-source/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,23 @@ export class ImageSource {
*/
static fromResource(name: string): Promise<ImageSource>;

/**
* (iOS only) Get system symbol scale
* @param scale symbol scale type
*/
static iosSymbolScaleFor(scale: iosSymbolScaleType): number;

/**
* Loads this instance from the specified system image name.
* @param name the name of the system image
*/
static fromSystemImageSync(name: string): ImageSource;
static fromSystemImageSync(name: string, scale?: iosSymbolScaleType): ImageSource;

/**
* Loads this instance from the specified system image name asynchronously.
* @param name the name of the system image
*/
static fromSystemImage(name: string): Promise<ImageSource>;
static fromSystemImage(name: string, scale?: iosSymbolScaleType): Promise<ImageSource>;

/**
* Loads this instance from the specified file.
Expand Down Expand Up @@ -259,6 +265,12 @@ export class ImageSource {
resizeAsync(maxSize: number, options?: any): Promise<ImageSource>;
}

/**
* iOS only
* SF Symbol scale
*/
export type iosSymbolScaleType = 'default' | 'small' | 'medium' | 'large';

/**
* @deprecated Use ImageSource.fromAsset() instead.
* Creates a new ImageSource instance and loads it from the specified image asset asynchronously.
Expand Down
35 changes: 29 additions & 6 deletions packages/core/image-source/index.ios.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Definitions.
import { ImageSource as ImageSourceDefinition } from '.';
import { ImageSource as ImageSourceDefinition, iosSymbolScaleType } from '.';
import { ImageAsset } from '../image-asset';
import * as httpModule from '../http';
import { Font } from '../ui/styling/font';
Expand Down Expand Up @@ -73,16 +73,39 @@ export class ImageSource implements ImageSourceDefinition {
return http.getImage(url);
}

static fromSystemImageSync(name: string): ImageSource {
const image = UIImage.systemImageNamed(name);
static iosSystemScaleFor(scale: iosSymbolScaleType) {
switch (scale) {
case 'small':
return UIImageSymbolScale.Small;
case 'medium':
return UIImageSymbolScale.Medium;
case 'large':
return UIImageSymbolScale.Large;
default:
return UIImageSymbolScale.Default;
}
}

static fromSystemImageSync(name: string, scale?: iosSymbolScaleType): ImageSource {
if (scale) {
const image = UIImage.systemImageNamedWithConfiguration(name, UIImageSymbolConfiguration.configurationWithScale(ImageSource.iosSystemScaleFor(scale)));
return image ? new ImageSource(image) : null;
} else {
const image = UIImage.systemImageNamed(name);

return image ? new ImageSource(image) : null;
return image ? new ImageSource(image) : null;
}
}

static fromSystemImage(name: string): Promise<ImageSource> {
static fromSystemImage(name: string, scale?: iosSymbolScaleType): Promise<ImageSource> {
return new Promise<ImageSource>((resolve, reject) => {
try {
const image = UIImage.systemImageNamed(name);
let image: UIImage;
if (scale) {
image = UIImage.systemImageNamedWithConfiguration(name, UIImageSymbolConfiguration.configurationWithScale(ImageSource.iosSystemScaleFor(scale)));
} else {
image = UIImage.systemImageNamed(name);
}
if (image) {
resolve(new ImageSource(image));
} else {
Expand Down
1 change: 1 addition & 0 deletions packages/core/references.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//github.com/ <reference path="../types-ios/src/lib/ios/objc-x86_64/objc!CFNetwork.d.ts" />
//github.com/ <reference path="../types-ios/src/lib/ios/objc-x86_64/objc!CoreText.d.ts" />
//github.com/ <reference path="../types-ios/src/lib/ios/objc-x86_64/objc!Darwin.d.ts" />
//github.com/ <reference path="../types-ios/src/lib/ios/objc-x86_64/objc!DarwinFoundation.d.ts" />
//github.com/ <reference path="../types-ios/src/lib/ios/objc-x86_64/objc!Symbols.d.ts" />
//github.com/ <reference path="../types-android/src/lib/android-29.d.ts" />
//github.com/ <reference path="./platforms/ios/typings/objc!MaterialComponents.d.ts" />
Expand Down
4 changes: 2 additions & 2 deletions packages/core/ui/core/view/index.ios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -901,8 +901,8 @@ export class View extends ViewCommon implements ViewDefinition {

let notification: number;
let args: string | UIView | null = this.nativeViewProtected;
if (typeof msg === 'string' && msg) {
args = msg;
if (options?.message) {
args = options.message;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed build error here picked up by latest TS configurations.

}

switch (options.iosNotificationType) {
Expand Down
15 changes: 12 additions & 3 deletions packages/core/ui/image/image-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { View, CSSType } from '../core/view';
import { booleanConverter } from '../core/view-base';
import { CoreTypes } from '../../core-types';
import { ImageAsset } from '../../image-asset';
import { ImageSource } from '../../image-source';
import { ImageSource, iosSymbolScaleType } from '../../image-source';
import { isDataURI, isFontIconURI, isFileOrResourcePath, RESOURCE_PREFIX, SYSTEM_PREFIX } from '../../utils';
import { Color } from '../../color';
import { Style } from '../styling/style';
Expand All @@ -21,6 +21,7 @@ export abstract class ImageBase extends View implements ImageDefinition {
public loadMode: 'sync' | 'async';
public decodeWidth: CoreTypes.LengthType;
public decodeHeight: CoreTypes.LengthType;
public iosSymbolScale: iosSymbolScaleType;

get tintColor(): Color {
return this.style.tintColor;
Expand Down Expand Up @@ -86,10 +87,10 @@ export abstract class ImageBase extends View implements ImageDefinition {
} else if (value.indexOf(SYSTEM_PREFIX) === 0) {
const sysPath = value.slice(SYSTEM_PREFIX.length);
if (sync) {
imageLoaded(ImageSource.fromSystemImageSync(sysPath));
imageLoaded(ImageSource.fromSystemImageSync(sysPath, this.iosSymbolScale));
} else {
this.imageSource = null;
ImageSource.fromSystemImage(sysPath).then(imageLoaded);
ImageSource.fromSystemImage(sysPath, this.iosSymbolScale).then(imageLoaded);
}
} else {
if (sync) {
Expand Down Expand Up @@ -196,4 +197,12 @@ export const iosSymbolEffectProperty = new Property<ImageBase, ImageSymbolEffect
});
iosSymbolEffectProperty.register(ImageBase);

/**
* iOS only
*/
export const iosSymbolScaleProperty = new Property<ImageBase, iosSymbolScaleType>({
name: 'iosSymbolScale',
});
iosSymbolScaleProperty.register(ImageBase);

export { ImageSymbolEffect, ImageSymbolEffects };
24 changes: 20 additions & 4 deletions packages/core/ui/image/index.ios.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, srcProperty, iosSymbolEffectProperty, ImageSymbolEffect, ImageSymbolEffects } from './image-common';
import { ImageSource } from '../../image-source';
import { ImageBase, stretchProperty, imageSourceProperty, tintColorProperty, srcProperty, iosSymbolEffectProperty, ImageSymbolEffect, ImageSymbolEffects, iosSymbolScaleProperty } from './image-common';
import { ImageSource, iosSymbolScaleType } from '../../image-source';
import { ImageAsset } from '../../image-asset';
import { Color } from '../../color';
import { Trace } from '../../trace';
Expand Down Expand Up @@ -192,19 +192,35 @@ export class Image extends ImageBase {
this._setNativeImage(value ? value.ios : null);
}

[srcProperty.setNative](value: string | ImageSource | ImageAsset) {
private _setSrc(value: string | ImageSource | ImageAsset) {
this._createImageSourceFromSrc(value);
if (this.iosSymbolScale) {
// when applying symbol scale, contentMode must be center
// https://stackoverflow.com/a/65787627
this.nativeViewProtected.contentMode = UIViewContentMode.Center;
}
}

[srcProperty.setNative](value: string | ImageSource | ImageAsset) {
this._setSrc(value);
}

[iosSymbolEffectProperty.setNative](value: ImageSymbolEffect | ImageSymbolEffects) {
if (SDK_VERSION < 17) {
return;
}
const symbol = typeof value === 'string' ? ImageSymbolEffect.fromSymbol(value) : value;
if (symbol && symbol.effect) {
if (symbol?.effect) {
// Note: https://developer.apple.com/documentation/symbols/symboleffectoptions/4197883-repeating
// Will want to move to https://developer.apple.com/documentation/symbols/nssymboleffectoptionsrepeatbehavior?language=objc as fallback once optionsWithRepeating is removed
this.nativeViewProtected.addSymbolEffectOptionsAnimatedCompletion(symbol.effect, symbol.options || NSSymbolEffectOptions.optionsWithRepeating(), true, symbol.completion || null);
} else {
this.nativeViewProtected.removeAllSymbolEffects();
}
}

[iosSymbolScaleProperty.setNative](value: iosSymbolScaleType) {
// reset src to configure scale
this._setSrc(this.src);
}
}
11 changes: 5 additions & 6 deletions packages/core/ui/image/symbol-effects.android.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { ImageSymbolEffectCommon, ImageSymbolEffects } from './symbol-effects-common';
import type { ImageSymbolEffect as ImageSymbolEffectDefinition } from './symbol-effects.d.ts';
export { ImageSymbolEffects };
import { ImageSymbolEffectCommon } from './symbol-effects-common';
export { ImageSymbolEffects } from './symbol-effects-common';

export const ImageSymbolEffect: typeof ImageSymbolEffectDefinition = class ImageSymbolEffect extends ImageSymbolEffectCommon implements ImageSymbolEffectDefinition {
static fromSymbol(symbol: string): ImageSymbolEffectDefinition {
export class ImageSymbolEffect extends ImageSymbolEffectCommon {
static fromSymbol(symbol: string) {
return new ImageSymbolEffect();
}
};
}
23 changes: 4 additions & 19 deletions packages/core/ui/image/symbol-effects.ios.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { SDK_VERSION } from '../../utils/constants';
import { ImageSymbolEffectCommon, ImageSymbolEffects } from './symbol-effects-common';
import type { ImageSymbolEffect as ImageSymbolEffectDefinition } from './symbol-effects.d.ts';
export { ImageSymbolEffects } from './symbol-effects-common';

export const ImageSymbolEffect: typeof ImageSymbolEffectDefinition = class ImageSymbolEffect extends ImageSymbolEffectCommon implements ImageSymbolEffectDefinition {
export class ImageSymbolEffect extends ImageSymbolEffectCommon {
constructor(symbol: NSSymbolEffect) {
super();
this.effect = symbol;
}
static fromSymbol(symbol: string): ImageSymbolEffectDefinition | null {
static fromSymbol(symbol: string): ImageSymbolEffect | null {
if (SDK_VERSION < 17) {
return null;
}
Expand Down Expand Up @@ -44,52 +44,37 @@ export const ImageSymbolEffect: typeof ImageSymbolEffectDefinition = class Image
if (SDK_VERSION < 18) {
return null;
}
// TODO: remove ts-expect-error once we bump the types package
switch (symbol) {
case ImageSymbolEffects.Breathe:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolBreatheEffect.effect());
case ImageSymbolEffects.BreathePlain:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolBreatheEffect.breathePlainEffect());
case ImageSymbolEffects.Rotate:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolRotateEffect.effect());
case ImageSymbolEffects.RotateClockwise:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolRotateEffect.rotateClockwiseEffect());
case ImageSymbolEffects.RotateCounterClockwise:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolRotateEffect.rotateCounterClockwiseEffect());
case ImageSymbolEffects.Wiggle:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.effect());
case ImageSymbolEffects.WiggleBackward:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleBackwardEffect());
case ImageSymbolEffects.WiggleClockwise:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleClockwiseEffect());
case ImageSymbolEffects.WiggleCounterClockwise:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleCounterClockwiseEffect());
case ImageSymbolEffects.WiggleDown:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleDownEffect());
case ImageSymbolEffects.WiggleForward:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleForwardEffect());
case ImageSymbolEffects.WiggleUp:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleUpEffect());
case ImageSymbolEffects.WiggleLeft:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleLeftEffect());
case ImageSymbolEffects.WiggleRight:
// @ts-expect-error added on iOS 18
return new ImageSymbolEffect(NSSymbolWiggleEffect.wiggleRightEffect());
}

return null;
}
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,11 @@ declare var NativeScriptEmbedderDelegate: {

prototype: NativeScriptEmbedderDelegate;
};

declare class NativeScriptViewFactory extends NSObject {
static getKeyWindow(): UIWindow;
static shared: NativeScriptViewFactory;
views: NSMutableDictionary<string, any>;
viewCreator: (id: string, ctrl: UIViewController) => void;
viewDestroyer: (id: string) => void;
}
Loading








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/NativeScript/NativeScript/pull/10569/files

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy