1 | import { ActionItemBase, ActionBarBase, isVisible, flatProperty, traceMissingIcon, androidContentInsetLeftProperty, androidContentInsetRightProperty } from './action-bar-common';
|
2 | import { View } from '../core/view';
|
3 | import { Color } from '../../color';
|
4 | import { layout, RESOURCE_PREFIX, isFontIconURI } from '../../utils';
|
5 | import { colorProperty } from '../styling/style-properties';
|
6 | import { ImageSource } from '../../image-source';
|
7 | import { Application } from '../../application';
|
8 | import { isAccessibilityServiceEnabled, updateContentDescription } from '../../accessibility';
|
9 | import { SDK_VERSION } from '../../utils/constants';
|
10 | export * from './action-bar-common';
|
11 | const R_ID_HOME = 0x0102002c;
|
12 | const ACTION_ITEM_ID_OFFSET = 10000;
|
13 | const DEFAULT_ELEVATION = 4;
|
14 | let AppCompatTextView;
|
15 | let actionItemIdGenerator = ACTION_ITEM_ID_OFFSET;
|
16 | function generateItemId() {
|
17 | actionItemIdGenerator++;
|
18 | return actionItemIdGenerator;
|
19 | }
|
20 | function loadActionIconDrawableOrResourceId(item) {
|
21 | const itemIcon = item.icon;
|
22 | const itemStyle = item.style;
|
23 | let drawableOrId = null;
|
24 | if (isFontIconURI(itemIcon)) {
|
25 | const fontIconCode = itemIcon.split('//')[1];
|
26 | const font = itemStyle.fontInternal;
|
27 | const color = itemStyle.color;
|
28 | const is = ImageSource.fromFontIconCodeSync(fontIconCode, font, color);
|
29 | if (is && is.android) {
|
30 | drawableOrId = new android.graphics.drawable.BitmapDrawable(appResources, is.android);
|
31 | }
|
32 | }
|
33 | else {
|
34 | drawableOrId = getDrawableOrResourceId(itemIcon, appResources);
|
35 | }
|
36 | if (!drawableOrId) {
|
37 | traceMissingIcon(itemIcon);
|
38 | }
|
39 | return drawableOrId;
|
40 | }
|
41 | let appResources;
|
42 | let MenuItemClickListener;
|
43 | function initializeMenuItemClickListener() {
|
44 | if (MenuItemClickListener) {
|
45 | return;
|
46 | }
|
47 | AppCompatTextView = androidx.appcompat.widget.AppCompatTextView;
|
48 | var MenuItemClickListenerImpl = (function (_super) {
|
49 | __extends(MenuItemClickListenerImpl, _super);
|
50 | function MenuItemClickListenerImpl(owner) {
|
51 | var _this = _super.call(this) || this;
|
52 | _this.owner = owner;
|
53 | return global.__native(_this);
|
54 | }
|
55 | MenuItemClickListenerImpl.prototype.onMenuItemClick = function (item) {
|
56 | var itemId = item.getItemId();
|
57 | return this.owner._onAndroidItemSelected(itemId);
|
58 | };
|
59 | var _a;
|
60 | MenuItemClickListenerImpl = __decorate([
|
61 | Interfaces([androidx.appcompat.widget.Toolbar.OnMenuItemClickListener]),
|
62 | __metadata("design:paramtypes", [typeof (_a = typeof ActionBar !== "undefined" && ActionBar) === "function" ? _a : Object])
|
63 | ], MenuItemClickListenerImpl);
|
64 | return MenuItemClickListenerImpl;
|
65 | }(java.lang.Object));
|
66 | MenuItemClickListener = MenuItemClickListenerImpl;
|
67 | appResources = Application.android.context.getResources();
|
68 | }
|
69 | export class ActionItem extends ActionItemBase {
|
70 | constructor() {
|
71 | super();
|
72 | this._androidPosition = {
|
73 | position: 'actionBar',
|
74 | systemIcon: undefined,
|
75 | };
|
76 | this._itemId = generateItemId();
|
77 | }
|
78 |
|
79 | get android() {
|
80 | return this._androidPosition;
|
81 | }
|
82 | set android(value) {
|
83 | throw new Error('ActionItem.android is read-only');
|
84 | }
|
85 | _getItemId() {
|
86 | return this._itemId;
|
87 | }
|
88 | }
|
89 | export class AndroidActionBarSettings {
|
90 | constructor(actionBar) {
|
91 | this._iconVisibility = 'auto';
|
92 | this._actionBar = actionBar;
|
93 | }
|
94 | get icon() {
|
95 | return this._icon;
|
96 | }
|
97 | set icon(value) {
|
98 | if (value !== this._icon) {
|
99 | this._icon = value;
|
100 | this._actionBar._onIconPropertyChanged();
|
101 | }
|
102 | }
|
103 | get iconVisibility() {
|
104 | return this._iconVisibility;
|
105 | }
|
106 | set iconVisibility(value) {
|
107 | if (value !== this._iconVisibility) {
|
108 | this._iconVisibility = value;
|
109 | this._actionBar._onIconPropertyChanged();
|
110 | }
|
111 | }
|
112 | }
|
113 | export class NavigationButton extends ActionItem {
|
114 | }
|
115 | export class ActionBar extends ActionBarBase {
|
116 | constructor() {
|
117 | super();
|
118 | this._android = new AndroidActionBarSettings(this);
|
119 | }
|
120 | get android() {
|
121 | return this._android;
|
122 | }
|
123 | _addChildFromBuilder(name, value) {
|
124 | if (value instanceof NavigationButton) {
|
125 | this.navigationButton = value;
|
126 | }
|
127 | else if (value instanceof ActionItem) {
|
128 | this.actionItems?.addItem(value);
|
129 | }
|
130 | else if (value instanceof View) {
|
131 | this.titleView = value;
|
132 | }
|
133 | }
|
134 | createNativeView() {
|
135 | return new androidx.appcompat.widget.Toolbar(this._context);
|
136 | }
|
137 | initNativeView() {
|
138 | super.initNativeView();
|
139 | const nativeView = this.nativeViewProtected;
|
140 | initializeMenuItemClickListener();
|
141 | const menuItemClickListener = new MenuItemClickListener(this);
|
142 | nativeView.setOnMenuItemClickListener(menuItemClickListener);
|
143 | nativeView.menuItemClickListener = menuItemClickListener;
|
144 | }
|
145 | disposeNativeView() {
|
146 | if (this.nativeViewProtected?.menuItemClickListener) {
|
147 | this.nativeViewProtected.menuItemClickListener.owner = null;
|
148 | }
|
149 | super.disposeNativeView();
|
150 | }
|
151 | onLoaded() {
|
152 | super.onLoaded();
|
153 | this.update();
|
154 | }
|
155 | update() {
|
156 | if (!this.nativeViewProtected) {
|
157 | return;
|
158 | }
|
159 | const page = this.page;
|
160 | if (!page.frame || !page.frame._getNavBarVisible(page)) {
|
161 | this.nativeViewProtected.setVisibility(android.view.View.GONE);
|
162 |
|
163 | return;
|
164 | }
|
165 | this.nativeViewProtected.setVisibility(android.view.View.VISIBLE);
|
166 |
|
167 | this._addActionItems();
|
168 |
|
169 | this._updateTitleAndTitleView();
|
170 |
|
171 | this._updateIcon();
|
172 |
|
173 | this._updateNavigationButton();
|
174 | }
|
175 | _applyBackground(background, isBorderDrawable, onlyColor, backgroundDrawable) {
|
176 | const nativeView = this.nativeViewProtected;
|
177 | if (backgroundDrawable && onlyColor && SDK_VERSION >= 21) {
|
178 | if (isBorderDrawable && nativeView._cachedDrawable) {
|
179 | backgroundDrawable = nativeView._cachedDrawable;
|
180 |
|
181 | const constantState = backgroundDrawable.getConstantState();
|
182 | if (constantState) {
|
183 | try {
|
184 | backgroundDrawable = constantState.newDrawable(nativeView.getResources());
|
185 |
|
186 | }
|
187 | catch { }
|
188 | }
|
189 | nativeView.setBackground(backgroundDrawable);
|
190 | }
|
191 | const backgroundColor = (backgroundDrawable.backgroundColor = background.color.android);
|
192 | backgroundDrawable.mutate();
|
193 | backgroundDrawable.setColorFilter(backgroundColor, android.graphics.PorterDuff.Mode.SRC_IN);
|
194 | backgroundDrawable.invalidateSelf();
|
195 | backgroundDrawable.backgroundColor = backgroundColor;
|
196 | }
|
197 | else {
|
198 | super._applyBackground(background, isBorderDrawable, onlyColor, backgroundDrawable);
|
199 | }
|
200 | }
|
201 | _onAndroidItemSelected(itemId) {
|
202 |
|
203 | if (this.navigationButton && itemId === R_ID_HOME) {
|
204 | this.navigationButton._raiseTap();
|
205 | return true;
|
206 | }
|
207 |
|
208 | let menuItem = undefined;
|
209 | const items = this.actionItems?.getItems() ?? [];
|
210 | for (let i = 0; i < items.length; i++) {
|
211 | if (items[i]._getItemId() === itemId) {
|
212 | menuItem = items[i];
|
213 | break;
|
214 | }
|
215 | }
|
216 | if (menuItem) {
|
217 | menuItem._raiseTap();
|
218 | return true;
|
219 | }
|
220 | return false;
|
221 | }
|
222 | _updateNavigationButton() {
|
223 | const navButton = this.navigationButton;
|
224 | if (navButton && isVisible(navButton)) {
|
225 | const systemIcon = navButton.android.systemIcon;
|
226 | if (systemIcon !== undefined) {
|
227 |
|
228 | const systemResourceId = getSystemResourceId(systemIcon);
|
229 | if (systemResourceId) {
|
230 | this.nativeViewProtected.setNavigationIcon(systemResourceId);
|
231 | }
|
232 | }
|
233 | else if (navButton.icon) {
|
234 | const drawableOrId = loadActionIconDrawableOrResourceId(navButton);
|
235 | if (drawableOrId) {
|
236 | this.nativeViewProtected.setNavigationIcon(drawableOrId);
|
237 | }
|
238 | }
|
239 |
|
240 | this.nativeViewProtected.setNavigationContentDescription(navButton.text || null);
|
241 | const navBtn = new WeakRef(navButton);
|
242 | this.nativeViewProtected.setNavigationOnClickListener(new android.view.View.OnClickListener({
|
243 | onClick: function (v) {
|
244 | const owner = navBtn?.get();
|
245 | if (owner) {
|
246 | owner._raiseTap();
|
247 | }
|
248 | },
|
249 | }));
|
250 | }
|
251 | else {
|
252 | this.nativeViewProtected.setNavigationIcon(null);
|
253 | }
|
254 | }
|
255 | _updateIcon() {
|
256 | const visibility = getIconVisibility(this.android.iconVisibility);
|
257 | if (visibility) {
|
258 | const icon = this.android.icon;
|
259 | if (icon !== undefined) {
|
260 | const drawableOrId = getDrawableOrResourceId(icon, appResources);
|
261 | if (drawableOrId) {
|
262 | this.nativeViewProtected.setLogo(drawableOrId);
|
263 | }
|
264 | else {
|
265 | traceMissingIcon(icon);
|
266 | }
|
267 | }
|
268 | else {
|
269 | const defaultIcon = Application.android.nativeApp.getApplicationInfo().icon;
|
270 | this.nativeViewProtected.setLogo(defaultIcon);
|
271 | }
|
272 | }
|
273 | else {
|
274 | this.nativeViewProtected.setLogo(null);
|
275 | }
|
276 | }
|
277 | _updateTitleAndTitleView() {
|
278 | if (!this.titleView) {
|
279 |
|
280 | const title = this.title;
|
281 | if (title !== undefined) {
|
282 | this.nativeViewProtected.setTitle(title);
|
283 | }
|
284 | else {
|
285 | const appContext = Application.android.context;
|
286 | const appInfo = appContext.getApplicationInfo();
|
287 | const appLabel = appContext.getPackageManager().getApplicationLabel(appInfo);
|
288 | if (appLabel) {
|
289 | this.nativeViewProtected.setTitle(appLabel);
|
290 | }
|
291 | }
|
292 | }
|
293 |
|
294 | updateContentDescription(this, true);
|
295 | }
|
296 | _addActionItems() {
|
297 | const menu = this.nativeViewProtected.getMenu();
|
298 | const items = this.actionItems?.getVisibleItems() ?? [];
|
299 | menu.clear();
|
300 | for (let i = 0; i < items.length; i++) {
|
301 | const item = items[i];
|
302 | const menuItem = menu.add(android.view.Menu.NONE, item._getItemId(), android.view.Menu.NONE, item.text + '');
|
303 | if (item.actionView && item.actionView.android) {
|
304 |
|
305 | item.android.position = 'actionBar';
|
306 | menuItem.setActionView(item.actionView.android);
|
307 | ActionBar._setOnClickListener(item);
|
308 | }
|
309 | else if (item.android.systemIcon) {
|
310 |
|
311 | const systemResourceId = getSystemResourceId(item.android.systemIcon);
|
312 | if (systemResourceId) {
|
313 | menuItem.setIcon(systemResourceId);
|
314 | }
|
315 | }
|
316 | else if (item.icon) {
|
317 | const drawableOrId = loadActionIconDrawableOrResourceId(item);
|
318 | if (drawableOrId) {
|
319 | menuItem.setIcon(drawableOrId);
|
320 | }
|
321 | }
|
322 | const showAsAction = getShowAsAction(item);
|
323 | menuItem.setShowAsAction(showAsAction);
|
324 | }
|
325 | }
|
326 | static _setOnClickListener(item) {
|
327 | const weakRef = new WeakRef(item);
|
328 | item.actionView.android.setOnClickListener(new android.view.View.OnClickListener({
|
329 | onClick: function (v) {
|
330 | const owner = weakRef?.get();
|
331 | if (owner) {
|
332 | owner._raiseTap();
|
333 | }
|
334 | },
|
335 | }));
|
336 | }
|
337 | _onTitlePropertyChanged() {
|
338 | if (this.nativeViewProtected) {
|
339 | this._updateTitleAndTitleView();
|
340 | }
|
341 | }
|
342 | _onIconPropertyChanged() {
|
343 | if (this.nativeViewProtected) {
|
344 | this._updateIcon();
|
345 | }
|
346 | }
|
347 | _addViewToNativeVisualTree(child, atIndex = Number.MAX_VALUE) {
|
348 | super._addViewToNativeVisualTree(child);
|
349 | if (this.nativeViewProtected && child.nativeViewProtected) {
|
350 | if (atIndex >= this.nativeViewProtected.getChildCount()) {
|
351 | this.nativeViewProtected.addView(child.nativeViewProtected);
|
352 | }
|
353 | else {
|
354 | this.nativeViewProtected.addView(child.nativeViewProtected, atIndex);
|
355 | }
|
356 | return true;
|
357 | }
|
358 | return false;
|
359 | }
|
360 | _removeViewFromNativeVisualTree(child) {
|
361 | super._removeViewFromNativeVisualTree(child);
|
362 | if (this.nativeViewProtected && child.nativeViewProtected) {
|
363 | this.nativeViewProtected.removeView(child.nativeViewProtected);
|
364 | }
|
365 | }
|
366 | [colorProperty.getDefault]() {
|
367 | const nativeView = this.nativeViewProtected;
|
368 | if (!defaultTitleTextColor) {
|
369 | let tv = getAppCompatTextView(nativeView);
|
370 | if (!tv) {
|
371 | const title = nativeView.getTitle();
|
372 |
|
373 | nativeView.setTitle('');
|
374 | tv = getAppCompatTextView(nativeView);
|
375 | if (title) {
|
376 |
|
377 | nativeView.setTitle(title);
|
378 | }
|
379 | }
|
380 |
|
381 |
|
382 | defaultTitleTextColor = tv ? tv.getTextColors().getDefaultColor() : -570425344;
|
383 | }
|
384 | return defaultTitleTextColor;
|
385 | }
|
386 | [colorProperty.setNative](value) {
|
387 | const color = value instanceof Color ? value.android : value;
|
388 | this.nativeViewProtected.setTitleTextColor(color);
|
389 | }
|
390 | [flatProperty.setNative](value) {
|
391 | const compat = androidx.core.view.ViewCompat;
|
392 | if (compat.setElevation) {
|
393 | if (value) {
|
394 | compat.setElevation(this.nativeViewProtected, 0);
|
395 | }
|
396 | else {
|
397 | const val = DEFAULT_ELEVATION * layout.getDisplayDensity();
|
398 | compat.setElevation(this.nativeViewProtected, val);
|
399 | }
|
400 | }
|
401 | }
|
402 | [androidContentInsetLeftProperty.setNative]() {
|
403 | if (SDK_VERSION >= 21) {
|
404 | this.nativeViewProtected.setContentInsetsAbsolute(this.effectiveContentInsetLeft, this.effectiveContentInsetRight);
|
405 | }
|
406 | }
|
407 | [androidContentInsetRightProperty.setNative]() {
|
408 | if (SDK_VERSION >= 21) {
|
409 | this.nativeViewProtected.setContentInsetsAbsolute(this.effectiveContentInsetLeft, this.effectiveContentInsetRight);
|
410 | }
|
411 | }
|
412 | accessibilityScreenChanged() {
|
413 | if (!isAccessibilityServiceEnabled()) {
|
414 | return;
|
415 | }
|
416 | const nativeView = this.nativeViewProtected;
|
417 | if (!nativeView) {
|
418 | return;
|
419 | }
|
420 | const originalFocusableState = SDK_VERSION >= 26 && nativeView.getFocusable();
|
421 | const originalImportantForAccessibility = nativeView.getImportantForAccessibility();
|
422 | const originalIsAccessibilityHeading = SDK_VERSION >= 28 && nativeView.isAccessibilityHeading();
|
423 | try {
|
424 | nativeView.setFocusable(false);
|
425 | nativeView.setImportantForAccessibility(android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
426 | let announceView = null;
|
427 | const numChildren = nativeView.getChildCount();
|
428 | for (let i = 0; i < numChildren; i += 1) {
|
429 | const childView = nativeView.getChildAt(i);
|
430 | if (!childView) {
|
431 | continue;
|
432 | }
|
433 | childView.setFocusable(true);
|
434 | if (childView instanceof androidx.appcompat.widget.AppCompatTextView) {
|
435 | announceView = childView;
|
436 | if (SDK_VERSION >= 28) {
|
437 | announceView.setAccessibilityHeading(true);
|
438 | }
|
439 | }
|
440 | }
|
441 | if (!announceView) {
|
442 | announceView = nativeView;
|
443 | }
|
444 | announceView.setFocusable(true);
|
445 | announceView.setImportantForAccessibility(android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
446 | announceView.sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED);
|
447 | announceView.sendAccessibilityEvent(android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED);
|
448 | }
|
449 | catch {
|
450 |
|
451 | }
|
452 | finally {
|
453 | setTimeout(() => {
|
454 |
|
455 | const localNativeView = this.nativeViewProtected;
|
456 | if (!localNativeView) {
|
457 | return;
|
458 | }
|
459 | if (SDK_VERSION >= 28) {
|
460 | nativeView.setAccessibilityHeading(originalIsAccessibilityHeading);
|
461 | }
|
462 | if (SDK_VERSION >= 26) {
|
463 | localNativeView.setFocusable(originalFocusableState);
|
464 | }
|
465 | localNativeView.setImportantForAccessibility(originalImportantForAccessibility);
|
466 | });
|
467 | }
|
468 | }
|
469 | }
|
470 | function getAppCompatTextView(toolbar) {
|
471 | for (let i = 0, count = toolbar.getChildCount(); i < count; i++) {
|
472 | const child = toolbar.getChildAt(i);
|
473 | if (child instanceof AppCompatTextView) {
|
474 | return child;
|
475 | }
|
476 | }
|
477 | return null;
|
478 | }
|
479 | ActionBar.prototype.recycleNativeView = 'auto';
|
480 | let defaultTitleTextColor;
|
481 | function getDrawableOrResourceId(icon, resources) {
|
482 | if (typeof icon !== 'string') {
|
483 | return null;
|
484 | }
|
485 | let result = null;
|
486 | if (icon.indexOf(RESOURCE_PREFIX) === 0) {
|
487 | const resourceId = resources.getIdentifier(icon.substr(RESOURCE_PREFIX.length), 'drawable', Application.android.packageName);
|
488 | if (resourceId > 0) {
|
489 | result = resourceId;
|
490 | }
|
491 | }
|
492 | else {
|
493 | let drawable;
|
494 | const is = ImageSource.fromFileOrResourceSync(icon);
|
495 | if (is) {
|
496 | drawable = new android.graphics.drawable.BitmapDrawable(appResources, is.android);
|
497 | }
|
498 | result = drawable;
|
499 | }
|
500 | return result;
|
501 | }
|
502 | function getShowAsAction(menuItem) {
|
503 | switch (menuItem.android.position) {
|
504 | case 'actionBarIfRoom':
|
505 | return android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
|
506 | case 'popup':
|
507 | return android.view.MenuItem.SHOW_AS_ACTION_NEVER;
|
508 | case 'actionBar':
|
509 | default:
|
510 | return android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
|
511 | }
|
512 | }
|
513 | function getIconVisibility(iconVisibility) {
|
514 | switch (iconVisibility) {
|
515 | case 'always':
|
516 | return true;
|
517 | case 'auto':
|
518 | case 'never':
|
519 | default:
|
520 | return false;
|
521 | }
|
522 | }
|
523 | function getSystemResourceId(systemIcon) {
|
524 | return android.content.res.Resources.getSystem().getIdentifier(systemIcon, 'drawable', 'android');
|
525 | }
|
526 |
|
\ | No newline at end of file |