import { View } from "./background-common"; import { isNullOrUndefined, isFunction, getClass } from "utils/types"; import { CacheLayerType } from "utils/utils"; import { parse } from "css-value"; export * from "./background-common" // TODO: Change this implementation to use // We are using "ad" here to avoid namespace collision with the global android object export module ad { let SDK: number; function getSDK() { if (!SDK) { SDK = android.os.Build.VERSION.SDK_INT; } return SDK; } let _defaultBackgrounds = new Map(); function isSetColorFilterOnlyWidget(nativeView: android.view.View): boolean { return ( nativeView instanceof android.widget.Button || (nativeView instanceof android.support.v7.widget.Toolbar && getSDK() >= 21 // There is an issue with the DrawableContainer which was fixed for API version 21 and above: https://code.google.com/p/android/issues/detail?id=60183 ) ); } export function onBackgroundOrBorderPropertyChanged(view: View) { let nativeView = view._nativeView; if (!nativeView) { return; } let background = view.style.backgroundInternal; let backgroundDrawable = nativeView.getBackground(); let cache = view._nativeView; if (isSetColorFilterOnlyWidget(nativeView) && !isNullOrUndefined(backgroundDrawable) && isFunction(backgroundDrawable.setColorFilter) && !background.hasBorderWidth() && !background.hasBorderRadius() && !background.clipPath && isNullOrUndefined(background.image) && !isNullOrUndefined(background.color)) { let backgroundColor = (backgroundDrawable).backgroundColor = background.color.android; backgroundDrawable.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN); (backgroundDrawable).backgroundColor = backgroundColor; } else if (!background.isEmpty()) { if (!(backgroundDrawable instanceof org.nativescript.widgets.BorderDrawable)) { let viewClass = getClass(view); if (!isSetColorFilterOnlyWidget(nativeView) && !_defaultBackgrounds.has(viewClass)) { _defaultBackgrounds.set(viewClass, nativeView.getBackground()); } backgroundDrawable = new org.nativescript.widgets.BorderDrawable(1, view.toString()); refreshBorderDrawable(view, backgroundDrawable); if (getSDK() >= 16) { nativeView.setBackground(backgroundDrawable); } else { nativeView.setBackgroundDrawable(backgroundDrawable); } } else { refreshBorderDrawable(view, backgroundDrawable); } if ((background.hasBorderWidth() || background.hasBorderRadius() || background.clipPath) && getSDK() < 18) { // Switch to software because of unsupported canvas methods if hardware acceleration is on: // http://developer.android.com/guide/topics/graphics/hardware-accel.html cache.layerType = cache.getLayerType(); cache.setLayerType(android.view.View.LAYER_TYPE_SOFTWARE, null); } } else { // reset the value with the default native value if (nativeView instanceof android.widget.Button) { let nativeButton = new android.widget.Button(nativeView.getContext()); if (getSDK() >= 16) { nativeView.setBackground(nativeButton.getBackground()); } else { nativeView.setBackgroundDrawable(nativeButton.getBackground()); } } else { let viewClass = getClass(view); if (_defaultBackgrounds.has(viewClass)) { if (getSDK() >= 16) { nativeView.setBackground(_defaultBackgrounds.get(viewClass)); } else { nativeView.setBackgroundDrawable(_defaultBackgrounds.get(viewClass)); } } } if (cache.layerType !== undefined) { cache.setLayerType(cache.layerType, null); cache.layerType = undefined; } } // TODO: Can we move BorderWidths as separate native setter? // This way we could skip setPadding if borderWidth is not changed. let leftPadding = Math.round(view.effectiveBorderLeftWidth + view.effectivePaddingLeft); let topPadding = Math.round(view.effectiveBorderTopWidth + view.effectivePaddingTop); let rightPadding = Math.round(view.effectiveBorderRightWidth + view.effectivePaddingRight); let bottomPadding = Math.round(view.effectiveBorderBottomWidth + view.effectivePaddingBottom); nativeView.setPadding( leftPadding, topPadding, rightPadding, bottomPadding ); } } function refreshBorderDrawable(view: View, borderDrawable: org.nativescript.widgets.BorderDrawable) { let background = view.style.backgroundInternal; if (background) { let backgroundPositionParsedCSSValues: native.Array = null; let backgroundSizeParsedCSSValues: native.Array = null; if (background.position) { backgroundPositionParsedCSSValues = createNativeCSSValueArray(background.position); } if (background.size) { backgroundSizeParsedCSSValues = createNativeCSSValueArray(background.size); } let blackColor = android.graphics.Color.BLACK; borderDrawable.refresh( (background.borderTopColor && background.borderTopColor.android !== undefined) ? background.borderTopColor.android : blackColor, (background.borderRightColor && background.borderRightColor.android !== undefined) ? background.borderRightColor.android : blackColor, (background.borderBottomColor && background.borderBottomColor.android !== undefined) ? background.borderBottomColor.android : blackColor, (background.borderLeftColor && background.borderLeftColor.android !== undefined) ? background.borderLeftColor.android : blackColor, background.borderTopWidth, background.borderRightWidth, background.borderBottomWidth, background.borderLeftWidth, background.borderTopLeftRadius, background.borderTopRightRadius, background.borderBottomRightRadius, background.borderBottomLeftRadius, background.clipPath, (background.color && background.color.android) ? background.color.android : 0, (background.image && background.image.android) ? background.image.android : null, background.repeat, background.position, backgroundPositionParsedCSSValues, background.size, backgroundSizeParsedCSSValues ); //console.log(`>>> ${borderDrawable.toDebugString()}`); } } function createNativeCSSValueArray(css: string): native.Array { if (!css) { return null; } let cssValues = parse(css); let nativeArray = Array.create(org.nativescript.widgets.CSSValue, cssValues.length); for (let i = 0, length = cssValues.length; i < length; i++) { nativeArray[i] = new org.nativescript.widgets.CSSValue( cssValues[i].type, cssValues[i].string, cssValues[i].unit, cssValues[i].value ); } return nativeArray; }