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
16import pip from '@ohos.pip';
17import { NodeController, FrameNode, TypedFrameNode, UIContext } from '@kit.ArkUI';
18
19const TAG: string = 'PiPContent';
20const ABOUT_TO_STOP = 3;
21
22class XCNodeController extends NodeController {
23  private mXComponent: TypedFrameNode<XComponentInterface, XComponentAttribute>;
24  private node: FrameNode | null = null;
25
26  constructor(xComponent: TypedFrameNode<XComponentInterface, XComponentAttribute>) {
27    super();
28    this.mXComponent = xComponent;
29  }
30
31  makeNode(uiContext: UIContext): FrameNode | null {
32    this.node = new FrameNode(uiContext);
33    this.node.appendChild(this.mXComponent);
34    return this.node;
35  }
36
37  removeNode() {
38    this.node?.removeChild(this.mXComponent);
39  }
40}
41
42@Entry
43@Component
44struct PiPContent {
45  private xComponentController: XComponentController = new XComponentController();
46  private nodeController: NodeController | null = null;
47  private mXCNodeController: XCNodeController | null = null;
48  private useNode: boolean = false;
49  private xComponent: TypedFrameNode<XComponentInterface, XComponentAttribute> | null = null;
50  xComponentId: string = 'pipContent';
51  xComponentType: string = 'surface';
52
53  aboutToAppear(): void {
54    this.nodeController = pip.getCustomUIController();
55    this.xComponent = pip.getTypeNode();
56    if (this.xComponent === null || this.xComponent === undefined) {
57      console.error(TAG, `xComponent node is null`);
58      return;
59    }
60    let type: string = this.xComponent.getNodeType();
61    if (type !== 'XComponent') {
62      console.error(TAG, `xComponent type mismatch: ${type}`);
63      return;
64    }
65    this.useNode = true;
66    pip.setTypeNodeEnabled();
67    this.mXCNodeController = new XCNodeController(this.xComponent);
68    console.info(TAG, 'use Node Controller');
69
70    pip.on('stateChange', (state: number) => {
71      console.info(TAG, `stateChange state:${state}`);
72      if (state === ABOUT_TO_STOP) {
73        this.mXCNodeController?.removeNode();
74      }
75    })
76  }
77
78  aboutToDisappear(): void {
79    pip.off('stateChange');
80  }
81
82  build() {
83    Stack() {
84      if (this.useNode) {
85        this.buildNode();
86      } else {
87       this.buildXComponent();
88      }
89      if (this.nodeController !== null) {
90        this.buildCustomUI();
91      }
92    }
93    .size({ width: '100%', height: '100%' });
94  }
95
96  @Builder
97  buildCustomUI() {
98    NodeContainer(this.nodeController)
99      .size({ width: '100%', height: '100%' });
100  }
101
102  @Builder
103  buildXComponent() {
104    XComponent({ id: this.xComponentId, type: this.xComponentType, controller: this.xComponentController })
105      .onLoad(() => {
106        pip.initXComponentController(this.xComponentController);
107        console.debug(TAG, 'XComponent onLoad done');
108      })
109      .size({ width: '100%', height: '100%' })
110      .backgroundColor(Color.Transparent);
111  }
112
113  @Builder
114  buildNode() {
115    NodeContainer(this.mXCNodeController)
116      .size({ width: '100%', height: '100%' })
117  }
118}