• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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