mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge remote-tracking branch 'origin/main' into feat/tabs-icon-improvements
This commit is contained in:
@@ -97,11 +97,6 @@ interface ApplicationEvents {
|
|||||||
*/
|
*/
|
||||||
on(event: 'livesync', callback: (args: ApplicationEventData) => void, thisArg?: any): void;
|
on(event: 'livesync', callback: (args: ApplicationEventData) => void, thisArg?: any): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* This event is raised when application css is changed.
|
|
||||||
*/
|
|
||||||
on(event: 'cssChanged', callback: (args: CssChangedEventData) => void, thisArg?: any): void;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This event is raised on application launchEvent.
|
* This event is raised on application launchEvent.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class ImageAssetBase extends Observable implements ImageAssetDefinition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
set options(value: ImageAssetOptions) {
|
set options(value: ImageAssetOptions) {
|
||||||
this._options = value;
|
this._options = normalizeImageAssetOptions(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
get nativeImage(): any {
|
get nativeImage(): any {
|
||||||
@@ -35,6 +35,35 @@ export class ImageAssetBase extends Observable implements ImageAssetDefinition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toPositiveInt(value: any): number {
|
||||||
|
if (value == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (typeof value === 'number') {
|
||||||
|
return value > 0 ? Math.floor(value) : 0;
|
||||||
|
}
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
const parsed = parseInt(value, 10);
|
||||||
|
return isNaN(parsed) || parsed <= 0 ? 0 : parsed;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeImageAssetOptions(options: ImageAssetOptions): ImageAssetOptions {
|
||||||
|
const normalized = options ? { ...options } : ({} as ImageAssetOptions);
|
||||||
|
// Coerce potential string values to positive integers; fallback to 0
|
||||||
|
// to trigger default sizing downstream
|
||||||
|
(normalized as any).width = toPositiveInt((options as any)?.width);
|
||||||
|
(normalized as any).height = toPositiveInt((options as any)?.height);
|
||||||
|
if (typeof normalized.keepAspectRatio !== 'boolean') {
|
||||||
|
normalized.keepAspectRatio = true;
|
||||||
|
}
|
||||||
|
if (typeof normalized.autoScaleFactor !== 'boolean') {
|
||||||
|
normalized.autoScaleFactor = true;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
export function getAspectSafeDimensions(sourceWidth, sourceHeight, reqWidth, reqHeight) {
|
export function getAspectSafeDimensions(sourceWidth, sourceHeight, reqWidth, reqHeight) {
|
||||||
const widthCoef = sourceWidth / reqWidth;
|
const widthCoef = sourceWidth / reqWidth;
|
||||||
const heightCoef = sourceHeight / reqHeight;
|
const heightCoef = sourceHeight / reqHeight;
|
||||||
@@ -47,8 +76,9 @@ export function getAspectSafeDimensions(sourceWidth, sourceHeight, reqWidth, req
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getRequestedImageSize(src: { width: number; height: number }, options: ImageAssetOptions): { width: number; height: number } {
|
export function getRequestedImageSize(src: { width: number; height: number }, options: ImageAssetOptions): { width: number; height: number } {
|
||||||
let reqWidth = options.width || Math.min(src.width, Screen.mainScreen.widthPixels);
|
const normalized = normalizeImageAssetOptions(options);
|
||||||
let reqHeight = options.height || Math.min(src.height, Screen.mainScreen.heightPixels);
|
let reqWidth = normalized.width || Math.min(src.width, Screen.mainScreen.widthPixels);
|
||||||
|
let reqHeight = normalized.height || Math.min(src.height, Screen.mainScreen.heightPixels);
|
||||||
|
|
||||||
if (options && options.keepAspectRatio) {
|
if (options && options.keepAspectRatio) {
|
||||||
const safeAspectSize = getAspectSafeDimensions(src.width, src.height, reqWidth, reqHeight);
|
const safeAspectSize = getAspectSafeDimensions(src.width, src.height, reqWidth, reqHeight);
|
||||||
|
|||||||
27
packages/core/image-asset/image-asset-options.spec.ts
Normal file
27
packages/core/image-asset/image-asset-options.spec.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { getRequestedImageSize } from './image-asset-common';
|
||||||
|
|
||||||
|
describe('ImageAssetOptions normalization', () => {
|
||||||
|
it('coerces string width/height to numbers', () => {
|
||||||
|
const src = { width: 2000, height: 1500 };
|
||||||
|
const result = getRequestedImageSize(src as any, { width: '300' as any, height: '200' as any, keepAspectRatio: false, autoScaleFactor: true } as any);
|
||||||
|
expect(result.width).toBe(300);
|
||||||
|
expect(result.height).toBe(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('falls back to defaults when invalid strings provided', () => {
|
||||||
|
const src = { width: 800, height: 600 };
|
||||||
|
const result = getRequestedImageSize(src as any, { width: 'abc' as any, height: '' as any, keepAspectRatio: false } as any);
|
||||||
|
// should fall back to screen pixel defaults via getRequestedImageSize, but since
|
||||||
|
// we cannot easily control Screen.mainScreen here, we at least assert they are > 0
|
||||||
|
expect(result.width).toBeGreaterThan(0);
|
||||||
|
expect(result.height).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('respects keepAspectRatio by adjusting to safe dimensions', () => {
|
||||||
|
const src = { width: 2000, height: 1000 };
|
||||||
|
const result = getRequestedImageSize(src as any, { width: '500' as any, height: '500' as any, keepAspectRatio: true } as any);
|
||||||
|
// current implementation scales using the smaller coefficient (min), so expect 1000x500
|
||||||
|
expect(result.width).toBe(1000);
|
||||||
|
expect(result.height).toBe(500);
|
||||||
|
});
|
||||||
|
});
|
||||||
Binary file not shown.
@@ -6,7 +6,8 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.1.0'
|
// Updated for Java 21 compatibility via Gradle 8.4
|
||||||
|
classpath 'com.android.tools.build:gradle:8.3.2'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ def isWinOs = System.properties['os.name'].toLowerCase().contains('windows')
|
|||||||
|
|
||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
def computeCompileSdkVersion () {
|
def computeCompileSdkValue () {
|
||||||
if(project.hasProperty("compileSdk")) {
|
if(project.hasProperty("compileSdk")) {
|
||||||
return compileSdk
|
return compileSdk
|
||||||
}
|
}
|
||||||
@@ -15,15 +15,6 @@ def computeCompileSdkVersion () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def computeBuildToolsVersion() {
|
|
||||||
if(project.hasProperty("buildToolsVersion")) {
|
|
||||||
return buildToolsVersion
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "32.0.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def computeTargetSdkVersion() {
|
def computeTargetSdkVersion() {
|
||||||
if(project.hasProperty("targetSdk")) {
|
if(project.hasProperty("targetSdk")) {
|
||||||
return targetSdk
|
return targetSdk
|
||||||
@@ -34,12 +25,13 @@ def computeTargetSdkVersion() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion computeCompileSdkVersion()
|
// AGP 8 DSL: use 'compileSdk' and specify namespace
|
||||||
buildToolsVersion computeBuildToolsVersion()
|
compileSdk computeCompileSdkValue()
|
||||||
|
namespace "org.nativescript.widgets"
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 17
|
minSdk 17
|
||||||
targetSdkVersion computeTargetSdkVersion()
|
targetSdk computeTargetSdkVersion()
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,6 +170,36 @@ public class Utils {
|
|||||||
boolean autoScaleFactor;
|
boolean autoScaleFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int parsePositiveInt(JSONObject object, String key) {
|
||||||
|
if (object == null || key == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (!object.has(key) || object.isNull(key)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Object value = object.get(key);
|
||||||
|
if (value instanceof Number) {
|
||||||
|
int parsed = (int) Math.floor(((Number) value).doubleValue());
|
||||||
|
return parsed > 0 ? parsed : 0;
|
||||||
|
}
|
||||||
|
if (value instanceof String) {
|
||||||
|
String s = ((String) value).trim();
|
||||||
|
if (s.length() == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
int parsed = Integer.parseInt(s);
|
||||||
|
return parsed > 0 ? parsed : 0;
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (JSONException ignored) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
private static final Executor executors = Executors.newCachedThreadPool();
|
private static final Executor executors = Executors.newCachedThreadPool();
|
||||||
|
|
||||||
|
|
||||||
@@ -297,8 +327,9 @@ public class Utils {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
JSONObject object = new JSONObject(options);
|
JSONObject object = new JSONObject(options);
|
||||||
opts.width = object.optInt("width", 0);
|
// Coerce numeric strings or numbers; fallback to 0 for invalid values
|
||||||
opts.height = object.optInt("height", 0);
|
opts.width = parsePositiveInt(object, "width");
|
||||||
|
opts.height = parsePositiveInt(object, "height");
|
||||||
opts.keepAspectRatio = object.optBoolean("keepAspectRatio", true);
|
opts.keepAspectRatio = object.optBoolean("keepAspectRatio", true);
|
||||||
opts.autoScaleFactor = object.optBoolean("autoScaleFactor", true);
|
opts.autoScaleFactor = object.optBoolean("autoScaleFactor", true);
|
||||||
} catch (JSONException ignored) {
|
} catch (JSONException ignored) {
|
||||||
|
|||||||
@@ -6,6 +6,33 @@ set -e
|
|||||||
echo "Use dumb gradle terminal"
|
echo "Use dumb gradle terminal"
|
||||||
export TERM=dumb
|
export TERM=dumb
|
||||||
|
|
||||||
|
# Prefer running with JDK 21 for Gradle 8.4+/AGP 8.3+
|
||||||
|
if [ "$(uname)" = "Darwin" ]; then
|
||||||
|
# On macOS, prefer JDK 21, fall back to JDK 17
|
||||||
|
if /usr/libexec/java_home -v 21 >/dev/null 2>&1; then
|
||||||
|
export JAVA_HOME=$(/usr/libexec/java_home -v 21)
|
||||||
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
|
echo "Using Java (21) at $JAVA_HOME"
|
||||||
|
java -version 2>&1 | head -n 1
|
||||||
|
elif /usr/libexec/java_home -v 17 >/dev/null 2>&1; then
|
||||||
|
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
|
||||||
|
export PATH="$JAVA_HOME/bin:$PATH"
|
||||||
|
echo "Using Java (17) at $JAVA_HOME"
|
||||||
|
java -version 2>&1 | head -n 1
|
||||||
|
else
|
||||||
|
echo "Warning: JDK 21 or 17 not found via /usr/libexec/java_home. Using current JAVA_HOME: ${JAVA_HOME:-unset}"
|
||||||
|
java -version 2>&1 || true
|
||||||
|
echo "Install JDK 21 (preferred) or JDK 17."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# Non-macOS: print Java version for visibility
|
||||||
|
if command -v java >/dev/null 2>&1; then
|
||||||
|
echo "Detected Java runtime: $(java -version 2>&1 | head -n 1)"
|
||||||
|
else
|
||||||
|
echo "Warning: 'java' not found on PATH. Build will likely fail."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
rm -rf dist/package/platforms/android || true
|
rm -rf dist/package/platforms/android || true
|
||||||
mkdir -p dist/package/platforms/android
|
mkdir -p dist/package/platforms/android
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user