@nativescript/core
Version:
A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.
503 lines • 18.8 kB
JavaScript
import { ActionItemBase, ActionBarBase, isVisible, flatProperty, traceMissingIcon, androidContentInsetLeftProperty, androidContentInsetRightProperty } from './action-bar-common';
import { View } from '../core/view';
import { Color } from '../../color';
import { layout, RESOURCE_PREFIX, isFontIconURI } from '../../utils';
import { colorProperty } from '../styling/style-properties';
import { ImageSource } from '../../image-source';
import { Application } from '../../application';
import { isAccessibilityServiceEnabled, updateContentDescription } from '../../accessibility';
import { SDK_VERSION } from '../../utils/constants';
export * from './action-bar-common';
const R_ID_HOME = 0x0102002c;
const ACTION_ITEM_ID_OFFSET = 10000;
const DEFAULT_ELEVATION = 4;
let AppCompatTextView;
let actionItemIdGenerator = ACTION_ITEM_ID_OFFSET;
function generateItemId() {
actionItemIdGenerator++;
return actionItemIdGenerator;
}
function loadActionIconDrawableOrResourceId(item) {
const itemIcon = item.icon;
const itemStyle = item.style;
let drawableOrId = null;
if (isFontIconURI(itemIcon)) {
const fontIconCode = itemIcon.split('//')[1];
const font = itemStyle.fontInternal;
const color = itemStyle.color;
const is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color);
if (is && is.android) {
drawableOrId = new android.graphics.drawable.BitmapDrawable(appResources, is.android);
}
}
else {
drawableOrId = getDrawableOrResourceId(itemIcon, appResources);
}
if (!drawableOrId) {
traceMissingIcon(itemIcon);
}
return drawableOrId;
}
let appResources;
let MenuItemClickListener;
function initializeMenuItemClickListener() {
if (MenuItemClickListener) {
return;
}
AppCompatTextView = androidx.appcompat.widget.AppCompatTextView;
var MenuItemClickListenerImpl = /** @class */ (function (_super) {
__extends(MenuItemClickListenerImpl, _super);
function MenuItemClickListenerImpl(owner) {
var _this = _super.call(this) || this;
_this.owner = owner;
return global.__native(_this);
}
MenuItemClickListenerImpl.prototype.onMenuItemClick = function (item) {
var itemId = item.getItemId();
return this.owner._onAndroidItemSelected(itemId);
};
var _a;
MenuItemClickListenerImpl = __decorate([
Interfaces([androidx.appcompat.widget.Toolbar.OnMenuItemClickListener]),
__metadata("design:paramtypes", [typeof (_a = typeof ActionBar !== "undefined" && ActionBar) === "function" ? _a : Object])
], MenuItemClickListenerImpl);
return MenuItemClickListenerImpl;
}(java.lang.Object));
MenuItemClickListener = MenuItemClickListenerImpl;
appResources = Application.android.context.getResources();
}
export class ActionItem extends ActionItemBase {
constructor() {
super();
this._androidPosition = {
position: 'actionBar',
systemIcon: undefined,
};
this._itemId = generateItemId();
}
// @ts-ignore
get android() {
return this._androidPosition;
}
set android(value) {
throw new Error('ActionItem.android is read-only');
}
_getItemId() {
return this._itemId;
}
}
export class AndroidActionBarSettings {
constructor(actionBar) {
this._iconVisibility = 'auto';
this._actionBar = actionBar;
}
get icon() {
return this._icon;
}
set icon(value) {
if (value !== this._icon) {
this._icon = value;
this._actionBar._onIconPropertyChanged();
}
}
get iconVisibility() {
return this._iconVisibility;
}
set iconVisibility(value) {
if (value !== this._iconVisibility) {
this._iconVisibility = value;
this._actionBar._onIconPropertyChanged();
}
}
}
export class NavigationButton extends ActionItem {
}
export class ActionBar extends ActionBarBase {
constructor() {
super();
this._android = new AndroidActionBarSettings(this);
}
get android() {
return this._android;
}
_addChildFromBuilder(name, value) {
if (value instanceof NavigationButton) {
this.navigationButton = value;
}
else if (value instanceof ActionItem) {
this.actionItems?.addItem(value);
}
else if (value instanceof View) {
this.titleView = value;
}
}
createNativeView() {
return new androidx.appcompat.widget.Toolbar(this._context);
}
initNativeView() {
super.initNativeView();
const nativeView = this.nativeViewProtected;
initializeMenuItemClickListener();
const menuItemClickListener = new MenuItemClickListener(this);
nativeView.setOnMenuItemClickListener(menuItemClickListener);
nativeView.menuItemClickListener = menuItemClickListener;
}
disposeNativeView() {
if (this.nativeViewProtected?.menuItemClickListener) {
this.nativeViewProtected.menuItemClickListener.owner = null;
}
super.disposeNativeView();
}
onLoaded() {
super.onLoaded();
this.update();
}
get needsNativeDrawableFill() {
return true;
}
update() {
if (!this.nativeViewProtected) {
return;
}
const page = this.page;
if (!page.frame || !page.frame._getNavBarVisible(page)) {
this.nativeViewProtected.setVisibility(android.view.View.GONE);
// If action bar is hidden - no need to fill it with items.
return;
}
this.nativeViewProtected.setVisibility(android.view.View.VISIBLE);
// Add menu items
this._addActionItems();
// Set title
this._updateTitleAndTitleView();
// Set home icon
this._updateIcon();
// Set navigation button
this._updateNavigationButton();
}
_onAndroidItemSelected(itemId) {
// Handle home button
if (this.navigationButton && itemId === R_ID_HOME) {
this.navigationButton._raiseTap();
return true;
}
// Find item with the right ID;
let menuItem = undefined;
const items = this.actionItems?.getItems() ?? [];
for (let i = 0; i < items.length; i++) {
if (items[i]._getItemId() === itemId) {
menuItem = items[i];
break;
}
}
if (menuItem) {
menuItem._raiseTap();
return true;
}
return false;
}
_updateNavigationButton() {
const navButton = this.navigationButton;
if (navButton && isVisible(navButton)) {
const systemIcon = navButton.android.systemIcon;
if (systemIcon !== undefined) {
// Try to look in the system resources.
const systemResourceId = getSystemResourceId(systemIcon);
if (systemResourceId) {
this.nativeViewProtected.setNavigationIcon(systemResourceId);
}
}
else if (navButton.icon) {
const drawableOrId = loadActionIconDrawableOrResourceId(navButton);
if (drawableOrId) {
this.nativeViewProtected.setNavigationIcon(drawableOrId);
}
}
// Set navigation content description, used by screen readers for the vision-impaired users
this.nativeViewProtected.setNavigationContentDescription(navButton.text || null);
const navBtn = new WeakRef(navButton);
this.nativeViewProtected.setNavigationOnClickListener(new android.view.View.OnClickListener({
onClick: function (v) {
const owner = navBtn?.get();
if (owner) {
owner._raiseTap();
}
},
}));
}
else {
this.nativeViewProtected.setNavigationIcon(null);
}
}
_updateIcon() {
const visibility = getIconVisibility(this.android.iconVisibility);
if (visibility) {
const icon = this.android.icon;
if (icon !== undefined) {
const drawableOrId = getDrawableOrResourceId(icon, appResources);
if (drawableOrId) {
this.nativeViewProtected.setLogo(drawableOrId);
}
else {
traceMissingIcon(icon);
}
}
else {
const defaultIcon = Application.android.nativeApp.getApplicationInfo().icon;
this.nativeViewProtected.setLogo(defaultIcon);
}
}
else {
this.nativeViewProtected.setLogo(null);
}
}
_updateTitleAndTitleView() {
if (!this.titleView) {
// No title view - show the title
const title = this.title;
if (title !== undefined) {
this.nativeViewProtected.setTitle(title);
}
else {
const appContext = Application.android.context;
const appInfo = appContext.getApplicationInfo();
const appLabel = appContext.getPackageManager().getApplicationLabel(appInfo);
if (appLabel) {
this.nativeViewProtected.setTitle(appLabel);
}
}
}
// Update content description for the screen reader.
updateContentDescription(this, true);
}
_addActionItems() {
const menu = this.nativeViewProtected.getMenu();
const items = this.actionItems?.getVisibleItems() ?? [];
menu.clear();
for (let i = 0; i < items.length; i++) {
const item = items[i];
const menuItem = menu.add(android.view.Menu.NONE, item._getItemId(), android.view.Menu.NONE, item.text + '');
if (item.actionView && item.actionView.android) {
// With custom action view, the menuitem cannot be displayed in a popup menu.
item.android.position = 'actionBar';
menuItem.setActionView(item.actionView.android);
ActionBar._setOnClickListener(item);
}
else if (item.android.systemIcon) {
// Try to look in the system resources.
const systemResourceId = getSystemResourceId(item.android.systemIcon);
if (systemResourceId) {
menuItem.setIcon(systemResourceId);
}
}
else if (item.icon) {
const drawableOrId = loadActionIconDrawableOrResourceId(item);
if (drawableOrId) {
menuItem.setIcon(drawableOrId);
}
}
const showAsAction = getShowAsAction(item);
menuItem.setShowAsAction(showAsAction);
}
}
static _setOnClickListener(item) {
const weakRef = new WeakRef(item);
item.actionView.android.setOnClickListener(new android.view.View.OnClickListener({
onClick: function (v) {
const owner = weakRef?.get();
if (owner) {
owner._raiseTap();
}
},
}));
}
_onTitlePropertyChanged() {
if (this.nativeViewProtected) {
this._updateTitleAndTitleView();
}
}
_onIconPropertyChanged() {
if (this.nativeViewProtected) {
this._updateIcon();
}
}
_addViewToNativeVisualTree(child, atIndex = Number.MAX_VALUE) {
super._addViewToNativeVisualTree(child);
if (this.nativeViewProtected && child.nativeViewProtected) {
if (atIndex >= this.nativeViewProtected.getChildCount()) {
this.nativeViewProtected.addView(child.nativeViewProtected);
}
else {
this.nativeViewProtected.addView(child.nativeViewProtected, atIndex);
}
return true;
}
return false;
}
_removeViewFromNativeVisualTree(child) {
super._removeViewFromNativeVisualTree(child);
if (this.nativeViewProtected && child.nativeViewProtected) {
this.nativeViewProtected.removeView(child.nativeViewProtected);
}
}
[colorProperty.getDefault]() {
const nativeView = this.nativeViewProtected;
if (!defaultTitleTextColor) {
let tv = getAppCompatTextView(nativeView);
if (!tv) {
const title = nativeView.getTitle();
// setTitle will create AppCompatTextView internally;
nativeView.setTitle('');
tv = getAppCompatTextView(nativeView);
if (title) {
// restore title.
nativeView.setTitle(title);
}
}
// Fallback to hardcoded falue if we don't find TextView instance...
// using new TextView().getTextColors().getDefaultColor() returns different value: -1979711488
defaultTitleTextColor = tv ? tv.getTextColors().getDefaultColor() : -570425344;
}
return defaultTitleTextColor;
}
[colorProperty.setNative](value) {
const color = value instanceof Color ? value.android : value;
this.nativeViewProtected.setTitleTextColor(color);
}
[flatProperty.setNative](value) {
const compat = androidx.core.view.ViewCompat;
if (compat.setElevation) {
if (value) {
compat.setElevation(this.nativeViewProtected, 0);
}
else {
const val = DEFAULT_ELEVATION * layout.getDisplayDensity();
compat.setElevation(this.nativeViewProtected, val);
}
}
}
[androidContentInsetLeftProperty.setNative]() {
if (SDK_VERSION >= 21) {
this.nativeViewProtected.setContentInsetsAbsolute(this.effectiveContentInsetLeft, this.effectiveContentInsetRight);
}
}
[androidContentInsetRightProperty.setNative]() {
if (SDK_VERSION >= 21) {
this.nativeViewProtected.setContentInsetsAbsolute(this.effectiveContentInsetLeft, this.effectiveContentInsetRight);
}
}
accessibilityScreenChanged() {
if (!isAccessibilityServiceEnabled()) {
return;
}
const nativeView = this.nativeViewProtected;
if (!nativeView) {
return;
}
const originalFocusableState = SDK_VERSION >= 26 && nativeView.getFocusable();
const originalImportantForAccessibility = nativeView.getImportantForAccessibility();
const originalIsAccessibilityHeading = SDK_VERSION >= 28 && nativeView.isAccessibilityHeading();
try {
nativeView.setFocusable(false);
nativeView.setImportantForAccessibility(android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO);
let announceView = null;
const numChildren = nativeView.getChildCount();
for (let i = 0; i < numChildren; i += 1) {
const childView = nativeView.getChildAt(i);
if (!childView) {
continue;
}
childView.setFocusable(true);
if (childView instanceof androidx.appcompat.widget.AppCompatTextView) {
announceView = childView;
if (SDK_VERSION >= 28) {
announceView.setAccessibilityHeading(true);
}
}
}
if (!announceView) {
announceView = nativeView;
}
announceView.setFocusable(true);
announceView.setImportantForAccessibility(android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES);
announceView.sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED);
announceView.sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
}
catch {
// ignore
}
finally {
setTimeout(() => {
// Reset status after the focus have been reset.
const localNativeView = this.nativeViewProtected;
if (!localNativeView) {
return;
}
if (SDK_VERSION >= 28) {
nativeView.setAccessibilityHeading(originalIsAccessibilityHeading);
}
if (SDK_VERSION >= 26) {
localNativeView.setFocusable(originalFocusableState);
}
localNativeView.setImportantForAccessibility(originalImportantForAccessibility);
});
}
}
}
function getAppCompatTextView(toolbar) {
for (let i = 0, count = toolbar.getChildCount(); i < count; i++) {
const child = toolbar.getChildAt(i);
if (child instanceof AppCompatTextView) {
return child;
}
}
return null;
}
ActionBar.prototype.recycleNativeView = 'auto';
let defaultTitleTextColor;
function getDrawableOrResourceId(icon, resources) {
if (typeof icon !== 'string') {
return null;
}
let result = null;
if (icon.indexOf(RESOURCE_PREFIX) === 0) {
const resourceId = resources.getIdentifier(icon.substr(RESOURCE_PREFIX.length), 'drawable', Application.android.packageName);
if (resourceId > 0) {
result = resourceId;
}
}
else {
let drawable;
const is = ImageSource.fromFileOrResourceSync(icon);
if (is) {
drawable = new android.graphics.drawable.BitmapDrawable(appResources, is.android);
}
result = drawable;
}
return result;
}
function getShowAsAction(menuItem) {
switch (menuItem.android.position) {
case 'actionBarIfRoom':
return android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
case 'popup':
return android.view.MenuItem.SHOW_AS_ACTION_NEVER;
case 'actionBar':
default:
return android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
}
}
function getIconVisibility(iconVisibility) {
switch (iconVisibility) {
case 'always':
return true;
case 'auto':
case 'never':
default:
return false;
}
}
function getSystemResourceId(systemIcon) {
return android.content.res.Resources.getSystem().getIdentifier(systemIcon, 'drawable', 'android');
}
//# sourceMappingURL=index.android.js.map