1 /* 2 * Copyright (c) 2022 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 16 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 18 19 #include <cstdint> 20 #include <list> 21 #include <map> 22 #include <optional> 23 #include <string> 24 #include <unordered_map> 25 #include <unordered_set> 26 #include <utility> 27 28 #include "base/log/ace_trace.h" 29 #include "base/utils/noncopyable.h" 30 #include "base/utils/time_util.h" 31 #include "base/utils/utils.h" 32 #include "core/components_ng/base/frame_node.h" 33 #include "core/components_ng/base/inspector.h" 34 #include "core/components_ng/base/ui_node.h" 35 #include "core/components_v2/foreach/lazy_foreach_component.h" 36 #include "core/pipeline_ng/pipeline_context.h" 37 38 namespace OHOS::Ace::NG { 39 40 typedef struct OperationInfo { OperationInfoOperationInfo41 OperationInfo():node(nullptr) {} 42 int32_t changeCount = 0; 43 int32_t fromDiffTo = 0; 44 std::string key; 45 RefPtr<UINode> node; 46 bool isDeleting = false; 47 bool isChanged = false; 48 bool moveIn = false; 49 bool isExchange = false; 50 std::vector<std::string> extraKey; 51 } OperationInfo; 52 53 using LazyForEachChild = std::pair<std::string, RefPtr<UINode>>; 54 using LazyForEachCacheChild = std::pair<int32_t, RefPtr<UINode>>; 55 56 class ACE_EXPORT LazyForEachBuilder : public virtual AceType { 57 DECLARE_ACE_TYPE(NG::LazyForEachBuilder, AceType) 58 public: 59 LazyForEachBuilder() = default; 60 ~LazyForEachBuilder() override = default; 61 GetTotalCount()62 int32_t GetTotalCount() 63 { 64 return OnGetTotalCount(); 65 } 66 67 int32_t GetTotalCountOfOriginalDataset(const std::list<V2::Operation>& DataOperations); 68 69 std::pair<std::string, RefPtr<UINode>> GetChildByIndex(int32_t index, bool needBuild, bool isCache = false); 70 ExpandChildrenOnInitial()71 void ExpandChildrenOnInitial() 72 { 73 OnExpandChildrenOnInitialInNG(); 74 } 75 76 void OnDataReloaded(); 77 78 bool OnDataAdded(size_t index); 79 80 bool OnDataBulkAdded(size_t index, size_t count); 81 82 RefPtr<UINode> OnDataDeleted(size_t index); 83 84 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkDeleted(size_t index, size_t count); 85 86 bool OnDataChanged(size_t index); 87 88 std::list<std::pair<std::string, RefPtr<UINode>>>& OnDataBulkChanged(size_t index, size_t count); 89 90 void OnDataMoveToNewPlace(size_t from, size_t to); 91 92 bool OnDataMoved(size_t from, size_t to); 93 94 std::pair<int32_t, std::list<RefPtr<UINode>>> OnDatasetChange(std::list<V2::Operation> DataOperations); 95 96 void RepairDatasetItems(std::map<int32_t, LazyForEachChild>& cachedTemp, 97 std::map<int32_t, LazyForEachChild>& expiringTempItem_, std::map<int32_t, int32_t>& indexChangedMap); 98 99 void RepairMoveOrExchange(std::map<int32_t, LazyForEachChild>& expiringTempItem_, 100 OperationInfo& info, LazyForEachChild& child, int32_t index, int32_t changedIndex); 101 102 void CollectIndexChangedCount(std::map<int32_t, int32_t>& indexChangedMap); 103 104 bool ClassifyOperation(V2::Operation& operation, int32_t& initialIndex, 105 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 106 107 bool ValidateIndex(int32_t index, const std::string& type); 108 109 void OperateAdd(V2::Operation& operation, int32_t& initialIndex); 110 111 void OperateDelete(V2::Operation& operation, int32_t& initialIndex); 112 113 void OperateMove(V2::Operation& operation, int32_t& initialIndex, 114 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 115 116 void OperateChange(V2::Operation& operation, int32_t& initialIndex, 117 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 118 119 std::map<int32_t, LazyForEachChild>::iterator FindItem(int32_t index, 120 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 121 122 void OperateExchange(V2::Operation& operation, int32_t& initialIndex, 123 std::map<int32_t, LazyForEachChild>& cachedTemp, std::map<int32_t, LazyForEachChild>& expiringTemp); 124 125 void OperateReload(std::map<int32_t, LazyForEachChild>& expiringTemp); 126 127 void ThrowRepeatOperationError(int32_t index); 128 129 void RecordOutOfBoundaryNodes(int32_t index); 130 InvalidIndexOfChangedData(size_t index)131 void InvalidIndexOfChangedData(size_t index) 132 { 133 for (auto& [key, child] : expiringItem_) { 134 if (static_cast<size_t>(child.first) == index) { 135 child.first = -1; 136 break; 137 } 138 } 139 } 140 GetChildByKey(const std::string & key)141 RefPtr<UINode> GetChildByKey(const std::string& key) 142 { 143 return nullptr; 144 } 145 GetItems(std::list<std::pair<std::string,RefPtr<UINode>>> & childList)146 std::map<int32_t, LazyForEachChild>& GetItems(std::list<std::pair<std::string, RefPtr<UINode>>>& childList) 147 { 148 startIndex_ = -1; 149 endIndex_ = -1; 150 int32_t lastIndex = -1; 151 bool isCertained = false; 152 153 decltype(cachedItems_) items(std::move(cachedItems_)); 154 155 for (auto& [index, node] : items) { 156 if (!node.second) { 157 cachedItems_.try_emplace(index, std::move(node)); 158 continue; 159 } 160 161 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 162 if (frameNode && !frameNode->IsActive()) { 163 ACE_SYNTAX_SCOPED_TRACE("LazyForEach not active index[%d]", index); 164 frameNode->SetJSViewActive(false, true); 165 expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 166 continue; 167 } 168 cachedItems_.try_emplace(index, std::move(node)); 169 if (startIndex_ == -1) { 170 startIndex_ = index; 171 } 172 if (isLoop_) { 173 if (isCertained) { 174 continue; 175 } 176 if (lastIndex > -1 && index - lastIndex > 1) { 177 startIndex_ = index; 178 endIndex_ = lastIndex; 179 isCertained = true; 180 } else { 181 endIndex_ = std::max(endIndex_, index); 182 } 183 } else { 184 endIndex_ = std::max(endIndex_, index); 185 } 186 lastIndex = index; 187 } 188 189 if (needTransition) { 190 for (auto& [key, node] : expiringItem_) { 191 if (!node.second) { 192 continue; 193 } 194 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 195 if (frameNode && frameNode->IsOnMainTree()) { 196 childList.emplace_back(key, node.second); 197 } 198 } 199 needTransition = false; 200 } 201 202 return cachedItems_; 203 } 204 RemoveAllChild()205 void RemoveAllChild() 206 { 207 ACE_SYNTAX_SCOPED_TRACE("LazyForEach RemoveAllChild"); 208 for (auto& [index, node] : cachedItems_) { 209 if (!node.second) { 210 continue; 211 } 212 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 213 if (frameNode) { 214 frameNode->SetActive(false); 215 } 216 auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 217 if (!pair.second) { 218 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index); 219 } 220 } 221 } 222 SetActiveChildRange(int32_t start,int32_t end)223 bool SetActiveChildRange(int32_t start, int32_t end) 224 { 225 ACE_SYNTAX_SCOPED_TRACE("LazyForEach active range start[%d], end[%d]", start, end); 226 int32_t count = GetTotalCount(); 227 bool needBuild = false; 228 for (auto& [index, node] : cachedItems_) { 229 if ((index < count) && ((start <= end && start <= index && end >= index) || 230 (start > end && (index <= end || index >= start)))) { 231 if (node.second) { 232 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 233 if (frameNode) { 234 frameNode->SetActive(true); 235 } 236 continue; 237 } 238 auto keyIter = expiringItem_.find(node.first); 239 if (keyIter != expiringItem_.end() && keyIter->second.second) { 240 node.second = keyIter->second.second; 241 expiringItem_.erase(keyIter); 242 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 243 if (frameNode) { 244 frameNode->SetActive(true); 245 } 246 } 247 needBuild = true; 248 continue; 249 } 250 if (!node.second) { 251 continue; 252 } 253 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 254 if (frameNode) { 255 frameNode->SetActive(false); 256 } 257 auto pair = expiringItem_.try_emplace(node.first, LazyForEachCacheChild(index, std::move(node.second))); 258 if (!pair.second) { 259 TAG_LOGW(AceLogTag::ACE_LAZY_FOREACH, "Use repeat key for index: %{public}d", index); 260 } 261 needBuild = true; 262 } 263 return needBuild; 264 } 265 GetChildIndex(const RefPtr<FrameNode> & targetNode)266 int32_t GetChildIndex(const RefPtr<FrameNode>& targetNode) 267 { 268 for (auto& [index, node] : cachedItems_) { 269 if (node.second) { 270 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 271 if (frameNode == targetNode) { 272 return index; 273 } 274 } 275 } 276 for (auto& [key, node] : expiringItem_) { 277 if (!node.second) { 278 continue; 279 } 280 auto frameNode = AceType::DynamicCast<FrameNode>(node.second->GetFrameChildByIndex(0, true)); 281 if (frameNode && frameNode == targetNode) { 282 return node.first; 283 } 284 } 285 return -1; 286 } 287 288 void UpdateMoveFromTo(int32_t from, int32_t to); 289 void ResetMoveFromTo(); 290 int32_t ConvertFormToIndex(int32_t index); 291 SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag)292 void SetFlagForGeneratedItem(PropertyChangeFlag propertyChangeFlag) 293 { 294 for (const auto& item : cachedItems_) { 295 if (!item.second.second) { 296 continue; 297 } 298 item.second.second->ForceUpdateLayoutPropertyFlag(propertyChangeFlag); 299 } 300 } 301 CacheItem(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,const std::optional<LayoutConstraintF> & itemConstraint,int64_t deadline,bool & isTimeout)302 RefPtr<UINode> CacheItem(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 303 const std::optional<LayoutConstraintF>& itemConstraint, int64_t deadline, bool& isTimeout) 304 { 305 ACE_SCOPED_TRACE("Builder:BuildLazyItem [%d]", index); 306 auto itemInfo = OnGetChildByIndex(ConvertFormToIndex(index), expiringItem_); 307 CHECK_NULL_RETURN(itemInfo.second, nullptr); 308 cache.try_emplace(itemInfo.first, LazyForEachCacheChild(index, itemInfo.second)); 309 auto context = itemInfo.second->GetContext(); 310 CHECK_NULL_RETURN(context, itemInfo.second); 311 auto frameNode = AceType::DynamicCast<FrameNode>(itemInfo.second->GetFrameChildByIndex(0, false, true)); 312 context->SetPredictNode(frameNode); 313 if (!itemInfo.second->RenderCustomChild(deadline)) { 314 isTimeout = true; 315 context->ResetPredictNode(); 316 return itemInfo.second; 317 } 318 ProcessOffscreenNode(itemInfo.second, false); 319 itemInfo.second->Build(nullptr); 320 context->ResetPredictNode(); 321 itemInfo.second->SetJSViewActive(false, true); 322 cachedItems_[index] = LazyForEachChild(itemInfo.first, nullptr); 323 324 return itemInfo.second; 325 } 326 CheckCacheIndex(std::set<int32_t> & idleIndexes,int32_t count)327 void CheckCacheIndex(std::set<int32_t>& idleIndexes, int32_t count) 328 { 329 for (int32_t i = 1; i <= cacheCount_; i++) { 330 if (isLoop_) { 331 if ((startIndex_ <= endIndex_ && endIndex_ + i < count) || 332 startIndex_ > endIndex_ + i) { 333 idleIndexes.emplace(endIndex_ + i); 334 } else if ((endIndex_ + i) % count < startIndex_) { 335 idleIndexes.emplace((endIndex_ + i) % count); 336 } 337 } else { 338 if (endIndex_ + i < count) { 339 idleIndexes.emplace(endIndex_ + i); 340 } 341 } 342 } 343 for (int32_t i = 1; i <= cacheCount_; i++) { 344 if (isLoop_) { 345 if ((startIndex_ <= endIndex_ && startIndex_ >= i) || 346 startIndex_ > endIndex_ + i) { 347 idleIndexes.emplace(startIndex_ - i); 348 } else if ((startIndex_ - i + count) % count > endIndex_) { 349 idleIndexes.emplace((startIndex_ - i + count) % count); 350 } 351 } else { 352 if (startIndex_ >= i) { 353 idleIndexes.emplace(startIndex_ - i); 354 } 355 } 356 } 357 } 358 PreBuildByIndex(int32_t index,std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask)359 bool PreBuildByIndex(int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cache, 360 int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask) 361 { 362 if (GetSysTimestamp() > deadline) { 363 if (!DeleteExpiringItemImmediately()) { 364 cache.merge(expiringItem_); 365 } 366 return false; 367 } 368 bool isTimeout = false; 369 preBuildingIndex_ = -1; 370 auto uiNode = CacheItem(index, cache, itemConstraint, deadline, isTimeout); 371 if (isTimeout) { 372 preBuildingIndex_ = index; 373 return false; 374 } 375 if (!canRunLongPredictTask && itemConstraint) { 376 return false; 377 } 378 if (canRunLongPredictTask && uiNode && itemConstraint) { 379 RefPtr<FrameNode> frameNode = DynamicCast<FrameNode>(uiNode); 380 while (!frameNode) { 381 auto tempNode = uiNode; 382 uiNode = tempNode->GetFirstChild(); 383 if (!uiNode) { 384 break; 385 } 386 frameNode = DynamicCast<FrameNode>(uiNode); 387 } 388 if (frameNode) { 389 frameNode->GetGeometryNode()->SetParentLayoutConstraint(itemConstraint.value()); 390 FrameNode::ProcessOffscreenNode(frameNode); 391 } 392 } 393 return true; 394 } 395 ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)396 bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline, 397 const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask, 398 std::set<int32_t>& idleIndexes) 399 { 400 if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) { 401 preBuildingIndex_ = -1; 402 return true; 403 } 404 idleIndexes.erase(preBuildingIndex_); 405 return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask); 406 } 407 408 bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask); 409 ProcessCachedIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes)410 void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, 411 std::set<int32_t>& idleIndexes) 412 { 413 auto expiringIter = expiringItem_.begin(); 414 while (expiringIter != expiringItem_.end()) { 415 const auto& key = expiringIter->first; 416 const auto& node = expiringIter->second; 417 auto iter = idleIndexes.find(node.first); 418 if (iter != idleIndexes.end() && node.second) { 419 LoadCacheByIndex(cache, idleIndexes, node, key, iter, expiringIter); 420 } else { 421 LoadCacheByKey(cache, idleIndexes, node, key, expiringIter); 422 } 423 } 424 } 425 LoadCacheByIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,const std::set<int32_t>::iterator & iter,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)426 void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 427 const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter, 428 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 429 { 430 ProcessOffscreenNode(node.second, false); 431 432 if (node.first == preBuildingIndex_) { 433 cache.try_emplace(key, node); 434 } else { 435 cache.try_emplace(key, std::move(node)); 436 cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr)); 437 idleIndexes.erase(iter); 438 } 439 440 expiringIter++; 441 } 442 LoadCacheByKey(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes,const LazyForEachCacheChild & node,const std::string & key,std::unordered_map<std::string,LazyForEachCacheChild>::iterator & expiringIter)443 void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes, 444 const LazyForEachCacheChild& node, const std::string& key, 445 std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter) 446 { 447 NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true); 448 ProcessOffscreenNode(node.second, true); 449 NotifyItemDeleted(RawPtr(node.second), key); 450 451 if (node.second) { 452 node.second->DetachFromMainTree(); 453 } 454 if (DeleteExpiringItemImmediately()) { 455 expiringIter = expiringItem_.erase(expiringIter); 456 } else { 457 expiringIter++; 458 } 459 } 460 ProcessOffscreenNode(RefPtr<UINode> uiNode,bool remove)461 void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove) 462 { 463 if (uiNode) { 464 auto frameNode = DynamicCast<FrameNode>(uiNode); 465 while (!frameNode) { 466 auto tempNode = uiNode; 467 uiNode = tempNode->GetFirstChild(); 468 if (!uiNode) { 469 break; 470 } 471 frameNode = DynamicCast<FrameNode>(uiNode); 472 } 473 if (frameNode) { 474 if (!remove) { 475 Inspector::AddOffscreenNode(frameNode); 476 } else { 477 Inspector::RemoveOffscreenNode(frameNode); 478 } 479 } 480 } 481 } 482 ClearAllOffscreenNode()483 void ClearAllOffscreenNode() 484 { 485 for (auto& [key, node] : expiringItem_) { 486 ProcessOffscreenNode(node.second, true); 487 } 488 for (auto& [key, node] : cachedItems_) { 489 ProcessOffscreenNode(node.second, true); 490 } 491 } 492 493 virtual void ReleaseChildGroupById(const std::string& id) = 0; 494 495 virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0; 496 497 virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0; 498 SetCacheCount(int32_t cacheCount)499 void SetCacheCount(int32_t cacheCount) 500 { 501 cacheCount_ = cacheCount; 502 } 503 SetIsLoop(bool isLoop)504 void SetIsLoop(bool isLoop) 505 { 506 isLoop_ = isLoop; 507 } 508 clearDeletedNodes()509 void clearDeletedNodes() 510 { 511 nodeList_.clear(); 512 } 513 SetUseNewInterface(bool useNewInterface)514 void SetUseNewInterface(bool useNewInterface) 515 { 516 useNewInterface_ = useNewInterface; 517 } 518 GetCachedUINodeMap()519 const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap() 520 { 521 return expiringItem_; 522 } 523 GetAllChildren()524 const std::map<int32_t, LazyForEachChild>& GetAllChildren() 525 { 526 if (!cachedItems_.empty()) { 527 startIndex_ = cachedItems_.begin()->first; 528 endIndex_ = cachedItems_.rbegin()->first; 529 } 530 if (isLoop_ && !cachedItems_.empty()) { 531 int32_t lastIndex = -1; 532 for (auto& [index, node] : cachedItems_) { 533 if (lastIndex > -1 && index - lastIndex > 1) { 534 startIndex_ = index; 535 endIndex_ = lastIndex; 536 break; 537 } 538 } 539 } 540 return cachedItems_; 541 } 542 SetJSViewActive(bool active)543 void SetJSViewActive(bool active) 544 { 545 for (const auto& node : cachedItems_) { 546 if (node.second.second == nullptr) { 547 continue; 548 } 549 node.second.second->SetJSViewActive(active, true); 550 } 551 for (const auto& node : expiringItem_) { 552 node.second.second->SetJSViewActive(active, true); 553 } 554 } 555 PaintDebugBoundaryTreeAll(bool flag)556 void PaintDebugBoundaryTreeAll(bool flag) 557 { 558 for (const auto& node : cachedItems_) { 559 if (node.second.second == nullptr) { 560 continue; 561 } 562 node.second.second->PaintDebugBoundaryTreeAll(flag); 563 } 564 for (const auto& node : expiringItem_) { 565 if (node.second.second == nullptr) { 566 continue; 567 } 568 node.second.second->PaintDebugBoundaryTreeAll(flag); 569 } 570 } 571 NotifyItemDeleted(UINode * node,const std::string & key)572 void NotifyItemDeleted(UINode* node, const std::string& key) 573 { 574 OnItemDeleted(node, key); 575 } 576 577 void GetAllItems(std::vector<UINode*>& items); 578 protected: 579 virtual int32_t OnGetTotalCount() = 0; 580 OnItemDeleted(UINode * node,const std::string & key)581 virtual void OnItemDeleted(UINode* node, const std::string& key) {}; 582 DeleteExpiringItemImmediately()583 virtual bool DeleteExpiringItemImmediately() 584 { 585 return false; 586 } 587 588 virtual LazyForEachChild OnGetChildByIndex( 589 int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0; 590 591 virtual LazyForEachChild OnGetChildByIndexNew(int32_t index, 592 std::map<int32_t, LazyForEachChild>& cachedItems, 593 std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0; 594 595 virtual void OnExpandChildrenOnInitialInNG() = 0; 596 597 virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0; 598 599 virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0; 600 601 virtual void NotifyDataAdded(size_t index) = 0; 602 603 virtual void KeepRemovedItemInCache(NG::LazyForEachChild node, 604 std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0; 605 606 private: 607 void RecycleItemsOutOfBoundary(); 608 void RecycleChildByIndex(int32_t index); 609 610 std::map<int32_t, LazyForEachChild> cachedItems_; 611 std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_; 612 std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_; 613 std::map<int32_t, OperationInfo> operationList_; 614 enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD }; 615 std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD}, 616 {"delete", OP::DEL}, 617 {"change", OP::CHANGE}, 618 {"move", OP::MOVE}, 619 {"exchange", OP::EXCHANGE}, 620 {"reload", OP::RELOAD}}; 621 std::list<int32_t> outOfBoundaryNodes_; 622 std::optional<std::pair<int32_t, int32_t>> moveFromTo_; 623 624 int32_t startIndex_ = -1; 625 int32_t endIndex_ = -1; 626 int32_t cacheCount_ = 0; 627 int32_t preBuildingIndex_ = -1; 628 int32_t totalCountOfOriginalDataset_ = 0; 629 bool needTransition = false; 630 bool isLoop_ = false; 631 bool useNewInterface_ = false; 632 ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder); 633 }; 634 } // namespace OHOS::Ace::NG 635 636 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H 637