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