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 16interface NodeInfo { 17 nodeId: number, 18 nodePtr: NodePtr 19} 20 21class NodeAdapter { 22 nativePtr_: NodePtr; 23 nativeRef_: NativeStrongRef; 24 nodeRefs_: Array<FrameNode> = new Array(); 25 count_: number = 0; 26 attachedNodeRef_: WeakRef<FrameNode>; 27 28 onAttachToNode?: (target: FrameNode) => void; 29 onDetachFromNode?: () => void; 30 onGetChildId?: (index: number) => number; 31 onCreateChild?: (index: number) => FrameNode; 32 onDisposeChild?: (id: number, node: FrameNode) => void; 33 onUpdateChild?: (id: number, node: FrameNode) => void; 34 35 constructor() { 36 this.nativeRef_ = getUINativeModule().nodeAdapter.createAdapter(); 37 this.nativePtr_ = this.nativeRef_.getNativeHandle(); 38 getUINativeModule().nodeAdapter.setCallbacks(this.nativePtr_, this, 39 this.onAttachToNodePtr, this.onDetachFromNodePtr, 40 this.onGetChildId !== undefined ? this.onGetChildId : undefined, 41 this.onCreateChild !== undefined ? this.onCreateNewNodePtr : undefined, 42 this.onDisposeChild !== undefined ? this.onDisposeNodePtr : undefined, 43 this.onUpdateChild !== undefined ? this.onUpdateNodePtr : undefined 44 ); 45 } 46 47 dispose(): void { 48 let hostNode = this.attachedNodeRef_.deref(); 49 if (hostNode !== undefined) { 50 NodeAdapter.detachNodeAdapter(hostNode); 51 } 52 this.nativeRef_.dispose(); 53 this.nativePtr_ = null; 54 } 55 56 set totalNodeCount(count: number) { 57 if (count < 0) { 58 return; 59 } 60 getUINativeModule().nodeAdapter.setTotalNodeCount(this.nativePtr_, count); 61 this.count_ = count; 62 } 63 64 get totalNodeCount(): number { 65 return this.count_; 66 } 67 68 reloadAllItems(): void { 69 getUINativeModule().nodeAdapter.notifyItemReloaded(this.nativePtr_); 70 } 71 72 reloadItem(start: number, count: number): void { 73 if (start < 0 || count < 0) { 74 return; 75 } 76 getUINativeModule().nodeAdapter.notifyItemChanged(this.nativePtr_, start, count); 77 } 78 79 removeItem(start: number, count: number): void { 80 if (start < 0 || count < 0) { 81 return; 82 } 83 getUINativeModule().nodeAdapter.notifyItemRemoved(this.nativePtr_, start, count); 84 } 85 86 insertItem(start: number, count: number): void { 87 if (start < 0 || count < 0) { 88 return; 89 } 90 getUINativeModule().nodeAdapter.notifyItemInserted(this.nativePtr_, start, count); 91 } 92 93 moveItem(from: number, to: number): void { 94 if (from < 0 || to < 0) { 95 return; 96 } 97 getUINativeModule().nodeAdapter.notifyItemMoved(this.nativePtr_, from, to); 98 } 99 100 getAllAvailableItems(): Array<FrameNode> { 101 let result: Array<FrameNode> = new Array(); 102 let nodes: Array<NodeInfo> = getUINativeModule().nodeAdapter.getAllItems(this.nativePtr_); 103 if (nodes !== undefined) { 104 nodes.forEach(node => { 105 let nodeId = node.nodeId; 106 if (FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.has(nodeId)) { 107 let frameNode = FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.get(nodeId).deref(); 108 result.push(frameNode); 109 } 110 }); 111 } 112 return result; 113 } 114 115 onAttachToNodePtr(target: NodeInfo): void { 116 let nodeId = target.nodeId; 117 if (FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.has(nodeId)) { 118 let frameNode = FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.get(nodeId).deref(); 119 if (frameNode === undefined) { 120 return; 121 } 122 frameNode.setAdapterRef(this); 123 this.attachedNodeRef_ = new WeakRef(frameNode); 124 if (this.onAttachToNode !== undefined) { 125 this.onAttachToNode(frameNode); 126 } 127 } 128 } 129 130 onDetachFromNodePtr(): void { 131 if (this === undefined) { 132 return; 133 } 134 if (this.onDetachFromNode !== undefined) { 135 this.onDetachFromNode(); 136 } 137 let attachedNode = this.attachedNodeRef_.deref(); 138 if (attachedNode !== undefined) { 139 attachedNode.setAdapterRef(undefined); 140 } 141 this.nodeRefs_.splice(0, this.nodeRefs_.length); 142 } 143 144 onCreateNewNodePtr(index: number): NodePtr { 145 if (this.onCreateChild !== undefined) { 146 let node = this.onCreateChild(index); 147 if (!this.nodeRefs_.includes(node)) { 148 this.nodeRefs_.push(node); 149 } 150 return node.getNodePtr(); 151 } 152 return null; 153 } 154 155 onDisposeNodePtr(id: number, node: NodeInfo): void { 156 let nodeId = node.nodeId; 157 if (FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.has(nodeId)) { 158 let frameNode = FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.get(nodeId).deref(); 159 if (this.onDisposeChild !== undefined && frameNode !== undefined) { 160 this.onDisposeChild(id, frameNode); 161 let index = this.nodeRefs_.indexOf(frameNode); 162 if (index > -1) { 163 this.nodeRefs_.splice(index, 1); 164 } 165 } 166 } 167 } 168 169 onUpdateNodePtr(id: number, node: NodeInfo): void { 170 let nodeId = node.nodeId; 171 if (FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.has(nodeId)) { 172 let frameNode = FrameNodeFinalizationRegisterProxy.ElementIdToOwningFrameNode_.get(nodeId).deref(); 173 if (this.onUpdateChild !== undefined && frameNode !== undefined) { 174 this.onUpdateChild(id, frameNode); 175 } 176 } 177 } 178 179 static attachNodeAdapter(adapter: NodeAdapter, node: FrameNode): boolean { 180 if (node === null || node === undefined) { 181 return false; 182 } 183 if (!node.isModifiable()) { 184 return false; 185 } 186 const hasAttributeProperty = Object.prototype.hasOwnProperty.call(node, 'attribute_'); 187 if (hasAttributeProperty) { 188 let frameeNode = node as TypedFrameNode<ArkComponent>; 189 if (frameeNode.attribute_.allowChildCount !== undefined) { 190 const allowCount = frameeNode.attribute_.allowChildCount(); 191 if (allowCount <= 1) { 192 return false; 193 } 194 } 195 } 196 return getUINativeModule().nodeAdapter.attachNodeAdapter(adapter.nativePtr_, node.getNodePtr()); 197 } 198 199 static detachNodeAdapter(node: FrameNode) { 200 if (node === null || node === undefined) { 201 return; 202 } 203 getUINativeModule().nodeAdapter.detachNodeAdapter(node.getNodePtr()); 204 } 205}