From 98deeccb2124484d31794fda4fb56aa27d0f7443 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Wed, 5 Oct 2016 13:09:08 +0300 Subject: [PATCH] Change image.android to use the new image.Cache class from widgets. (#2832) * Change image.android to use the new image.Cahce class from widgets. * fix npm scripts * npm tsc will compile all so no need for npm run dev-tsc-tests * fix tslint error * image-tests use memory only cache. * fix exception in image.android * Change image-tests so that Image won't be GC immediately. * Change cacheMode to enum --- .vscode/launch.json | 151 ++++++++---------- apps/package.json | 1 + package.json | 5 +- tests/.vscode/tasks.json | 10 ++ tests/app/TKUnit.ts | 8 +- tests/app/data/observable-tests.ts | 4 +- tests/app/ui/image/image-tests.ts | 67 ++++---- .../app/ui/styling/style-properties-tests.ts | 6 +- tests/package.json | 1 + tns-core-modules/ui/image/image-common.ts | 4 +- tns-core-modules/ui/image/image.android.ts | 117 ++++++++++++-- .../android/declarations.d.ts | 50 ------ .../android/org.nativescript.widgets.d.ts | 112 +++++++++++-- tns-platform-declarations/package.json | 6 - 14 files changed, 336 insertions(+), 206 deletions(-) create mode 100644 tests/.vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 3155f4945e..f335d24439 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,85 +1,70 @@ { - "version": "0.2.0", - "configurations": [ - { - "name": "Launch on iOS Device", - "type": "nativescript", - "platform": "ios", - "request": "launch", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false - }, - { - "name": "Attach on iOS Device", - "type": "nativescript", - "platform": "ios", - "request": "attach", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false - }, - { - "name": "Launch on iOS Emulator", - "type": "nativescript", - "platform": "ios", - "request": "launch", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": true - }, - { - "name": "Attach on iOS Emulator", - "type": "nativescript", - "platform": "ios", - "request": "attach", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": true - }, - { - "name": "Launch on Android Device", - "type": "nativescript", - "platform": "android", - "request": "launch", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false - }, - { - "name": "Launch on Android Emulator", - "type": "nativescript", - "platform": "android", - "request": "launch", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": true - }, - { - "name": "Attach on Android Device", - "type": "nativescript", - "platform": "android", - "request": "attach", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": false - }, - { - "name": "Attach on Android Emulator", - "type": "nativescript", - "platform": "android", - "request": "attach", - "appRoot": "${workspaceRoot}/tests", - "sourceMaps": true, - "diagnosticLogging": false, - "emulator": true - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Sync on iOS", + "type": "nativescript", + "platform": "ios", + "request": "launch", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false, + "rebuild": false, + "syncAllFiles": false + }, + { + "name": "Launch on iOS", + "type": "nativescript", + "platform": "ios", + "request": "launch", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false, + "rebuild": true + }, + { + "name": "Attach on iOS", + "type": "nativescript", + "platform": "ios", + "request": "attach", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false + }, + { + "name": "Sync on Android", + "type": "nativescript", + "platform": "android", + "request": "launch", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false, + "rebuild": false + }, + { + "name": "Launch on Android", + "type": "nativescript", + "platform": "android", + "request": "launch", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false, + "rebuild": true + }, + { + "name": "Attach on Android", + "type": "nativescript", + "platform": "android", + "request": "attach", + "appRoot": "${workspaceRoot}", + "sourceMaps": true, + "diagnosticLogging": false, + "emulator": false + } + ] } \ No newline at end of file diff --git a/apps/package.json b/apps/package.json index 4c13a5337d..bd1deeb5d1 100644 --- a/apps/package.json +++ b/apps/package.json @@ -16,6 +16,7 @@ "tns-core-modules": "2.1.0" }, "devDependencies": { + "tns-platform-declarations": "*", "babel-traverse": "6.10.4", "babel-types": "6.11.1", "babylon": "6.8.3", diff --git a/package.json b/package.json index 22d7e3633f..1846e2e77d 100644 --- a/package.json +++ b/package.json @@ -36,17 +36,16 @@ "tsc": "tsc", "tsc-w": "tsc --skipLibCheck -w", "dev-tsc-tns-platform-declarations": "tsc -p tns-platform-declarations", - "dev-tsc-tns-core-modules": "tsc -p tns-core-modules", "dev-tsc-tests": "tsc -p tests", "dev-tsc-apps": "tsc -p apps", - "dev-tsc-all": "npm run dev-tsc-tns-platform-declarations && npm run dev-tsc-tns-core-modules && npm run dev-tsc-tests && npm run dev-tsc-apps", + "dev-tsc-all": "npm run dev-tsc-tns-platform-declarations && npm run tsc && npm run dev-tsc-tests && npm run dev-tsc-apps", "dev-link-tns-platform-declarations": "cd tns-platform-declarations && npm link", "dev-link-tns-core-modules": "cd tns-core-modules && npm link", "dev-link-tests": "cd tests && npm link tns-platform-declarations && npm link tns-core-modules", "dev-link-apps": "cd apps && npm link tns-platform-declarations && npm link tns-core-modules", "dev-declarations": "npm run setup && rm -rf tns-platform-declarations/ios/objc* && TNS_TYPESCRIPT_DECLARATIONS_PATH=$PWD/tns-platform-declarations/ios/objc tns build ios --path tests", "test": "npm run test-android && npm run test-ios", - "pretest": "npm run setup && npm run dev-tsc-tns-core-modules && npm run dev-tsc-tests", + "pretest": "npm run setup && npm run tsc", "test-android": "tns run android --path tests --justlaunch", "test-ios": "tns run ios --path tests --justlaunch", "test-watch-android": "npm run pretest && concurrently --kill-others \"npm run tsc-tiw\" \"tns livesync android --path tests --watch\"", diff --git a/tests/.vscode/tasks.json b/tests/.vscode/tasks.json new file mode 100644 index 0000000000..926b1ddcd1 --- /dev/null +++ b/tests/.vscode/tasks.json @@ -0,0 +1,10 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "0.1.0", + "command": "tsc", + "isShellCommand": true, + "args": ["-p", "."], + "showOutput": "silent", + "problemMatcher": "$tsc" +} \ No newline at end of file diff --git a/tests/app/TKUnit.ts b/tests/app/TKUnit.ts index 418cefc112..c71b3b0a44 100644 --- a/tests/app/TKUnit.ts +++ b/tests/app/TKUnit.ts @@ -214,7 +214,7 @@ export function assertNotEqual(actual: any, expected: any, message?: string) { } } -export function assertEqual(actual: any, expected: any, message?: string) { +export function assertEqual(actual: T, expected: T, message?: string) { if (!types.isNullOrUndefined(actual) && !types.isNullOrUndefined(expected) && types.getClass(actual) === types.getClass(expected) @@ -222,11 +222,11 @@ export function assertEqual(actual: any, expected: any, message?: string) { // Use the equals method if (!actual.equals(expected)) { - throw new Error(`${message} Actual: <${actual}>(${typeof(actual)}). Expected: <${expected}>(${typeof(expected)})`); + throw new Error(`${message} Actual: <${actual}>(${typeof (actual)}). Expected: <${expected}>(${typeof (expected)})`); } } else if (actual !== expected) { - throw new Error(`${message} Actual: <${actual}>(${typeof(actual)}). Expected: <${expected}>(${typeof(expected)})`); + throw new Error(`${message} Actual: <${actual}>(${typeof (actual)}). Expected: <${expected}>(${typeof (expected)})`); } }; @@ -459,7 +459,7 @@ var doModalAndroid = function (quitLoop: () => boolean, timeoutSec: number) { } else { target.dispatchMessage(msg); } - + if (sdkVersion < 21) {//https://code.google.com/p/android-test-kit/issues/detail?id=84 msg.recycle(); } diff --git a/tests/app/data/observable-tests.ts b/tests/app/data/observable-tests.ts index d7fc4779d8..60238f943f 100644 --- a/tests/app/data/observable-tests.ts +++ b/tests/app/data/observable-tests.ts @@ -501,11 +501,11 @@ export function test_ObservableShouldEmitPropertyChangeWithSameObjectUsingWrappe export function test_CorrectEventArgsWhenWrappedValueIsUsed() { let testArray = [1]; let testObservable = new observable.Observable({ "property1": testArray}); - let actualArgsValue = 0; + let actualArgsValue; let propertyChangeHandler = function (args) { actualArgsValue = args.value; - } + testObservable.on(observable.Observable.propertyChangeEvent, propertyChangeHandler); testArray.push(2); diff --git a/tests/app/ui/image/image-tests.ts b/tests/app/ui/image/image-tests.ts index d00008c6f5..cac12ae909 100644 --- a/tests/app/ui/image/image-tests.ts +++ b/tests/app/ui/image/image-tests.ts @@ -1,8 +1,8 @@ -import {Image} from "ui/image"; -import {StackLayout} from "ui/layouts/stack-layout"; -import {GridLayout} from "ui/layouts/grid-layout"; -import {isIOS} from "platform"; -import {PropertyChangeData} from "data/observable"; +import { Image } from "ui/image"; +import { StackLayout } from "ui/layouts/stack-layout"; +import { GridLayout } from "ui/layouts/grid-layout"; +import { isIOS, isAndroid } from "platform"; +import { PropertyChangeData } from "data/observable"; import utils = require("utils/utils"); // import {target} from "../../TKUnit"; @@ -24,6 +24,11 @@ import color = require("color"); var imagePath = fs.path.join(__dirname, "../../logo.png"); +if (isAndroid) { + var imageModule = require("ui/image"); + imageModule.currentMode = imageModule.CacheMode.memory; // use memory cache only. +} + export var test_Image_Members = function () { var image = new ImageModule.Image(); TKUnit.assert(types.isUndefined(image.src), "Image.src is defined"); @@ -63,10 +68,10 @@ function runImageTest(done, image: ImageModule.Image, src: string) { testModel.off(ObservableModule.Observable.propertyChangeEvent, handler); try { - let imageIsLoaded = !!image.imageSource; + let imageIsLoaded = isIOS ? !!image.imageSource : true; TKUnit.assertTrue(!image.isLoading, "Image.isLoading should be false."); TKUnit.assertTrue(!testModel.get("imageIsLoading"), "imageIsLoading on viewModel should be false."); - TKUnit.assertTrue(imageIsLoaded, "imageIsLoading should be true."); + TKUnit.assertTrue(imageIsLoaded, "imageSource should be set."); if (done) { done(null); } @@ -86,6 +91,8 @@ function runImageTest(done, image: ImageModule.Image, src: string) { twoWay: true }, testModel); + let page = helper.getCurrentPage(); + page.content = image; image.src = src; testModel.on(ObservableModule.Observable.propertyChangeEvent, handler); if (done) { @@ -102,6 +109,7 @@ export var test_SettingImageSrc = function (done) { var image = new ImageModule.Image(); image.src = "https://www.google.com/images/errors/logo_sm_2.png"; // << img-create-src + (image).useCache = false; runImageTest(done, image, image.src) } @@ -125,6 +133,7 @@ export var test_SettingImageSrcToDataURI = function () { export var test_SettingImageSrcToFileWithinAppAsync = function (done) { var image = new ImageModule.Image(); + (image).useCache = false; image.loadMode = "async"; image.src = "~/logo.png"; runImageTest(done, image, image.src) @@ -140,7 +149,7 @@ export var test_SettingImageSrcToDataURIAsync = function (done) { // NOTE: This tests that setting multiple times src will not show the imageSource of a previous src value. // It however will never be reliable as to properly detect failure we need to use somewhat large timeout // waiting for imageSource to be set to the wrong value. -export var __test_SettingImageSrcTwiceMustNotMismatch = function(done) { +export var __test_SettingImageSrcTwiceMustNotMismatch = function (done) { var image = new Image(); image.on("propertyChange", (args: PropertyChangeData) => { if (args.propertyName === "isLoading" && args.value === false) { @@ -170,7 +179,7 @@ export var test_SettingStretch_AspectFit = function () { // << img-set-stretch var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var actualScaleType = testImage.android.getScaleType(); @@ -192,7 +201,7 @@ export var test_SettingStretch_Default = function () { image.imageSource = ImageSourceModule.fromFile(imagePath); var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var actualScaleType = testImage.android.getScaleType(); @@ -215,7 +224,7 @@ export var test_SettingStretch_AspectFill = function () { image.stretch = enumsModule.Stretch.aspectFill; var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var actualScaleType = testImage.android.getScaleType(); @@ -238,7 +247,7 @@ export var test_SettingStretch_Fill = function () { image.stretch = enumsModule.Stretch.fill; var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var actualScaleType = testImage.android.getScaleType(); @@ -261,7 +270,7 @@ export var test_SettingStretch_none = function () { image.stretch = enumsModule.Stretch.none; var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var actualScaleType = testImage.android.getScaleType(); @@ -284,21 +293,21 @@ function ios(func: T): T { export var test_SettingImageSourceWhenSizedToParentDoesNotRequestLayout = ios(() => { let host = new GridLayout(); - + let image = new Image(); host.width = 300; host.height = 300; host.addChild(image); - + let mainPage = helper.getCurrentPage(); mainPage.content = host; TKUnit.waitUntilReady(() => host.isLoaded); - + let called = false; image.requestLayout = () => called = true; image.src = "~/logo.png"; - + TKUnit.assertFalse(called, "image.requestLayout should not be called."); }); @@ -308,15 +317,15 @@ export var test_SettingImageSourceWhenFixedWidthAndHeightDoesNotRequestLayout = image.width = 100; image.height = 100; host.addChild(image); - + let mainPage = helper.getCurrentPage(); mainPage.content = host; TKUnit.waitUntilReady(() => host.isLoaded); - + let called = false; image.requestLayout = () => called = true; image.src = "~/logo.png"; - + TKUnit.assertFalse(called, "image.requestLayout should not be called."); }); @@ -324,21 +333,22 @@ export var test_SettingImageSourceWhenSizedToContentShouldInvalidate = ios(() => let host = new StackLayout(); let image = new Image(); host.addChild(image); - + let mainPage = helper.getCurrentPage(); mainPage.content = host; TKUnit.waitUntilReady(() => host.isLoaded); - + let called = false; image.requestLayout = () => called = true; image.src = "~/logo.png"; - + TKUnit.assertTrue(called, "image.requestLayout should be called."); }); -export var test_DimensionsAreRoundedAfterScale = function() { +export var test_DimensionsAreRoundedAfterScale = function () { let host = new StackLayout(); let image = new Image(); + (image).useCache = false; image.src = "~/ui/image/700x50.png"; let imageWidth = 700; let imageHeight = 50; @@ -347,12 +357,11 @@ export var test_DimensionsAreRoundedAfterScale = function() { let hostWidth = 320; host.width = hostWidth / density; host.height = hostWidth / density; - host.addChild(image); + host.addChild(image); let mainPage = helper.getCurrentPage(); mainPage.content = host; - TKUnit.waitUntilReady(() => host.isLoaded); - TKUnit.waitUntilReady(() => image.isLayoutValid); - + TKUnit.waitUntilReady(() => host.isLayoutValid); + let scale = hostWidth / imageWidth; let expectedHeight = Math.round(imageHeight * scale); TKUnit.assertEqual(image.getMeasuredWidth(), hostWidth, "Actual width is different from expected width."); @@ -365,7 +374,7 @@ export var test_tintColor = function () { image.imageSource = ImageSourceModule.fromFile(imagePath); var testFunc = function (views: Array) { - var testImage = views[0]; + var testImage = views[0]; if (image.android) { var tintColor = testImage.android.getColorFilter(); diff --git a/tests/app/ui/styling/style-properties-tests.ts b/tests/app/ui/styling/style-properties-tests.ts index abc9055a3b..1d8003bbb1 100644 --- a/tests/app/ui/styling/style-properties-tests.ts +++ b/tests/app/ui/styling/style-properties-tests.ts @@ -756,7 +756,7 @@ export function test_border_color() { let blue = new color.Color("blue"); let hex = blue.hex; testView.style.borderColor = hex; - TKUnit.assertEqual(testView.style.borderColor, blue, "all"); + TKUnit.assertEqual((testView.style.borderColor), blue, "all"); TKUnit.assertEqual(testView.style.borderTopColor, blue, "top"); TKUnit.assertEqual(testView.style.borderRightColor, blue, "right"); TKUnit.assertEqual(testView.style.borderBottomColor, blue, "bottom"); @@ -774,7 +774,7 @@ export function test_border_width() { TKUnit.assertEqual(testView.style.borderLeftWidth, 10, "left"); testView.style.borderWidth = "20"; - TKUnit.assertEqual(testView.style.borderWidth, 20, "all"); + TKUnit.assertEqual((testView.style.borderWidth), 20, "all"); TKUnit.assertEqual(testView.style.borderTopWidth, 20, "top"); TKUnit.assertEqual(testView.style.borderRightWidth, 20, "right"); TKUnit.assertEqual(testView.style.borderBottomWidth, 20, "bottom"); @@ -792,7 +792,7 @@ export function test_border_radius() { TKUnit.assertEqual(testView.style.borderBottomLeftRadius, 10, "left"); testView.style.borderRadius = "20"; - TKUnit.assertEqual(testView.style.borderRadius, 20, "all"); + TKUnit.assertEqual((testView.style.borderRadius), 20, "all"); TKUnit.assertEqual(testView.style.borderTopLeftRadius, 20, "top"); TKUnit.assertEqual(testView.style.borderTopRightRadius, 20, "right"); TKUnit.assertEqual(testView.style.borderBottomRightRadius, 20, "bottom"); diff --git a/tests/package.json b/tests/package.json index d4506c6095..70909223f1 100644 --- a/tests/package.json +++ b/tests/package.json @@ -16,6 +16,7 @@ "tns-core-modules": "2.3.0" }, "devDependencies": { + "tns-platform-declarations": "*", "babel-traverse": "6.9.0", "babel-types": "6.9.0", "babylon": "6.8.0", diff --git a/tns-core-modules/ui/image/image-common.ts b/tns-core-modules/ui/image/image-common.ts index 02bf4fec4b..4961091dbd 100644 --- a/tns-core-modules/ui/image/image-common.ts +++ b/tns-core-modules/ui/image/image-common.ts @@ -96,7 +96,7 @@ export class Image extends view.View implements definition.Image { /** * @internal */ - _createImageSourceFromSrc(): void { + public _createImageSourceFromSrc(): void { var value = this.src; if (types.isString(value)) { value = value.trim(); @@ -170,4 +170,4 @@ export class Image extends view.View implements definition.Image { this._setValue(Image.isLoadingProperty, false); } } -} +} \ No newline at end of file diff --git a/tns-core-modules/ui/image/image.android.ts b/tns-core-modules/ui/image/image.android.ts index 3d5ae075e7..a71b0bd199 100644 --- a/tns-core-modules/ui/image/image.android.ts +++ b/tns-core-modules/ui/image/image.android.ts @@ -1,27 +1,36 @@ import imageCommon = require("./image-common"); import dependencyObservable = require("ui/core/dependency-observable"); import proxy = require("ui/core/proxy"); -import * as enumsModule from "ui/enums"; import style = require("ui/styling/style"); import view = require("ui/core/view"); +import enums = require("ui/enums"); +import types = require("utils/types"); +import imageSource = require("image-source"); +import utils = require("utils/utils"); +import * as fs from "file-system"; +import * as application from "application"; global.moduleMerge(imageCommon, exports); -var enums: typeof enumsModule; -function ensureEnums() { - if (!enums) { - enums = require("ui/enums"); - } +const FILE_PREFIX = "file:///"; +let ASYNC = "async"; +let imageFetcher: org.nativescript.widgets.image.Fetcher; +let imageCache: org.nativescript.widgets.image.Cache; + +export enum CacheMode { + none, + memory, + diskAndMemory } +export let currentCacheMode: CacheMode; + function onStretchPropertyChanged(data: dependencyObservable.PropertyChangeData) { - var image = data.object; + let image = data.object; if (!image.android) { return; } - ensureEnums(); - switch (data.newValue) { case enums.Stretch.aspectFit: image.android.setScaleType(android.widget.ImageView.ScaleType.FIT_CENTER); @@ -48,6 +57,34 @@ function onImageSourcePropertyChanged(data: dependencyObservable.PropertyChangeD image._setNativeImage(data.newValue); } +export function initImageCache(context: android.content.Context, mode = CacheMode.diskAndMemory, memoryCacheSize: number = 0.25, diskCacheSize: number = 10 * 1024 * 1024): void { + if (currentCacheMode === mode) { + return; + } + + currentCacheMode = mode; + if (!imageFetcher) { + imageFetcher = new org.nativescript.widgets.image.Fetcher(context); + } + + // Disable cache. + if (mode === CacheMode.none) { + if (imageCache != null && imageFetcher != null) { + imageFetcher.clearCache(); + } + } + + let params = new org.nativescript.widgets.image.Cache.CacheParams(context, "_imageCache"); + params.setMemCacheSizePercent(memoryCacheSize); // Set memory cache to % of app memory + params.diskCacheEnabled = mode === CacheMode.diskAndMemory; + params.diskCacheSize = diskCacheSize; + imageCache = org.nativescript.widgets.image.Cache.getInstance(params); + imageFetcher.addImageCache(imageCache); + imageFetcher.initCache(); +} + +initImageCache(application.android.nativeApp); + // register the setNativeValue callback (imageCommon.Image.imageSourceProperty.metadata).onSetNativeValue = onImageSourcePropertyChanged; (imageCommon.Image.stretchProperty.metadata).onSetNativeValue = onStretchPropertyChanged; @@ -55,21 +92,79 @@ function onImageSourcePropertyChanged(data: dependencyObservable.PropertyChangeD export class Image extends imageCommon.Image { private _android: org.nativescript.widgets.ImageView; + public decodeWidth = 0; + public decodeHeight = 0; + public useCache = true; + get android(): org.nativescript.widgets.ImageView { return this._android; } public _createUI() { this._android = new org.nativescript.widgets.ImageView(this._context); + this._createImageSourceFromSrc(); } public _setNativeImage(nativeImage: any) { - let rotation = (nativeImage && nativeImage.rotationAngle) ? nativeImage.rotationAngle : 0 ; + if (!nativeImage) { + return; + } + + let rotation = nativeImage.rotationAngle ? nativeImage.rotationAngle : 0 ; if (rotation > 0) { this.android.setRotationAngle(rotation); } this.android.setImageBitmap(nativeImage.android); } + + public _createImageSourceFromSrc() { + let imageView = this._android; + if (!imageView) { + return; + } + + let value = this.src; + let async = this.loadMode === ASYNC; + let owner = new WeakRef(this); + let listener = new org.nativescript.widgets.image.Worker.OnImageLoadedListener({ + onImageLoaded: function (success) { + let that = owner.get(); + if (that) { + that._setValue(Image.isLoadingProperty, false); + } + } + }); + + this._resetValue(Image.imageSourceProperty); + if (types.isString(value)) { + value = value.trim(); + this._setValue(Image.isLoadingProperty, true); + + if (utils.isDataURI(value)) { + // TODO: Check with runtime what should we do in case of base64 string. + super._createImageSourceFromSrc(); + } + else if (imageSource.isFileOrResourcePath(value)) { + if (value.indexOf(utils.RESOURCE_PREFIX) === 0) { + imageFetcher.loadImage(value, imageView, this.decodeWidth, this.decodeHeight, this.useCache, async, listener); + } + else { + let fileName = value; + if (fileName.indexOf("~/") === 0) { + fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", "")); + } + + imageFetcher.loadImage(FILE_PREFIX + fileName, imageView, this.decodeWidth, this.decodeHeight, this.useCache, async, listener); + } + } + else { + // For backwards compatibility http always use async loading. + imageFetcher.loadImage(value, imageView, this.decodeWidth, this.decodeHeight, this.useCache, true, listener); + } + } else { + super._createImageSourceFromSrc(); + } + } } export class ImageStyler implements style.Styler { @@ -91,4 +186,4 @@ export class ImageStyler implements style.Styler { } } -ImageStyler.registerHandlers(); +ImageStyler.registerHandlers(); \ No newline at end of file diff --git a/tns-platform-declarations/android/declarations.d.ts b/tns-platform-declarations/android/declarations.d.ts index 7c25922227..6477cdcfa6 100644 --- a/tns-platform-declarations/android/declarations.d.ts +++ b/tns-platform-declarations/android/declarations.d.ts @@ -53,54 +53,4 @@ declare module android { } } } -} - -declare module org { - export module nativescript { - export module widgets { - export module Async { - export class CompleteCallback { - constructor(implementation: ICompleteCallback); - onComplete(result: Object, context: Object): void; - } - - export interface ICompleteCallback { - onComplete(result: Object, context: Object): void; - } - - export module Image { - export function download(url: string, callback: CompleteCallback, context: any); - } - - export module Http { - export class KeyValuePair { - public key: string; - public value: string; - constructor(key: string, value: string); - } - - export class RequestOptions { - public url: string; - public method: string; - public headers: java.util.ArrayList; - public content: string; - public timeout: number; - public screenWidth: number; - public screenHeight: number; - } - - export class RequestResult { - public raw: java.io.ByteArrayOutputStream; - public headers: java.util.ArrayList; - public statusCode: number; - public responseAsString: string; - public responseAsImage: android.graphics.Bitmap; - public error: java.lang.Exception; - } - - export function MakeRequest(options: RequestOptions, callback: CompleteCallback, context: any); - } - } - } - } } \ No newline at end of file diff --git a/tns-platform-declarations/android/org.nativescript.widgets.d.ts b/tns-platform-declarations/android/org.nativescript.widgets.d.ts index a548b214c2..85367e5dee 100644 --- a/tns-platform-declarations/android/org.nativescript.widgets.d.ts +++ b/tns-platform-declarations/android/org.nativescript.widgets.d.ts @@ -1,6 +1,50 @@ declare module org { module nativescript { module widgets { + export module Async { + export class CompleteCallback { + constructor(implementation: ICompleteCallback); + onComplete(result: Object, context: Object): void; + } + + export interface ICompleteCallback { + onComplete(result: Object, context: Object): void; + } + + export module Image { + export function download(url: string, callback: CompleteCallback, context: any); + } + + export module Http { + export class KeyValuePair { + public key: string; + public value: string; + constructor(key: string, value: string); + } + + export class RequestOptions { + public url: string; + public method: string; + public headers: java.util.ArrayList; + public content: string; + public timeout: number; + public screenWidth: number; + public screenHeight: number; + } + + export class RequestResult { + public raw: java.io.ByteArrayOutputStream; + public headers: java.util.ArrayList; + public statusCode: number; + public responseAsString: string; + public responseAsImage: android.graphics.Bitmap; + public error: java.lang.Exception; + } + + export function MakeRequest(options: RequestOptions, callback: CompleteCallback, context: any); + } + } + export class BorderDrawable extends android.graphics.drawable.ColorDrawable { constructor(density: number); public refresh( @@ -8,19 +52,19 @@ borderRightColor: number, borderBottomColor: number, borderLeftColor: number, - + borderTopWidth: number, borderRightWidth: number, borderBottomWidth: number, borderLeftWidth: number, - + borderTopLeftRadius: number, borderTopRightRadius: number, borderBottomRightRadius: number, borderBottomLeftRadius: number, - + clipPath: string, - + backgroundColor: number, backgroundImage: android.graphics.Bitmap, backgroundRepeat: string, @@ -29,39 +73,39 @@ backgroundSize: string, backgroundSizeParsedCSSValues: native.Array ); - + public getBorderTopColor(): number; public getBorderRightColor(): number; public getBorderBottomColor(): number; public getBorderLeftColor(): number; public getUniformBorderColor(): number; - + public getBorderTopWidth(): number; public getBorderRightWidth(): number; public getBorderBottomWidth(): number; public getBorderLeftWidth(): number; public getUniformBorderWidth(): number; - + public getBorderTopLeftRadius(): number; public getBorderTopRightRadius(): number; public getBorderBottomRightRadius(): number; public getBorderBottomLeftRadius(): number; public getUniformBorderRadius(): number; - + public getClipPath(): string; - + public getBackgroundColor(): number; public getBackgroundImage(): android.graphics.Bitmap; public getBackgroundRepeat(): string; public getBackgroundPosition(): string; public getBackgroundSize(): string; - + public hasUniformBorderColor(): boolean; public hasUniformBorderWidth(): boolean; public hasUniformBorderRadius(): boolean; public hasUniformBorder(): boolean; } - + export class CSSValue { constructor(type: string, str: string, unit: string, value: number); public getType(): string; @@ -69,7 +113,7 @@ public getUnit(): string; public getValue(): number; } - + export class CommonLayoutParams extends android.widget.FrameLayout.LayoutParams { constructor(); @@ -134,7 +178,7 @@ horizontal, vertical } - + export class OriginPoint { public static setX(view: android.view.View, value: number); public static setY(view: android.view.View, value: number); @@ -309,6 +353,48 @@ iconId: number; iconDrawable: android.graphics.drawable.Drawable; } + + export namespace image { + + export class Cache { + private constructor(); + public static getInstance(cacheParams: Cache.CacheParams): Cache; + } + + export class Worker { + + } + + export namespace Worker { + interface IOnImageLoadedListener { + onImageLoaded(success: boolean): void; + } + + export class OnImageLoadedListener implements IOnImageLoadedListener { + constructor(implementation: IOnImageLoadedListener); + public onImageLoaded(success: boolean): void; + } + } + + export class Fetcher extends Worker { + constructor(context: android.content.Context); + public addImageCache(cache: Cache): void; + public initCache(): void; + public clearCache(): void; + public loadImage(data: Object, imageView: ImageView, + decodeWidth: number, decodeHeight: number, useCache: boolean, async: boolean, + listener: Worker.IOnImageLoadedListener): void; + } + + export namespace Cache { + export class CacheParams { + constructor(context: android.content.Context, diskCacheDirectoryName: string); + public setMemCacheSizePercent(percent: number): void; + public diskCacheEnabled: boolean; + public diskCacheSize: number; + } + } + } } } } diff --git a/tns-platform-declarations/package.json b/tns-platform-declarations/package.json index aea870b4fc..66815a71c0 100644 --- a/tns-platform-declarations/package.json +++ b/tns-platform-declarations/package.json @@ -1,12 +1,6 @@ { "name": "tns-platform-declarations", "version": "2.4.0", - "nativescript": { - "platforms": { - "ios": "2.4.0", - "android": "2.4.0" - } - }, "description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects", "main": "", "scripts": {