/* * 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 };