* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
if (!('finalizeConstruction' in ViewPU.prototype)) {
Reflect.set(ViewPU.prototype, 'finalizeConstruction', () => {});
}
const display = globalThis.requireNapi('display');
const window = globalThis.requireNapi('window');
const hilog = globalThis.requireNapi('hilog');
const LengthMetrics = globalThis.requireNapi('arkui.node').LengthMetrics;
const curves = globalThis.requireNativeModule('ohos.curves');
const mediaQuery = requireNapi('mediaquery');
export var ExtraRegionPosition;
(function (k3) {
k3[(k3.TOP = 1)] = 'TOP';
k3[(k3.BOTTOM = 2)] = 'BOTTOM';
})(ExtraRegionPosition || (ExtraRegionPosition = {}));
export var PresetSplitRatio;
(function (s4) {
s4[(s4.LAYOUT_1V1 = 1)] = 'LAYOUT_1V1';
s4[(s4.LAYOUT_2V3 = 0.6666666666666666)] = 'LAYOUT_2V3';
s4[(s4.LAYOUT_3V2 = 1.5)] = 'LAYOUT_3V2';
})(PresetSplitRatio || (PresetSplitRatio = {}));
function withDefaultValue(h3, i3) {
if (h3 === void 0 || h3 === null) {
return i3;
}
return h3;
}
function getSplitRatio(f3, g3) {
if (f3 === void 0 || f3 === null) {
return g3;
}
if (f3 <= 0) {
return g3;
}
return f3;
}
class Logger {
static debug(d3, ...e3) {
return hilog.debug(0x3900, 'FoldSplitContainer', d3, ...e3);
}
static info(b3, ...c3) {
return hilog.info(0x3900, 'FoldSplitContainer', b3, ...c3);
}
static error(z2, ...a3) {
return hilog.error(0x3900, 'FoldSplitContainer', z2, ...a3);
}
}
function initLayout() {
return {
size: { width: 0, height: 0 },
position: { x: 0, y: 0 },
};
}
export class FoldSplitContainer extends ViewPU {
constructor(t2, u2, v2, w2 = -1, x2 = undefined, y2) {
super(t2, v2, w2, y2);
if (typeof x2 === 'function') {
this.paramsGenerator_ = x2;
}
this.primary = undefined;
this.secondary = undefined;
this.extra = undefined;
this.__expandedLayoutOptions = new SynchedPropertyObjectOneWayPU(
u2.expandedLayoutOptions,
this,
'expandedLayoutOptions'
);
this.__hoverModeLayoutOptions = new SynchedPropertyObjectOneWayPU(
u2.hoverModeLayoutOptions,
this,
'hoverModeLayoutOptions'
);
this.__foldedLayoutOptions = new SynchedPropertyObjectOneWayPU(
u2.foldedLayoutOptions,
this,
'foldedLayoutOptions'
);
this.__animationOptions = new SynchedPropertyObjectOneWayPU(
u2.animationOptions,
this,
'animationOptions'
);
this.onHoverStatusChange = () => {};
this.__primaryLayout = new ObservedPropertyObjectPU(
initLayout(),
this,
'primaryLayout'
);
this.__secondaryLayout = new ObservedPropertyObjectPU(
initLayout(),
this,
'secondaryLayout'
);
this.__extraLayout = new ObservedPropertyObjectPU(
initLayout(),
this,
'extraLayout'
);
this.__extraOpacity = new ObservedPropertySimplePU(1, this, 'extraOpacity');
this.windowStatusType = window.WindowStatusType.UNDEFINED;
this.foldStatus = display.FoldStatus.FOLD_STATUS_UNKNOWN;
this.rotation = 0;
this.windowInstance = undefined;
this.containerSize = { width: 0, height: 0 };
this.containerGlobalPosition = { x: 0, y: 0 };
this.listener = undefined;
this.isSmallScreen = false;
this.isHoverMode = undefined;
this.setInitiallyProvidedValue(u2);
this.declareWatch('expandedLayoutOptions', this.updateLayout);
this.declareWatch('hoverModeLayoutOptions', this.updateLayout);
this.declareWatch('foldedLayoutOptions', this.updateLayout);
this.finalizeConstruction();
}
setInitiallyProvidedValue(s2) {
if (s2.primary !== undefined) {
this.primary = s2.primary;
}
if (s2.secondary !== undefined) {
this.secondary = s2.secondary;
}
if (s2.extra !== undefined) {
this.extra = s2.extra;
}
if (s2.expandedLayoutOptions === undefined) {
this.__expandedLayoutOptions.set({
horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
isExtraRegionPerpendicular: true,
extraRegionPosition: ExtraRegionPosition.TOP,
});
}
if (s2.hoverModeLayoutOptions === undefined) {
this.__hoverModeLayoutOptions.set({
horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
showExtraRegion: false,
extraRegionPosition: ExtraRegionPosition.TOP,
});
}
if (s2.foldedLayoutOptions === undefined) {
this.__foldedLayoutOptions.set({
verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
});
}
if (s2.animationOptions === undefined) {
this.__animationOptions.set(undefined);
}
if (s2.onHoverStatusChange !== undefined) {
this.onHoverStatusChange = s2.onHoverStatusChange;
}
if (s2.primaryLayout !== undefined) {
this.primaryLayout = s2.primaryLayout;
}
if (s2.secondaryLayout !== undefined) {
this.secondaryLayout = s2.secondaryLayout;
}
if (s2.extraLayout !== undefined) {
this.extraLayout = s2.extraLayout;
}
if (s2.extraOpacity !== undefined) {
this.extraOpacity = s2.extraOpacity;
}
if (s2.windowStatusType !== undefined) {
this.windowStatusType = s2.windowStatusType;
}
if (s2.foldStatus !== undefined) {
this.foldStatus = s2.foldStatus;
}
if (s2.windowInstance !== undefined) {
this.windowInstance = s2.windowInstance;
}
if (s2.containerSize !== undefined) {
this.containerSize = s2.containerSize;
}
if (s2.containerGlobalPosition !== undefined) {
this.containerGlobalPosition = s2.containerGlobalPosition;
}
if (s2.listener !== undefined) {
this.listener = s2.listener;
}
if (s2.isSmallScreen !== undefined) {
this.isSmallScreen = s2.isSmallScreen;
}
if (s2.isHoverMode !== undefined) {
this.isHoverMode = s2.isHoverMode;
}
}
updateStateVars(r2) {
this.__expandedLayoutOptions.reset(r2.expandedLayoutOptions);
this.__hoverModeLayoutOptions.reset(r2.hoverModeLayoutOptions);
this.__foldedLayoutOptions.reset(r2.foldedLayoutOptions);
this.__animationOptions.reset(r2.animationOptions);
}
purgeVariableDependenciesOnElmtId(q2) {
this.__expandedLayoutOptions.purgeDependencyOnElmtId(q2);
this.__hoverModeLayoutOptions.purgeDependencyOnElmtId(q2);
this.__foldedLayoutOptions.purgeDependencyOnElmtId(q2);
this.__animationOptions.purgeDependencyOnElmtId(q2);
this.__primaryLayout.purgeDependencyOnElmtId(q2);
this.__secondaryLayout.purgeDependencyOnElmtId(q2);
this.__extraLayout.purgeDependencyOnElmtId(q2);
this.__extraOpacity.purgeDependencyOnElmtId(q2);
}
aboutToBeDeleted() {
this.__expandedLayoutOptions.aboutToBeDeleted();
this.__hoverModeLayoutOptions.aboutToBeDeleted();
this.__foldedLayoutOptions.aboutToBeDeleted();
this.__animationOptions.aboutToBeDeleted();
this.__primaryLayout.aboutToBeDeleted();
this.__secondaryLayout.aboutToBeDeleted();
this.__extraLayout.aboutToBeDeleted();
this.__extraOpacity.aboutToBeDeleted();
SubscriberManager.Get().delete(this.id__());
this.aboutToBeDeletedInternal();
}
get expandedLayoutOptions() {
return this.__expandedLayoutOptions.get();
}
set expandedLayoutOptions(p2) {
this.__expandedLayoutOptions.set(p2);
}
get hoverModeLayoutOptions() {
return this.__hoverModeLayoutOptions.get();
}
set hoverModeLayoutOptions(f1) {
this.__hoverModeLayoutOptions.set(f1);
}
get foldedLayoutOptions() {
return this.__foldedLayoutOptions.get();
}
set foldedLayoutOptions(n2) {
this.__foldedLayoutOptions.set(n2);
}
get animationOptions() {
return this.__animationOptions.get();
}
set animationOptions(n4) {
this.__animationOptions.set(n4);
}
get primaryLayout() {
return this.__primaryLayout.get();
}
set primaryLayout(m2) {
this.__primaryLayout.set(m2);
}
get secondaryLayout() {
return this.__secondaryLayout.get();
}
set secondaryLayout(l2) {
this.__secondaryLayout.set(l2);
}
get extraLayout() {
return this.__extraLayout.get();
}
set extraLayout(k2) {
this.__extraLayout.set(k2);
}
get extraOpacity() {
return this.__extraOpacity.get();
}
set extraOpacity(l1) {
this.__extraOpacity.set(l1);
}
aboutToAppear() {
this.listener = mediaQuery.matchMediaSync('(width<=600vp)');
this.isSmallScreen = this.listener.matches;
this.listener.on('change', (m4) => {
this.isSmallScreen = m4.matches;
});
try {
this.foldStatus = display.getFoldStatus();
} catch (exception) {
Logger.error('Failed getFoldStatus. code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
try {
display.on('foldStatusChange', (j4) => {
if (this.foldStatus !== j4) {
this.foldStatus = j4;
this.updateLayout();
this.updatePreferredOrientation();
}
});
} catch (exception) {
Logger.error('Failed display.on foldStatusChange. code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
try {
window.getLastWindow(this.getUIContext().getHostContext(), (e4, f4) => {
if (e4 && e4.code) {
Logger.error(
'Failed to get window instance, error code: %{public}d',
e4.code
);
return;
}
const g4 = f4.getWindowProperties().id;
if (g4 < 0) {
Logger.error(
'Failed to get window instance because the window id is invalid. window id: %{public}d', g4);
return;
}
this.windowInstance = f4;
this.updatePreferredOrientation();
this.dealWindowStatusChange();
});
} catch (exception) {
Logger.error('Failed getLastWindow code:%{public}d, message:%{public}s', exception.code, exception.message);
}
}
dealWindowStatusChange() {
try {
this.windowInstance.on('windowStatusChange', (i4) => {
this.windowStatusType = i4;
});
} catch (exception) {
Logger.error('Failed windowInstance.on windowStatusChange. code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
}
aboutToDisappear() {
if (this.listener) {
this.listener.off('change');
this.listener = undefined;
}
try {
display.off('foldStatusChange');
} catch (exception) {
Logger.error('Failed display.off foldStatusChange. code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
if (this.windowInstance) {
this.windowInstance.off('windowStatusChange');
}
}
initialRender() {
this.observeComponentCreation2((y1, z1) => {
Stack.create();
Stack.id('$$FoldSplitContainer$Stack$$');
Stack.width('100%');
Stack.height('100%');
Stack.onSizeChange((b2, d4) => {
this.updateContainerSize(d4);
this.updateContainerPosition();
this.updateLayout();
});
}, Stack);
this.observeComponentCreation2((w1, x1) => {
Column.create();
Column.size(this.primaryLayout.size);
Column.position({
start: LengthMetrics.vp(this.primaryLayout.position.x),
top: LengthMetrics.vp(this.primaryLayout.position.y),
});
Column.clip(true);
}, Column);
this.observeComponentCreation2((u1, v1) => {
If.create();
if (this.primary) {
this.ifElseBranchUpdateFunction(0, () => {
this.primary.bind(this)(this);
});
} else {
this.ifElseBranchUpdateFunction(1, () => {});
}
}, If);
If.pop();
Column.pop();
this.observeComponentCreation2((n1, o1) => {
Column.create();
Column.size(this.secondaryLayout.size);
Column.position({
start: LengthMetrics.vp(this.secondaryLayout.position.x),
top: LengthMetrics.vp(this.secondaryLayout.position.y),
});
Column.clip(true);
}, Column);
this.observeComponentCreation2((u3, v3) => {
If.create();
if (this.secondary) {
this.ifElseBranchUpdateFunction(0, () => {
this.secondary.bind(this)(this);
});
} else {
this.ifElseBranchUpdateFunction(1, () => {});
}
}, If);
If.pop();
Column.pop();
this.observeComponentCreation2((i2, j2) => {
If.create();
if (this.extra) {
this.ifElseBranchUpdateFunction(0, () => {
this.observeComponentCreation2((n3, o3) => {
Column.create();
Context.animation({ curve: Curve.Linear, duration: 250 });
Column.opacity(this.extraOpacity);
Context.animation(null);
Column.size(this.extraLayout.size);
Column.position({
start: LengthMetrics.vp(this.extraLayout.position.x),
top: LengthMetrics.vp(this.extraLayout.position.y),
});
Column.clip(true);
}, Column);
this.extra?.bind(this)?.(this);
Column.pop();
});
} else {
this.ifElseBranchUpdateFunction(1, () => {});
}
}, If);
If.pop();
Stack.pop();
}
dispatchHoverStatusChange(b4) {
if (this.onHoverStatusChange) {
try {
this.rotation = display.getDefaultDisplaySync().rotation;
} catch (exception) {
Logger.error('Failed display.getDefaultDisplaySync(). code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
this.onHoverStatusChange({
foldStatus: this.foldStatus,
isHoverMode: b4,
appRotation: this.rotation,
windowStatusType: this.windowStatusType,
});
}
}
hasExtraRegion() {
return !!this.extra;
}
async updatePreferredOrientation() {
if (this.windowInstance) {
try {
if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
await this.windowInstance.setPreferredOrientation(
window.Orientation.AUTO_ROTATION_PORTRAIT
);
} else {
await this.windowInstance.setPreferredOrientation(
window.Orientation.AUTO_ROTATION
);
}
} catch (i1) {
Logger.error('Failed to update preferred orientation.');
}
}
}
updateContainerSize(a4) {
this.containerSize.width = a4.width;
this.containerSize.height = a4.height;
}
updateContainerPosition() {
const y3 = this.getUIContext();
const z3 = y3.getFrameNodeById('$$FoldSplitContainer$Stack$$');
if (z3) {
this.containerGlobalPosition = z3.getPositionToWindow();
}
}
updateLayout() {
let t1 = false;
let g1;
if (this.isSmallScreen) {
g1 = this.getFoldedRegionLayouts();
} else {
if (this.foldStatus === display.FoldStatus.FOLD_STATUS_EXPANDED) {
g1 = this.getExpandedRegionLayouts();
} else if (
this.foldStatus === display.FoldStatus.FOLD_STATUS_HALF_FOLDED
) {
if (this.isPortraitOrientation()) {
g1 = this.getExpandedRegionLayouts();
} else {
g1 = this.getHoverModeRegionLayouts();
t1 = true;
}
} else if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
g1 = this.getFoldedRegionLayouts();
} else {
g1 = this.getExpandedRegionLayouts();
}
}
if (this.animationOptions === null) {
this.primaryLayout = g1.primary;
this.secondaryLayout = g1.secondary;
this.extraLayout = g1.extra;
} else if (this.animationOptions === void 0) {
Context.animateTo({ curve: curves.springMotion(0.35, 1, 0) }, () => {
this.primaryLayout = g1.primary;
this.secondaryLayout = g1.secondary;
this.extraLayout = g1.extra;
});
} else {
Context.animateTo(this.animationOptions, () => {
this.primaryLayout = g1.primary;
this.secondaryLayout = g1.secondary;
this.extraLayout = g1.extra;
});
}
if (this.isHoverMode !== t1) {
this.dispatchHoverStatusChange(t1);
this.isHoverMode = t1;
}
if (t1 && !this.hoverModeLayoutOptions.showExtraRegion) {
this.extraOpacity = 0;
} else {
this.extraOpacity = 1;
}
}
getExpandedRegionLayouts() {
const x = this.containerSize.width;
const y = this.containerSize.height;
const z = initLayout();
const a1 = initLayout();
const b1 = initLayout();
const c1 = getSplitRatio(
this.expandedLayoutOptions.horizontalSplitRatio,
PresetSplitRatio.LAYOUT_3V2
);
const d1 = getSplitRatio(
this.expandedLayoutOptions.verticalSplitRatio,
PresetSplitRatio.LAYOUT_1V1
);
if (this.hasExtraRegion()) {
b1.size.width = x / (c1 + 1);
} else {
b1.size.width = 0;
}
a1.size.height = y / (d1 + 1);
z.size.height = y - a1.size.height;
z.position.x = 0;
a1.position.x = 0;
z.position.y = 0;
a1.position.y = z.size.height;
const e1 = withDefaultValue(
this.expandedLayoutOptions.isExtraRegionPerpendicular,
true
);
if (e1) {
z.size.width = x - b1.size.width;
a1.size.width = x - b1.size.width;
b1.size.height = y;
b1.position.x = z.size.width;
b1.position.y = 0;
} else {
const j1 = withDefaultValue(
this.expandedLayoutOptions.extraRegionPosition,
ExtraRegionPosition.TOP
);
if (j1 === ExtraRegionPosition.BOTTOM) {
z.size.width = x;
a1.size.width = x - b1.size.width;
b1.size.height = a1.size.height;
b1.position.x = a1.size.width;
b1.position.y = z.size.height;
} else {
z.size.width = x - b1.size.width;
a1.size.width = x;
b1.size.height = z.size.height;
b1.position.x = z.size.width;
b1.position.y = 0;
}
}
return { primary: z, secondary: a1, extra: b1 };
}
getHoverModeRegionLayouts() {
const o = this.containerSize.width;
const p = this.containerSize.height;
const q = initLayout();
const r = initLayout();
const s = initLayout();
const t = this.getCreaseRegionRect();
q.position.x = 0;
q.position.y = 0;
r.position.x = 0;
r.position.y = t.top + t.height;
r.size.height = p - r.position.y;
q.size.height = t.top;
const u = withDefaultValue(
this.hoverModeLayoutOptions.showExtraRegion,
false
);
if (!u) {
q.size.width = o;
r.size.width = o;
s.position.x = o;
const r1 = withDefaultValue(
this.expandedLayoutOptions.isExtraRegionPerpendicular,
true
);
if (r1) {
s.size.height = this.extraLayout.size.height;
} else {
const s1 = withDefaultValue(
this.expandedLayoutOptions.extraRegionPosition,
ExtraRegionPosition.TOP
);
if (s1 === ExtraRegionPosition.BOTTOM) {
s.size.height = r.size.height;
s.position.y = r.position.y;
} else {
s.size.height = q.size.height;
s.position.y = 0;
}
}
} else {
const p1 = getSplitRatio(
this.hoverModeLayoutOptions.horizontalSplitRatio,
PresetSplitRatio.LAYOUT_3V2
);
const q1 = withDefaultValue(
this.hoverModeLayoutOptions.extraRegionPosition,
ExtraRegionPosition.TOP
);
if (this.hasExtraRegion()) {
s.size.width = o / (p1 + 1);
} else {
s.size.width = 0;
}
if (q1 === ExtraRegionPosition.BOTTOM) {
q.size.width = o;
r.size.width = o - s.size.width;
s.size.height = r.size.height;
s.position.x = r.size.width;
s.position.y = r.position.y;
} else {
s.size.height = q.size.height;
q.size.width = o - s.size.width;
r.size.width = o;
s.position.x = q.position.x + q.size.width;
s.position.y = 0;
}
}
return { primary: q, secondary: r, extra: s };
}
getFoldedRegionLayouts() {
const i = this.containerSize.width;
const j = this.containerSize.height;
const k = initLayout();
const l = initLayout();
const m = initLayout();
const n = getSplitRatio(
this.foldedLayoutOptions.verticalSplitRatio,
PresetSplitRatio.LAYOUT_1V1
);
l.size.height = j / (n + 1);
k.size.height = j - l.size.height;
m.size.height = 0;
k.size.width = i;
l.size.width = i;
m.size.width = 0;
k.position.x = 0;
l.position.x = 0;
m.position.x = i;
k.position.y = 0;
l.position.y = k.size.height;
m.position.y = 0;
return { primary: k, secondary: l, extra: m };
}
getCreaseRegionRect() {
const b = display.getCurrentFoldCreaseRegion();
const c = b.creaseRects;
let d = 0;
let e = 0;
let f = 0;
let g = 0;
if (c && c.length) {
const h = c[0];
d = px2vp(h.left) - this.containerGlobalPosition.x;
e = px2vp(h.top) - this.containerGlobalPosition.y;
f = px2vp(h.width);
g = px2vp(h.height);
}
return { left: d, top: e, width: f, height: g };
}
isPortraitOrientation() {
let a;
try {
a = display.getDefaultDisplaySync();
} catch (exception) {
Logger.error('Failed getDefaultDisplaySync. code:%{public}d, message:%{public}s',
exception.code, exception.message);
}
switch (a.orientation) {
case display.Orientation.PORTRAIT:
case display.Orientation.PORTRAIT_INVERTED:
return true;
case display.Orientation.LANDSCAPE:
case display.Orientation.LANDSCAPE_INVERTED:
default:
return false;
}
}
rerender() {
this.updateDirtyElements();
}
}
export default { ExtraRegionPosition, PresetSplitRatio, FoldSplitContainer };