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/list-view-sticky-headers
This commit is contained in:
@@ -7,6 +7,10 @@ import { makeValidator, makeParser } from './validators';
|
||||
import { CubicBezierAnimationCurve } from './animation-types';
|
||||
|
||||
export namespace CoreTypes {
|
||||
type AndroidOverflowSingle = 'ignore' | 'none' | 'dont-apply';
|
||||
type AndroidOverflowMultiple = 'left' | 'right' | 'top' | 'bottom' | 'left-dont-consume' | 'top-dont-consume' | 'right-dont-consume' | 'bottom-dont-consume' | 'all-but-left' | 'all-but-top' | 'all-but-right' | 'all-but-bottom';
|
||||
type AndroidOverflowStacked = AndroidOverflowSingle | `${AndroidOverflowSingle},${AndroidOverflowMultiple}`;
|
||||
export type AndroidOverflow = AndroidOverflowSingle | AndroidOverflowStacked;
|
||||
export type CSSWideKeywords = 'initial' | 'inherit' | 'unset' | 'revert';
|
||||
|
||||
/**
|
||||
|
||||
Binary file not shown.
10
packages/core/ui/animation/index.d.ts
vendored
10
packages/core/ui/animation/index.d.ts
vendored
@@ -6,11 +6,11 @@ import type { AnimationDefinition, AnimationPromise } from './animation-types';
|
||||
* Defines a animation set.
|
||||
*/
|
||||
export class Animation {
|
||||
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
|
||||
public play: (resetOnFinish?: boolean) => AnimationPromise;
|
||||
public cancel: () => void;
|
||||
public isPlaying: boolean;
|
||||
public _resolveAnimationCurve(curve: any): any;
|
||||
constructor(animationDefinitions: Array<AnimationDefinition>, playSequentially?: boolean);
|
||||
public play: (resetOnFinish?: boolean) => AnimationPromise;
|
||||
public cancel: () => void;
|
||||
public isPlaying: boolean;
|
||||
public _resolveAnimationCurve(curve: any): any;
|
||||
}
|
||||
|
||||
export function _resolveAnimationCurve(curve: any): any;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { Point, Position } from './view-interfaces';
|
||||
import type { GestureTypes, GestureEventData } from '../../gestures';
|
||||
import { getNativeScriptGlobals } from '../../../globals/global-utils';
|
||||
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty, AndroidHelper, statusBarStyleProperty } from './view-common';
|
||||
import { ViewCommon, isEnabledProperty, originXProperty, originYProperty, isUserInteractionEnabledProperty, testIDProperty, AndroidHelper, androidOverflowEdgeProperty, statusBarStyleProperty } from './view-common';
|
||||
import { paddingLeftProperty, paddingTopProperty, paddingRightProperty, paddingBottomProperty } from '../../styling/style-properties';
|
||||
import { Length } from '../../styling/length-shared';
|
||||
import { layout } from '../../../utils';
|
||||
@@ -320,6 +320,121 @@ function getModalOptions(domId: number): DialogOptions {
|
||||
return modalMap.get(domId);
|
||||
}
|
||||
|
||||
const INSET_LEFT = 0;
|
||||
const INSET_TOP = 4;
|
||||
const INSET_RIGHT = 8;
|
||||
const INSET_BOTTOM = 12;
|
||||
const INSET_LEFT_CONSUMED = 16;
|
||||
const INSET_TOP_CONSUMED = 20;
|
||||
const INSET_RIGHT_CONSUMED = 24;
|
||||
const INSET_BOTTOM_CONSUMED = 28;
|
||||
|
||||
const OverflowEdgeIgnore = -1;
|
||||
const OverflowEdgeNone: number = 0;
|
||||
const OverflowEdgeLeft: number = 1 << 1;
|
||||
const OverflowEdgeTop: number = 1 << 2;
|
||||
const OverflowEdgeRight: number = 1 << 3;
|
||||
const OverflowEdgeBottom: number = 1 << 4;
|
||||
const OverflowEdgeDontApply: number = 1 << 5;
|
||||
const OverflowEdgeLeftDontConsume: number = 1 << 6;
|
||||
const OverflowEdgeTopDontConsume: number = 1 << 7;
|
||||
const OverflowEdgeRightDontConsume: number = 1 << 8;
|
||||
const OverflowEdgeBottomDontConsume: number = 1 << 9;
|
||||
const OverflowEdgeAllButLeft: number = 1 << 10;
|
||||
const OverflowEdgeAllButTop: number = 1 << 11;
|
||||
const OverflowEdgeAllButRight: number = 1 << 12;
|
||||
const OverflowEdgeAllButBottom: number = 1 << 13;
|
||||
|
||||
class Inset {
|
||||
private view: DataView;
|
||||
private data: ArrayBuffer;
|
||||
constructor(data: java.nio.ByteBuffer) {
|
||||
this.data = (<any>ArrayBuffer).from(data);
|
||||
this.view = new DataView(this.data);
|
||||
}
|
||||
|
||||
public get left(): number {
|
||||
return this.view.getInt32(INSET_LEFT, true);
|
||||
}
|
||||
|
||||
public set left(value: number) {
|
||||
this.view.setInt32(INSET_LEFT, value, true);
|
||||
}
|
||||
|
||||
public get top(): number {
|
||||
return this.view.getInt32(INSET_TOP, true);
|
||||
}
|
||||
|
||||
public set top(value: number) {
|
||||
this.view.setInt32(INSET_TOP, value, true);
|
||||
}
|
||||
|
||||
public get right(): number {
|
||||
return this.view.getInt32(INSET_RIGHT, true);
|
||||
}
|
||||
|
||||
public set right(value: number) {
|
||||
this.view.setInt32(INSET_RIGHT, value, true);
|
||||
}
|
||||
|
||||
public get bottom(): number {
|
||||
return this.view.getInt32(INSET_BOTTOM, true);
|
||||
}
|
||||
|
||||
public set bottom(value: number) {
|
||||
this.view.setInt32(INSET_BOTTOM, value, true);
|
||||
}
|
||||
|
||||
public get leftConsumed(): boolean {
|
||||
return this.view.getInt32(INSET_LEFT_CONSUMED, true) > 0;
|
||||
}
|
||||
|
||||
public set leftConsumed(value: boolean) {
|
||||
this.view.setInt32(INSET_LEFT_CONSUMED, value ? 1 : 0, true);
|
||||
}
|
||||
|
||||
public get topConsumed(): boolean {
|
||||
return this.view.getInt32(INSET_TOP_CONSUMED, true) > 0;
|
||||
}
|
||||
|
||||
public set topConsumed(value: boolean) {
|
||||
this.view.setInt32(INSET_TOP_CONSUMED, value ? 1 : 0, true);
|
||||
}
|
||||
|
||||
public get rightConsumed(): boolean {
|
||||
return this.view.getInt32(INSET_RIGHT_CONSUMED, true) > 0;
|
||||
}
|
||||
|
||||
public set rightConsumed(value: boolean) {
|
||||
this.view.setInt32(INSET_RIGHT_CONSUMED, value ? 1 : 0, true);
|
||||
}
|
||||
|
||||
public get bottomConsumed(): boolean {
|
||||
return this.view.getInt32(INSET_BOTTOM_CONSUMED, true) > 0;
|
||||
}
|
||||
|
||||
public set bottomConsumed(value: boolean) {
|
||||
this.view.setInt32(INSET_BOTTOM_CONSUMED, value ? 1 : 0, true);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `Inset: left=${this.left}, top=${this.top}, right=${this.right}, bottom=${this.bottom}, ` + `leftConsumed=${this.leftConsumed}, topConsumed=${this.topConsumed}, ` + `rightConsumed=${this.rightConsumed}, bottomConsumed=${this.bottomConsumed}`;
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
left: this.left,
|
||||
top: this.top,
|
||||
right: this.right,
|
||||
bottom: this.bottom,
|
||||
leftConsumed: this.leftConsumed,
|
||||
topConsumed: this.topConsumed,
|
||||
rightConsumed: this.rightConsumed,
|
||||
bottomConsumed: this.bottomConsumed,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class View extends ViewCommon {
|
||||
public static androidBackPressedEvent = androidBackPressedEvent;
|
||||
|
||||
@@ -330,6 +445,8 @@ export class View extends ViewCommon {
|
||||
private layoutChangeListenerIsSet: boolean;
|
||||
private layoutChangeListener: android.view.View.OnLayoutChangeListener;
|
||||
private _rootManager: androidx.fragment.app.FragmentManager;
|
||||
private insetListenerIsSet: boolean;
|
||||
private needsInsetListener: boolean;
|
||||
|
||||
nativeViewProtected: android.view.View;
|
||||
|
||||
@@ -348,6 +465,12 @@ export class View extends ViewCommon {
|
||||
if (this.isLoaded && !this.layoutChangeListenerIsSet && isLayoutEvent) {
|
||||
this.setOnLayoutChangeListener();
|
||||
}
|
||||
|
||||
const isInsetEvent = typeof eventNames === 'string' ? eventNames.indexOf(ViewCommon.androidOverflowInsetEvent) !== -1 : false;
|
||||
// only avaiable on LayoutBase
|
||||
if (!this.insetListenerIsSet && isInsetEvent) {
|
||||
this.setInsetListener();
|
||||
}
|
||||
}
|
||||
|
||||
removeEventListener(eventNames: string, callback?: (data: EventData) => void, thisArg?: any) {
|
||||
@@ -359,6 +482,43 @@ export class View extends ViewCommon {
|
||||
this.nativeViewProtected.removeOnLayoutChangeListener(this.layoutChangeListener);
|
||||
this.layoutChangeListenerIsSet = false;
|
||||
}
|
||||
|
||||
const isInsetEvent = typeof eventNames === 'string' ? eventNames.indexOf(ViewCommon.androidOverflowInsetEvent) !== -1 : false;
|
||||
|
||||
if (this.insetListenerIsSet && isInsetEvent && this.nativeViewProtected && (this.nativeViewProtected as any).setInsetListener) {
|
||||
(this.nativeViewProtected as any).setInsetListener(null);
|
||||
this.insetListenerIsSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
private setInsetListener() {
|
||||
if (this.nativeViewProtected) {
|
||||
if ((this.nativeViewProtected as any).setInsetListener) {
|
||||
const ref = new WeakRef(this);
|
||||
(this.nativeViewProtected as any).setInsetListener(
|
||||
new org.nativescript.widgets.LayoutBase.WindowInsetListener({
|
||||
onApplyWindowInsets(param0) {
|
||||
const owner = ref.get();
|
||||
if (!owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
const inset = new Inset(param0);
|
||||
const args = {
|
||||
eventName: ViewCommon.androidOverflowInsetEvent,
|
||||
object: this,
|
||||
inset,
|
||||
};
|
||||
owner.notify(args);
|
||||
},
|
||||
}),
|
||||
);
|
||||
this.insetListenerIsSet = true;
|
||||
}
|
||||
this.needsInsetListener = false;
|
||||
} else {
|
||||
this.needsInsetListener = true;
|
||||
}
|
||||
}
|
||||
|
||||
public _getChildFragmentManager(): androidx.fragment.app.FragmentManager {
|
||||
@@ -419,6 +579,35 @@ export class View extends ViewCommon {
|
||||
return manager;
|
||||
}
|
||||
|
||||
[androidOverflowEdgeProperty.setNative](value: CoreTypes.AndroidOverflow) {
|
||||
const nativeView = this.nativeViewProtected as any;
|
||||
if (typeof value !== 'string' || nativeView === null || nativeView == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!('setOverflowEdge' in nativeView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (value) {
|
||||
case 'none':
|
||||
nativeView.setOverflowEdge(OverflowEdgeNone);
|
||||
break;
|
||||
case 'ignore':
|
||||
nativeView.setOverflowEdge(OverflowEdgeIgnore);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
const edge = parseEdges(value);
|
||||
|
||||
if (edge != null) {
|
||||
nativeView.setOverflowEdge(edge);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public onLoaded() {
|
||||
this._manager = null;
|
||||
@@ -468,6 +657,10 @@ export class View extends ViewCommon {
|
||||
if (this.needsOnLayoutChangeListener()) {
|
||||
this.setOnLayoutChangeListener();
|
||||
}
|
||||
|
||||
if (!this.insetListenerIsSet && this.needsInsetListener) {
|
||||
this.setInsetListener();
|
||||
}
|
||||
}
|
||||
|
||||
public needsOnLayoutChangeListener() {
|
||||
@@ -1356,8 +1549,43 @@ export class View extends ViewCommon {
|
||||
}
|
||||
}
|
||||
|
||||
const edgeMap: Record<string, number> = {
|
||||
none: OverflowEdgeNone,
|
||||
left: OverflowEdgeLeft,
|
||||
top: OverflowEdgeTop,
|
||||
right: OverflowEdgeRight,
|
||||
bottom: OverflowEdgeBottom,
|
||||
'dont-apply': OverflowEdgeDontApply,
|
||||
'left-dont-consume': OverflowEdgeLeftDontConsume,
|
||||
'top-dont-consume': OverflowEdgeTopDontConsume,
|
||||
'right-dont-consume': OverflowEdgeRightDontConsume,
|
||||
'bottom-dont-consume': OverflowEdgeBottomDontConsume,
|
||||
'all-but-left': OverflowEdgeAllButLeft,
|
||||
'all-but-top': OverflowEdgeAllButTop,
|
||||
'all-but-right': OverflowEdgeAllButRight,
|
||||
'all-but-bottom': OverflowEdgeAllButBottom,
|
||||
};
|
||||
|
||||
function parseEdges(edges: string): number | null {
|
||||
let result = 0;
|
||||
const values = edges.split(',');
|
||||
for (const raw of values) {
|
||||
const value = edgeMap[raw.trim()];
|
||||
if (value === undefined) continue;
|
||||
// dont-apply overrides everything else
|
||||
if (value === OverflowEdgeDontApply) return value;
|
||||
result |= value;
|
||||
}
|
||||
return result === 0 ? null : result;
|
||||
}
|
||||
|
||||
export class ContainerView extends View {
|
||||
public iosOverflowSafeArea: boolean;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.androidOverflowEdge = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
export class CustomLayoutView extends ContainerView {
|
||||
|
||||
12
packages/core/ui/core/view/index.d.ts
vendored
12
packages/core/ui/core/view/index.d.ts
vendored
@@ -92,6 +92,13 @@ export abstract class View extends ViewCommon {
|
||||
*/
|
||||
public static accessibilityFocusChangedEvent: string;
|
||||
|
||||
/**
|
||||
* String value used when hooking to androidOverflowInset event.
|
||||
*
|
||||
* @nsEvent {EventDataValue} androidOverflowInset
|
||||
*/
|
||||
public static androidOverflowInsetEvent: string;
|
||||
|
||||
/**
|
||||
* Gets the android-specific native instance that lies behind this proxy. Will be available if running on an Android platform.
|
||||
*/
|
||||
@@ -802,6 +809,11 @@ export abstract class View extends ViewCommon {
|
||||
*/
|
||||
on(event: 'shownModally', callback: (args: ShownModallyData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Raised after the view is shown as a modal dialog.
|
||||
*/
|
||||
on(event: 'androidOverflowInset', callback: (args: ShownModallyData) => void, thisArg?: any);
|
||||
|
||||
/**
|
||||
* Returns the current modal view that this page is showing (is parent of), if any.
|
||||
*/
|
||||
|
||||
@@ -80,6 +80,7 @@ export abstract class ViewCommon extends ViewBase {
|
||||
public static accessibilityFocusEvent = accessibilityFocusEvent;
|
||||
public static accessibilityFocusChangedEvent = accessibilityFocusChangedEvent;
|
||||
public static accessibilityPerformEscapeEvent = accessibilityPerformEscapeEvent;
|
||||
public static androidOverflowInsetEvent = 'androidOverflowInset';
|
||||
|
||||
public accessibilityIdentifier: string;
|
||||
public accessibilityLabel: string;
|
||||
@@ -994,6 +995,7 @@ export abstract class ViewCommon extends ViewBase {
|
||||
public iosOverflowSafeArea: boolean;
|
||||
public iosOverflowSafeAreaEnabled: boolean;
|
||||
public iosIgnoreSafeArea: boolean;
|
||||
public androidOverflowEdge: CoreTypes.AndroidOverflow;
|
||||
|
||||
get isLayoutValid(): boolean {
|
||||
return this._isLayoutValid;
|
||||
@@ -1344,6 +1346,12 @@ export const iosIgnoreSafeAreaProperty = new InheritedProperty({
|
||||
});
|
||||
iosIgnoreSafeAreaProperty.register(ViewCommon);
|
||||
|
||||
export const androidOverflowEdgeProperty = new Property<ViewCommon, CoreTypes.AndroidOverflow>({
|
||||
name: 'androidOverflowEdge',
|
||||
defaultValue: 'ignore',
|
||||
});
|
||||
androidOverflowEdgeProperty.register(ViewCommon);
|
||||
|
||||
/**
|
||||
* Glass effects
|
||||
*/
|
||||
|
||||
@@ -59,3 +59,27 @@ export interface Size {
|
||||
*/
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the inset values for AndroidOverflowInsetData.
|
||||
*/
|
||||
export interface Inset {
|
||||
top: number;
|
||||
right: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
topConsumed: boolean;
|
||||
rightConsumed: boolean;
|
||||
bottomConsumed: boolean;
|
||||
leftConsumed: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the data for the androidOverflowInset event.
|
||||
*/
|
||||
export interface AndroidOverflowInsetData extends EventData {
|
||||
/**
|
||||
* The inset values passed to the view to consume or update.
|
||||
*/
|
||||
inset?: Inset;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import '../../globals';
|
||||
import { setActivityCallbacks } from '.';
|
||||
import { Application } from '../../application';
|
||||
import { isEmbedded } from '../embedding';
|
||||
|
||||
import { enableEdgeToEdge } from '../../utils/native-helper-for-android';
|
||||
const EMPTY_FN = () => {};
|
||||
declare const com: any;
|
||||
|
||||
@@ -22,6 +22,7 @@ if (!isEmbedded()) {
|
||||
// Set isNativeScriptActivity in onCreate.
|
||||
// The JS constructor might not be called because the activity is created from Android.
|
||||
this.isNativeScriptActivity = true;
|
||||
enableEdgeToEdge(this);
|
||||
if (!this._callbacks) {
|
||||
setActivityCallbacks(this);
|
||||
}
|
||||
@@ -78,6 +79,7 @@ if (!isEmbedded()) {
|
||||
// Set isNativeScriptActivity in onCreate.
|
||||
// The JS constructor might not be called because the activity is created from Android.
|
||||
activity.isNativeScriptActivity = true;
|
||||
enableEdgeToEdge(this);
|
||||
if (!activity._callbacks) {
|
||||
setActivityCallbacks(activity);
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ export class Frame extends FrameBase {
|
||||
private _containerViewId = -1;
|
||||
private _tearDownPending = false;
|
||||
private _attachedToWindow = false;
|
||||
_defaultOverflowEdge: number;
|
||||
_defaultOverflowEdgeValue: string;
|
||||
/**
|
||||
* This property indicates that the view is to be reused as a root view or has been previously disposed.
|
||||
*/
|
||||
@@ -84,6 +86,7 @@ export class Frame extends FrameBase {
|
||||
constructor() {
|
||||
super();
|
||||
this._android = new AndroidFrame(this);
|
||||
this.androidOverflowEdge = 'ignore';
|
||||
}
|
||||
|
||||
public static reloadPage(context?: ModuleContext): void {
|
||||
|
||||
@@ -17,7 +17,7 @@ export { ViewBase, eachDescendant, getAncestor, getViewById, booleanConverter, q
|
||||
export type { ShowModalOptions } from './core/view-base';
|
||||
export { View, CSSType, ContainerView, ViewHelper, AndroidHelper, IOSHelper, isUserInteractionEnabledProperty, PseudoClassHandler, CustomLayoutView } from './core/view';
|
||||
export type { Template, KeyedTemplate, AddArrayFromBuilder, AddChildFromBuilder, GlassEffectConfig, GlassEffectType, GlassEffectVariant } from './core/view';
|
||||
export type { ShownModallyData, Size } from './core/view/view-interfaces';
|
||||
export type { ShownModallyData, Size, AndroidOverflowInsetData } from './core/view/view-interfaces';
|
||||
export { Property, CoercibleProperty, InheritedProperty, CssProperty, InheritedCssProperty, ShorthandProperty, CssAnimationProperty, makeParser, makeValidator } from './core/properties';
|
||||
export { unsetValue } from './core/properties/property-shared';
|
||||
export { addWeakEventListener, removeWeakEventListener } from './core/weak-event-listener';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Color } from '../color';
|
||||
import { numberHasDecimals, numberIs64Bit } from './types';
|
||||
import { getNativeApp } from '../application/helpers-common';
|
||||
import { androidGetCurrentActivity } from '../application/helpers';
|
||||
@@ -294,3 +295,133 @@ export function isRealDevice(): boolean {
|
||||
|
||||
return fingerprint != null && (fingerprint.indexOf('vbox') > -1 || fingerprint.indexOf('generic') > -1);
|
||||
}
|
||||
|
||||
const DefaultLightScrim = new Color(0xe6, 0xff, 0xff, 0xff);
|
||||
const DefaultDarkScrim = new Color(0x80, 0x1b, 0x1b, 0x1b);
|
||||
const DefaultStatusBarLight = new Color(0);
|
||||
const DefaultStatusBarDark = new Color(0);
|
||||
|
||||
interface ISystemColor {
|
||||
navigationBarLight: Color;
|
||||
navigationBarDark: Color;
|
||||
statusBarLight: Color;
|
||||
statusBarDark: Color;
|
||||
handler?: (bar: 'status' | 'navigation', resources: android.content.res.Resources) => boolean;
|
||||
}
|
||||
const systemColors = new WeakMap<androidx.appcompat.app.AppCompatActivity, ISystemColor>();
|
||||
|
||||
function setEnableEdgeToEdge(activity: androidx.appcompat.app.AppCompatActivity, existingColors: ISystemColor) {
|
||||
enableEdgeToEdge(activity, {
|
||||
statusBarLightColor: existingColors.statusBarLight,
|
||||
statusBarDarkColor: existingColors.statusBarDark,
|
||||
navigationBarLightColor: existingColors.navigationBarLight,
|
||||
navigationBarDarkColor: existingColors.navigationBarDark,
|
||||
handleDarkMode: existingColors?.handler ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
export function setStatusBarColor(options?: { activity?: androidx.appcompat.app.AppCompatActivity; lightColor?: Color; darkColor?: Color }): void {
|
||||
const statusBarLightColor = options?.lightColor ?? null;
|
||||
const statusBarDarkColor = options?.darkColor ?? null;
|
||||
const activity = options?.activity ?? getCurrentActivity();
|
||||
|
||||
if (activity) {
|
||||
const existingColors = systemColors.get(activity) ?? {
|
||||
navigationBarLight: DefaultLightScrim,
|
||||
navigationBarDark: DefaultDarkScrim,
|
||||
statusBarLight: DefaultStatusBarLight,
|
||||
statusBarDark: DefaultStatusBarDark,
|
||||
};
|
||||
existingColors.statusBarLight ??= statusBarLightColor;
|
||||
existingColors.statusBarDark ??= statusBarDarkColor;
|
||||
systemColors.set(getCurrentActivity(), existingColors);
|
||||
|
||||
setEnableEdgeToEdge(activity, existingColors);
|
||||
}
|
||||
}
|
||||
|
||||
export function setNavigationBarColor(options?: { activity?: androidx.appcompat.app.AppCompatActivity; lightColor?: Color; darkColor?: Color }): void {
|
||||
const navigationBarLightColor = options?.lightColor ?? null;
|
||||
const navigationBarDarkColor = options?.darkColor ?? null;
|
||||
const activity = options?.activity ?? getCurrentActivity();
|
||||
if (activity) {
|
||||
const existingColors = systemColors.get(activity) ?? {
|
||||
navigationBarLight: DefaultLightScrim,
|
||||
navigationBarDark: DefaultDarkScrim,
|
||||
statusBarLight: DefaultStatusBarLight,
|
||||
statusBarDark: DefaultStatusBarDark,
|
||||
};
|
||||
existingColors.navigationBarLight ??= navigationBarLightColor;
|
||||
existingColors.navigationBarDark ??= navigationBarDarkColor;
|
||||
systemColors.set(getCurrentActivity(), existingColors);
|
||||
|
||||
setEnableEdgeToEdge(activity, existingColors);
|
||||
}
|
||||
}
|
||||
|
||||
export function setDarkModeHandler(options?: { activity?: androidx.appcompat.app.AppCompatActivity; handler: (bar: 'status' | 'navigation', resources: android.content.res.Resources) => boolean }): void {
|
||||
const darkModeHandler = options?.handler ?? null;
|
||||
const activity = options?.activity ?? getCurrentActivity();
|
||||
if (activity) {
|
||||
const existingColors = systemColors.get(activity) ?? {
|
||||
navigationBarLight: DefaultLightScrim,
|
||||
navigationBarDark: DefaultDarkScrim,
|
||||
statusBarLight: DefaultStatusBarLight,
|
||||
statusBarDark: DefaultStatusBarDark,
|
||||
};
|
||||
|
||||
existingColors.handler ??= darkModeHandler;
|
||||
|
||||
systemColors.set(getCurrentActivity(), existingColors);
|
||||
|
||||
setEnableEdgeToEdge(activity, existingColors);
|
||||
}
|
||||
}
|
||||
|
||||
export function enableEdgeToEdge(
|
||||
activity: androidx.appcompat.app.AppCompatActivity,
|
||||
options?: {
|
||||
statusBarLightColor?: Color;
|
||||
statusBarDarkColor?: Color;
|
||||
navigationBarLightColor?: Color;
|
||||
navigationBarDarkColor?: Color;
|
||||
handleDarkMode?: (bar: 'status' | 'navigation', resources: android.content.res.Resources) => boolean;
|
||||
},
|
||||
): void {
|
||||
let handleDarkMode: org.nativescript.widgets.Utils.HandleDarkMode;
|
||||
let statusBarLight: number = 0;
|
||||
let statusBarDark: number = 0;
|
||||
let navigationBarLight: number = DefaultLightScrim.android;
|
||||
let navigationBarDark: number = DefaultDarkScrim.android;
|
||||
if (options) {
|
||||
if (typeof options.handleDarkMode === 'function') {
|
||||
handleDarkMode = new org.nativescript.widgets.Utils.HandleDarkMode({
|
||||
onHandle(bar, resources) {
|
||||
if (bar === 0) {
|
||||
return options.handleDarkMode('status', resources);
|
||||
} else {
|
||||
return options.handleDarkMode('navigation', resources);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
if (options.statusBarLightColor instanceof Color) {
|
||||
statusBarLight = options.statusBarLightColor.android;
|
||||
}
|
||||
if (options.statusBarDarkColor instanceof Color) {
|
||||
statusBarDark = options.statusBarDarkColor.android;
|
||||
}
|
||||
if (options.navigationBarLightColor instanceof Color) {
|
||||
navigationBarLight = options.navigationBarLightColor.android;
|
||||
}
|
||||
if (options.navigationBarDarkColor instanceof Color) {
|
||||
navigationBarDark = options.navigationBarDarkColor.android;
|
||||
}
|
||||
}
|
||||
|
||||
if (handleDarkMode) {
|
||||
org.nativescript.widgets.Utils.enableEdgeToEdge(activity, java.lang.Integer.valueOf(statusBarLight), java.lang.Integer.valueOf(statusBarDark), java.lang.Integer.valueOf(navigationBarLight), java.lang.Integer.valueOf(navigationBarDark), handleDarkMode);
|
||||
} else {
|
||||
org.nativescript.widgets.Utils.enableEdgeToEdge(activity, java.lang.Integer.valueOf(statusBarLight), java.lang.Integer.valueOf(statusBarDark), java.lang.Integer.valueOf(navigationBarLight), java.lang.Integer.valueOf(navigationBarDark));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user