1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16if (!('finalizeConstruction' in ViewPU.prototype)) {
17  Reflect.set(ViewPU.prototype, 'finalizeConstruction', () => {});
18}
19const display = globalThis.requireNapi('display');
20const window = globalThis.requireNapi('window');
21const hilog = globalThis.requireNapi('hilog');
22const LengthMetrics = globalThis.requireNapi('arkui.node').LengthMetrics;
23const curves = globalThis.requireNativeModule('ohos.curves');
24const mediaQuery = requireNapi('mediaquery');
25export var ExtraRegionPosition;
26(function (k3) {
27  k3[(k3['TOP'] = 1)] = 'TOP';
28  k3[(k3['BOTTOM'] = 2)] = 'BOTTOM';
29})(ExtraRegionPosition || (ExtraRegionPosition = {}));
30export var PresetSplitRatio;
31(function (s4) {
32  s4[(s4['LAYOUT_1V1'] = 1)] = 'LAYOUT_1V1';
33  s4[(s4['LAYOUT_2V3'] = 0.6666666666666666)] = 'LAYOUT_2V3';
34  s4[(s4['LAYOUT_3V2'] = 1.5)] = 'LAYOUT_3V2';
35})(PresetSplitRatio || (PresetSplitRatio = {}));
36function withDefaultValue(h3, i3) {
37  if (h3 === void 0 || h3 === null) {
38    return i3;
39  }
40  return h3;
41}
42function getSplitRatio(f3, g3) {
43  if (f3 === void 0 || f3 === null) {
44    return g3;
45  }
46  if (f3 <= 0) {
47    return g3;
48  }
49  return f3;
50}
51class Logger {
52  static debug(d3, ...e3) {
53    return hilog.debug(0x3900, 'FoldSplitContainer', d3, ...e3);
54  }
55  static info(b3, ...c3) {
56    return hilog.info(0x3900, 'FoldSplitContainer', b3, ...c3);
57  }
58  static error(z2, ...a3) {
59    return hilog.error(0x3900, 'FoldSplitContainer', z2, ...a3);
60  }
61}
62function initLayout() {
63  return {
64    size: { width: 0, height: 0 },
65    position: { x: 0, y: 0 },
66  };
67}
68export class FoldSplitContainer extends ViewPU {
69  constructor(t2, u2, v2, w2 = -1, x2 = undefined, y2) {
70    super(t2, v2, w2, y2);
71    if (typeof x2 === 'function') {
72      this.paramsGenerator_ = x2;
73    }
74    this.primary = undefined;
75    this.secondary = undefined;
76    this.extra = undefined;
77    this.__expandedLayoutOptions = new SynchedPropertyObjectOneWayPU(
78      u2.expandedLayoutOptions,
79      this,
80      'expandedLayoutOptions'
81    );
82    this.__hoverModeLayoutOptions = new SynchedPropertyObjectOneWayPU(
83      u2.hoverModeLayoutOptions,
84      this,
85      'hoverModeLayoutOptions'
86    );
87    this.__foldedLayoutOptions = new SynchedPropertyObjectOneWayPU(
88      u2.foldedLayoutOptions,
89      this,
90      'foldedLayoutOptions'
91    );
92    this.__animationOptions = new SynchedPropertyObjectOneWayPU(
93      u2.animationOptions,
94      this,
95      'animationOptions'
96    );
97    this.onHoverStatusChange = () => {};
98    this.__primaryLayout = new ObservedPropertyObjectPU(
99      initLayout(),
100      this,
101      'primaryLayout'
102    );
103    this.__secondaryLayout = new ObservedPropertyObjectPU(
104      initLayout(),
105      this,
106      'secondaryLayout'
107    );
108    this.__extraLayout = new ObservedPropertyObjectPU(
109      initLayout(),
110      this,
111      'extraLayout'
112    );
113    this.__extraOpacity = new ObservedPropertySimplePU(1, this, 'extraOpacity');
114    this.windowStatusType = window.WindowStatusType.UNDEFINED;
115    this.foldStatus = display.FoldStatus.FOLD_STATUS_UNKNOWN;
116    this.windowInstance = undefined;
117    this.containerSize = { width: 0, height: 0 };
118    this.containerGlobalPosition = { x: 0, y: 0 };
119    this.listener = undefined;
120    this.isSmallScreen = false;
121    this.isHoverMode = undefined;
122    this.setInitiallyProvidedValue(u2);
123    this.declareWatch('expandedLayoutOptions', this.updateLayout);
124    this.declareWatch('hoverModeLayoutOptions', this.updateLayout);
125    this.declareWatch('foldedLayoutOptions', this.updateLayout);
126    this.finalizeConstruction();
127  }
128  setInitiallyProvidedValue(s2) {
129    if (s2.primary !== undefined) {
130      this.primary = s2.primary;
131    }
132    if (s2.secondary !== undefined) {
133      this.secondary = s2.secondary;
134    }
135    if (s2.extra !== undefined) {
136      this.extra = s2.extra;
137    }
138    if (s2.expandedLayoutOptions === undefined) {
139      this.__expandedLayoutOptions.set({
140        horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
141        verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
142        isExtraRegionPerpendicular: true,
143        extraRegionPosition: ExtraRegionPosition.TOP,
144      });
145    }
146    if (s2.hoverModeLayoutOptions === undefined) {
147      this.__hoverModeLayoutOptions.set({
148        horizontalSplitRatio: PresetSplitRatio.LAYOUT_3V2,
149        showExtraRegion: false,
150        extraRegionPosition: ExtraRegionPosition.TOP,
151      });
152    }
153    if (s2.foldedLayoutOptions === undefined) {
154      this.__foldedLayoutOptions.set({
155        verticalSplitRatio: PresetSplitRatio.LAYOUT_1V1,
156      });
157    }
158    if (s2.animationOptions === undefined) {
159      this.__animationOptions.set(undefined);
160    }
161    if (s2.onHoverStatusChange !== undefined) {
162      this.onHoverStatusChange = s2.onHoverStatusChange;
163    }
164    if (s2.primaryLayout !== undefined) {
165      this.primaryLayout = s2.primaryLayout;
166    }
167    if (s2.secondaryLayout !== undefined) {
168      this.secondaryLayout = s2.secondaryLayout;
169    }
170    if (s2.extraLayout !== undefined) {
171      this.extraLayout = s2.extraLayout;
172    }
173    if (s2.extraOpacity !== undefined) {
174      this.extraOpacity = s2.extraOpacity;
175    }
176    if (s2.windowStatusType !== undefined) {
177      this.windowStatusType = s2.windowStatusType;
178    }
179    if (s2.foldStatus !== undefined) {
180      this.foldStatus = s2.foldStatus;
181    }
182    if (s2.windowInstance !== undefined) {
183      this.windowInstance = s2.windowInstance;
184    }
185    if (s2.containerSize !== undefined) {
186      this.containerSize = s2.containerSize;
187    }
188    if (s2.containerGlobalPosition !== undefined) {
189      this.containerGlobalPosition = s2.containerGlobalPosition;
190    }
191    if (s2.listener !== undefined) {
192      this.listener = s2.listener;
193    }
194    if (s2.isSmallScreen !== undefined) {
195      this.isSmallScreen = s2.isSmallScreen;
196    }
197    if (s2.isHoverMode !== undefined) {
198      this.isHoverMode = s2.isHoverMode;
199    }
200  }
201  updateStateVars(r2) {
202    this.__expandedLayoutOptions.reset(r2.expandedLayoutOptions);
203    this.__hoverModeLayoutOptions.reset(r2.hoverModeLayoutOptions);
204    this.__foldedLayoutOptions.reset(r2.foldedLayoutOptions);
205    this.__animationOptions.reset(r2.animationOptions);
206  }
207  purgeVariableDependenciesOnElmtId(q2) {
208    this.__expandedLayoutOptions.purgeDependencyOnElmtId(q2);
209    this.__hoverModeLayoutOptions.purgeDependencyOnElmtId(q2);
210    this.__foldedLayoutOptions.purgeDependencyOnElmtId(q2);
211    this.__animationOptions.purgeDependencyOnElmtId(q2);
212    this.__primaryLayout.purgeDependencyOnElmtId(q2);
213    this.__secondaryLayout.purgeDependencyOnElmtId(q2);
214    this.__extraLayout.purgeDependencyOnElmtId(q2);
215    this.__extraOpacity.purgeDependencyOnElmtId(q2);
216  }
217  aboutToBeDeleted() {
218    this.__expandedLayoutOptions.aboutToBeDeleted();
219    this.__hoverModeLayoutOptions.aboutToBeDeleted();
220    this.__foldedLayoutOptions.aboutToBeDeleted();
221    this.__animationOptions.aboutToBeDeleted();
222    this.__primaryLayout.aboutToBeDeleted();
223    this.__secondaryLayout.aboutToBeDeleted();
224    this.__extraLayout.aboutToBeDeleted();
225    this.__extraOpacity.aboutToBeDeleted();
226    SubscriberManager.Get().delete(this.id__());
227    this.aboutToBeDeletedInternal();
228  }
229  get expandedLayoutOptions() {
230    return this.__expandedLayoutOptions.get();
231  }
232  set expandedLayoutOptions(p2) {
233    this.__expandedLayoutOptions.set(p2);
234  }
235  get hoverModeLayoutOptions() {
236    return this.__hoverModeLayoutOptions.get();
237  }
238  set hoverModeLayoutOptions(f1) {
239    this.__hoverModeLayoutOptions.set(f1);
240  }
241  get foldedLayoutOptions() {
242    return this.__foldedLayoutOptions.get();
243  }
244  set foldedLayoutOptions(n2) {
245    this.__foldedLayoutOptions.set(n2);
246  }
247  get animationOptions() {
248    return this.__animationOptions.get();
249  }
250  set animationOptions(n4) {
251    this.__animationOptions.set(n4);
252  }
253  get primaryLayout() {
254    return this.__primaryLayout.get();
255  }
256  set primaryLayout(m2) {
257    this.__primaryLayout.set(m2);
258  }
259  get secondaryLayout() {
260    return this.__secondaryLayout.get();
261  }
262  set secondaryLayout(l2) {
263    this.__secondaryLayout.set(l2);
264  }
265  get extraLayout() {
266    return this.__extraLayout.get();
267  }
268  set extraLayout(k2) {
269    this.__extraLayout.set(k2);
270  }
271  get extraOpacity() {
272    return this.__extraOpacity.get();
273  }
274  set extraOpacity(l1) {
275    this.__extraOpacity.set(l1);
276  }
277  aboutToAppear() {
278    this.listener = mediaQuery.matchMediaSync('(width<=600vp)');
279    this.isSmallScreen = this.listener.matches;
280    this.listener.on('change', (m4) => {
281      this.isSmallScreen = m4.matches;
282    });
283    this.foldStatus = display.getFoldStatus();
284    display.on('foldStatusChange', (j4) => {
285      if (this.foldStatus !== j4) {
286        this.foldStatus = j4;
287        this.updateLayout();
288        this.updatePreferredOrientation();
289      }
290    });
291    window.getLastWindow(this.getUIContext().getHostContext(), (e4, f4) => {
292      if (e4 && e4.code) {
293        Logger.error(
294          'Failed to get window instance, error code: %{public}d',
295          e4.code
296        );
297        return;
298      }
299      const g4 = f4.getWindowProperties().id;
300      if (g4 < 0) {
301        Logger.error(
302          'Failed to get window instance because the window id is invalid. window id: %{public}d',
303          g4
304        );
305        return;
306      }
307      this.windowInstance = f4;
308      this.updatePreferredOrientation();
309      this.windowInstance.on('windowStatusChange', (i4) => {
310        this.windowStatusType = i4;
311      });
312    });
313  }
314  aboutToDisappear() {
315    if (this.listener) {
316      this.listener.off('change');
317      this.listener = undefined;
318    }
319    display.off('foldStatusChange');
320    if (this.windowInstance) {
321      this.windowInstance.off('windowStatusChange');
322    }
323  }
324  initialRender() {
325    this.observeComponentCreation2((y1, z1) => {
326      Stack.create();
327      Stack.id('$$FoldSplitContainer$Stack$$');
328      Stack.width('100%');
329      Stack.height('100%');
330      Stack.onSizeChange((b2, d4) => {
331        this.updateContainerSize(d4);
332        this.updateContainerPosition();
333        this.updateLayout();
334      });
335    }, Stack);
336    this.observeComponentCreation2((w1, x1) => {
337      Column.create();
338      Column.size(this.primaryLayout.size);
339      Column.position({
340        start: LengthMetrics.vp(this.primaryLayout.position.x),
341        top: LengthMetrics.vp(this.primaryLayout.position.y),
342      });
343      Column.clip(true);
344    }, Column);
345    this.observeComponentCreation2((u1, v1) => {
346      If.create();
347      if (this.primary) {
348        this.ifElseBranchUpdateFunction(0, () => {
349          this.primary.bind(this)(this);
350        });
351      } else {
352        this.ifElseBranchUpdateFunction(1, () => {});
353      }
354    }, If);
355    If.pop();
356    Column.pop();
357    this.observeComponentCreation2((n1, o1) => {
358      Column.create();
359      Column.size(this.secondaryLayout.size);
360      Column.position({
361        start: LengthMetrics.vp(this.secondaryLayout.position.x),
362        top: LengthMetrics.vp(this.secondaryLayout.position.y),
363      });
364      Column.clip(true);
365    }, Column);
366    this.observeComponentCreation2((u3, v3) => {
367      If.create();
368      if (this.secondary) {
369        this.ifElseBranchUpdateFunction(0, () => {
370          this.secondary.bind(this)(this);
371        });
372      } else {
373        this.ifElseBranchUpdateFunction(1, () => {});
374      }
375    }, If);
376    If.pop();
377    Column.pop();
378    this.observeComponentCreation2((i2, j2) => {
379      If.create();
380      if (this.extra) {
381        this.ifElseBranchUpdateFunction(0, () => {
382          this.observeComponentCreation2((n3, o3) => {
383            Column.create();
384            Context.animation({ curve: Curve.Linear, duration: 250 });
385            Column.opacity(this.extraOpacity);
386            Context.animation(null);
387            Column.size(this.extraLayout.size);
388            Column.position({
389              start: LengthMetrics.vp(this.extraLayout.position.x),
390              top: LengthMetrics.vp(this.extraLayout.position.y),
391            });
392            Column.clip(true);
393          }, Column);
394          this.extra?.bind(this)?.(this);
395          Column.pop();
396        });
397      } else {
398        this.ifElseBranchUpdateFunction(1, () => {});
399      }
400    }, If);
401    If.pop();
402    Stack.pop();
403  }
404  dispatchHoverStatusChange(b4) {
405    if (this.onHoverStatusChange) {
406      this.onHoverStatusChange({
407        foldStatus: this.foldStatus,
408        isHoverMode: b4,
409        appRotation: display.getDefaultDisplaySync().rotation,
410        windowStatusType: this.windowStatusType,
411      });
412    }
413  }
414  hasExtraRegion() {
415    return !!this.extra;
416  }
417  async updatePreferredOrientation() {
418    if (this.windowInstance) {
419      try {
420        if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
421          await this.windowInstance.setPreferredOrientation(
422            window.Orientation.AUTO_ROTATION_PORTRAIT
423          );
424        } else {
425          await this.windowInstance.setPreferredOrientation(
426            window.Orientation.AUTO_ROTATION
427          );
428        }
429      } catch (i1) {
430        Logger.error('Failed to update preferred orientation.');
431      }
432    }
433  }
434  updateContainerSize(a4) {
435    this.containerSize.width = a4.width;
436    this.containerSize.height = a4.height;
437  }
438  updateContainerPosition() {
439    const y3 = this.getUIContext();
440    const z3 = y3.getFrameNodeById('$$FoldSplitContainer$Stack$$');
441    if (z3) {
442      this.containerGlobalPosition = z3.getPositionToWindow();
443    }
444  }
445  updateLayout() {
446    let t1 = false;
447    let g1;
448    if (this.isSmallScreen) {
449      g1 = this.getFoldedRegionLayouts();
450    } else {
451      if (this.foldStatus === display.FoldStatus.FOLD_STATUS_EXPANDED) {
452        g1 = this.getExpandedRegionLayouts();
453      } else if (
454        this.foldStatus === display.FoldStatus.FOLD_STATUS_HALF_FOLDED
455      ) {
456        if (this.isPortraitOrientation()) {
457          g1 = this.getExpandedRegionLayouts();
458        } else {
459          g1 = this.getHoverModeRegionLayouts();
460          t1 = true;
461        }
462      } else if (this.foldStatus === display.FoldStatus.FOLD_STATUS_FOLDED) {
463        g1 = this.getFoldedRegionLayouts();
464      } else {
465        g1 = this.getExpandedRegionLayouts();
466      }
467    }
468    if (this.animationOptions === null) {
469      this.primaryLayout = g1.primary;
470      this.secondaryLayout = g1.secondary;
471      this.extraLayout = g1.extra;
472    } else if (this.animationOptions === void 0) {
473      Context.animateTo({ curve: curves.springMotion(0.35, 1, 0) }, () => {
474        this.primaryLayout = g1.primary;
475        this.secondaryLayout = g1.secondary;
476        this.extraLayout = g1.extra;
477      });
478    } else {
479      Context.animateTo(this.animationOptions, () => {
480        this.primaryLayout = g1.primary;
481        this.secondaryLayout = g1.secondary;
482        this.extraLayout = g1.extra;
483      });
484    }
485    if (this.isHoverMode !== t1) {
486      this.dispatchHoverStatusChange(t1);
487      this.isHoverMode = t1;
488    }
489    if (t1 && !this.hoverModeLayoutOptions.showExtraRegion) {
490      this.extraOpacity = 0;
491    } else {
492      this.extraOpacity = 1;
493    }
494  }
495  getExpandedRegionLayouts() {
496    const x = this.containerSize.width;
497    const y = this.containerSize.height;
498    const z = initLayout();
499    const a1 = initLayout();
500    const b1 = initLayout();
501    const c1 = getSplitRatio(
502      this.expandedLayoutOptions.horizontalSplitRatio,
503      PresetSplitRatio.LAYOUT_3V2
504    );
505    const d1 = getSplitRatio(
506      this.expandedLayoutOptions.verticalSplitRatio,
507      PresetSplitRatio.LAYOUT_1V1
508    );
509    if (this.hasExtraRegion()) {
510      b1.size.width = x / (c1 + 1);
511    } else {
512      b1.size.width = 0;
513    }
514    a1.size.height = y / (d1 + 1);
515    z.size.height = y - a1.size.height;
516    z.position.x = 0;
517    a1.position.x = 0;
518    z.position.y = 0;
519    a1.position.y = z.size.height;
520    const e1 = withDefaultValue(
521      this.expandedLayoutOptions.isExtraRegionPerpendicular,
522      true
523    );
524    if (e1) {
525      z.size.width = x - b1.size.width;
526      a1.size.width = x - b1.size.width;
527      b1.size.height = y;
528      b1.position.x = z.size.width;
529      b1.position.y = 0;
530    } else {
531      const j1 = withDefaultValue(
532        this.expandedLayoutOptions.extraRegionPosition,
533        ExtraRegionPosition.TOP
534      );
535      if (j1 === ExtraRegionPosition.BOTTOM) {
536        z.size.width = x;
537        a1.size.width = x - b1.size.width;
538        b1.size.height = a1.size.height;
539        b1.position.x = a1.size.width;
540        b1.position.y = z.size.height;
541      } else {
542        z.size.width = x - b1.size.width;
543        a1.size.width = x;
544        b1.size.height = z.size.height;
545        b1.position.x = z.size.width;
546        b1.position.y = 0;
547      }
548    }
549    return { primary: z, secondary: a1, extra: b1 };
550  }
551  getHoverModeRegionLayouts() {
552    const o = this.containerSize.width;
553    const p = this.containerSize.height;
554    const q = initLayout();
555    const r = initLayout();
556    const s = initLayout();
557    const t = this.getCreaseRegionRect();
558    q.position.x = 0;
559    q.position.y = 0;
560    r.position.x = 0;
561    r.position.y = t.top + t.height;
562    r.size.height = p - r.position.y;
563    q.size.height = t.top;
564    const u = withDefaultValue(
565      this.hoverModeLayoutOptions.showExtraRegion,
566      false
567    );
568    if (!u) {
569      q.size.width = o;
570      r.size.width = o;
571      s.position.x = o;
572      const r1 = withDefaultValue(
573        this.expandedLayoutOptions.isExtraRegionPerpendicular,
574        true
575      );
576      if (r1) {
577        s.size.height = this.extraLayout.size.height;
578      } else {
579        const s1 = withDefaultValue(
580          this.expandedLayoutOptions.extraRegionPosition,
581          ExtraRegionPosition.TOP
582        );
583        if (s1 === ExtraRegionPosition.BOTTOM) {
584          s.size.height = r.size.height;
585          s.position.y = r.position.y;
586        } else {
587          s.size.height = q.size.height;
588          s.position.y = 0;
589        }
590      }
591    } else {
592      const p1 = getSplitRatio(
593        this.hoverModeLayoutOptions.horizontalSplitRatio,
594        PresetSplitRatio.LAYOUT_3V2
595      );
596      const q1 = withDefaultValue(
597        this.hoverModeLayoutOptions.extraRegionPosition,
598        ExtraRegionPosition.TOP
599      );
600      if (this.hasExtraRegion()) {
601        s.size.width = o / (p1 + 1);
602      } else {
603        s.size.width = 0;
604      }
605      if (q1 === ExtraRegionPosition.BOTTOM) {
606        q.size.width = o;
607        r.size.width = o - s.size.width;
608        s.size.height = r.size.height;
609        s.position.x = r.size.width;
610        s.position.y = r.position.y;
611      } else {
612        s.size.height = q.size.height;
613        q.size.width = o - s.size.width;
614        r.size.width = o;
615        s.position.x = q.position.x + q.size.width;
616        s.position.y = 0;
617      }
618    }
619    return { primary: q, secondary: r, extra: s };
620  }
621  getFoldedRegionLayouts() {
622    const i = this.containerSize.width;
623    const j = this.containerSize.height;
624    const k = initLayout();
625    const l = initLayout();
626    const m = initLayout();
627    const n = getSplitRatio(
628      this.foldedLayoutOptions.verticalSplitRatio,
629      PresetSplitRatio.LAYOUT_1V1
630    );
631    l.size.height = j / (n + 1);
632    k.size.height = j - l.size.height;
633    m.size.height = 0;
634    k.size.width = i;
635    l.size.width = i;
636    m.size.width = 0;
637    k.position.x = 0;
638    l.position.x = 0;
639    m.position.x = i;
640    k.position.y = 0;
641    l.position.y = k.size.height;
642    m.position.y = 0;
643    return { primary: k, secondary: l, extra: m };
644  }
645  getCreaseRegionRect() {
646    const b = display.getCurrentFoldCreaseRegion();
647    const c = b.creaseRects;
648    let d = 0;
649    let e = 0;
650    let f = 0;
651    let g = 0;
652    if (c && c.length) {
653      const h = c[0];
654      d = px2vp(h.left) - this.containerGlobalPosition.x;
655      e = px2vp(h.top) - this.containerGlobalPosition.y;
656      f = px2vp(h.width);
657      g = px2vp(h.height);
658    }
659    return { left: d, top: e, width: f, height: g };
660  }
661  isPortraitOrientation() {
662    const a = display.getDefaultDisplaySync();
663    switch (a.orientation) {
664      case display.Orientation.PORTRAIT:
665      case display.Orientation.PORTRAIT_INVERTED:
666        return true;
667      case display.Orientation.LANDSCAPE:
668      case display.Orientation.LANDSCAPE_INVERTED:
669      default:
670        return false;
671    }
672  }
673  rerender() {
674    this.updateDirtyElements();
675  }
676}
677
678export default { ExtraRegionPosition, PresetSplitRatio, FoldSplitContainer };
679