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                 cache.merge(expiringItem_);
380             }
381             return false;
382         }
383         bool isTimeout = false;
384         preBuildingIndex_ = -1;
385         auto uiNode = CacheItem(index, cache, itemConstraint, deadline, isTimeout);
386         if (isTimeout) {
387             preBuildingIndex_ = index;
388             return false;
389         }
390         if (!canRunLongPredictTask && itemConstraint) {
391             return false;
392         }
393         if (canRunLongPredictTask && uiNode && itemConstraint) {
394             RefPtr<FrameNode> frameNode = DynamicCast<FrameNode>(uiNode);
395             while (!frameNode) {
396                 auto tempNode = uiNode;
397                 uiNode = tempNode->GetFirstChild();
398                 if (!uiNode) {
399                     break;
400                 }
401                 frameNode = DynamicCast<FrameNode>(uiNode);
402             }
403             if (frameNode) {
404                 frameNode->GetGeometryNode()->SetParentLayoutConstraint(itemConstraint.value());
405                 FrameNode::ProcessOffscreenNode(frameNode);
406             }
407         }
408         return true;
409     }
410 
ProcessPreBuildingIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,int64_t deadline,const std::optional<LayoutConstraintF> & itemConstraint,bool canRunLongPredictTask,std::set<int32_t> & idleIndexes)411     bool ProcessPreBuildingIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, int64_t deadline,
412         const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask,
413         std::set<int32_t>& idleIndexes)
414     {
415         if (idleIndexes.find(preBuildingIndex_) == idleIndexes.end()) {
416             preBuildingIndex_ = -1;
417             return true;
418         }
419         idleIndexes.erase(preBuildingIndex_);
420         return PreBuildByIndex(preBuildingIndex_, cache, deadline, itemConstraint, canRunLongPredictTask);
421     }
422 
423     bool PreBuild(int64_t deadline, const std::optional<LayoutConstraintF>& itemConstraint, bool canRunLongPredictTask);
424 
ProcessCachedIndex(std::unordered_map<std::string,LazyForEachCacheChild> & cache,std::set<int32_t> & idleIndexes)425     void ProcessCachedIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache,
426         std::set<int32_t>& idleIndexes)
427     {
428         auto expiringIter = expiringItem_.begin();
429         while (expiringIter != expiringItem_.end()) {
430             const auto& key = expiringIter->first;
431             const auto& node = expiringIter->second;
432             auto iter = idleIndexes.find(node.first);
433             if (iter != idleIndexes.end() && node.second) {
434                 LoadCacheByIndex(cache, idleIndexes, node, key, iter, expiringIter);
435             } else {
436                 LoadCacheByKey(cache, idleIndexes, node, key, expiringIter);
437             }
438         }
439     }
440 
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)441     void LoadCacheByIndex(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
442         const LazyForEachCacheChild& node, const std::string& key, const std::set<int32_t>::iterator& iter,
443         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
444     {
445         ProcessOffscreenNode(node.second, false);
446 
447         if (node.first == preBuildingIndex_) {
448             cache.try_emplace(key, node);
449         } else {
450             cache.try_emplace(key, std::move(node));
451             cachedItems_.try_emplace(node.first, LazyForEachChild(key, nullptr));
452             idleIndexes.erase(iter);
453         }
454 
455         expiringIter++;
456     }
457 
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)458     void LoadCacheByKey(std::unordered_map<std::string, LazyForEachCacheChild>& cache, std::set<int32_t>& idleIndexes,
459         const LazyForEachCacheChild& node, const std::string& key,
460         std::unordered_map<std::string, LazyForEachCacheChild>::iterator& expiringIter)
461     {
462         NotifyDataDeleted(node.second, static_cast<size_t>(node.first), true);
463         ProcessOffscreenNode(node.second, true);
464         NotifyItemDeleted(RawPtr(node.second), key);
465 
466         if (node.second) {
467             node.second->DetachFromMainTree();
468         }
469         if (DeleteExpiringItemImmediately()) {
470             expiringIter = expiringItem_.erase(expiringIter);
471         } else {
472             expiringIter++;
473         }
474     }
475 
ProcessOffscreenNode(RefPtr<UINode> uiNode,bool remove)476     void ProcessOffscreenNode(RefPtr<UINode> uiNode, bool remove)
477     {
478         if (uiNode) {
479             auto frameNode = DynamicCast<FrameNode>(uiNode);
480             while (!frameNode) {
481                 auto tempNode = uiNode;
482                 uiNode = tempNode->GetFirstChild();
483                 if (!uiNode) {
484                     break;
485                 }
486                 frameNode = DynamicCast<FrameNode>(uiNode);
487             }
488             if (frameNode) {
489                 if (!remove) {
490                     Inspector::AddOffscreenNode(frameNode);
491                 } else {
492                     Inspector::RemoveOffscreenNode(frameNode);
493                 }
494             }
495         }
496     }
497 
ClearAllOffscreenNode()498     void ClearAllOffscreenNode()
499     {
500         for (auto& [key, node] : expiringItem_) {
501             ProcessOffscreenNode(node.second, true);
502         }
503         for (auto& [key, node] : cachedItems_) {
504             ProcessOffscreenNode(node.second, true);
505         }
506     }
507 
508     virtual void ReleaseChildGroupById(const std::string& id) = 0;
509 
510     virtual void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) = 0;
511 
512     virtual void UnregisterDataChangeListener(V2::DataChangeListener* listener) = 0;
513 
SetCacheCount(int32_t cacheCount)514     void SetCacheCount(int32_t cacheCount)
515     {
516         cacheCount_ = cacheCount;
517     }
518 
SetIsLoop(bool isLoop)519     void SetIsLoop(bool isLoop)
520     {
521         isLoop_ = isLoop;
522     }
523 
clearDeletedNodes()524     void clearDeletedNodes()
525     {
526         nodeList_.clear();
527     }
528 
SetUseNewInterface(bool useNewInterface)529     void SetUseNewInterface(bool useNewInterface)
530     {
531         useNewInterface_ = useNewInterface;
532     }
533 
GetCachedUINodeMap()534     const std::unordered_map<std::string, LazyForEachCacheChild>& GetCachedUINodeMap()
535     {
536         return expiringItem_;
537     }
538 
GetAllChildren()539     const std::map<int32_t, LazyForEachChild>& GetAllChildren()
540     {
541         if (!cachedItems_.empty()) {
542             startIndex_ = cachedItems_.begin()->first;
543             endIndex_ = cachedItems_.rbegin()->first;
544         }
545         if (isLoop_ && !cachedItems_.empty()) {
546             int32_t lastIndex = -1;
547             for (auto& [index, node] : cachedItems_) {
548                 if (lastIndex > -1 && index - lastIndex > 1) {
549                     startIndex_ = index;
550                     endIndex_ = lastIndex;
551                     break;
552                 }
553             }
554         }
555         return cachedItems_;
556     }
557 
SetJSViewActive(bool active)558     void SetJSViewActive(bool active)
559     {
560         for (const auto& node : cachedItems_) {
561             if (node.second.second == nullptr) {
562                 continue;
563             }
564             node.second.second->SetJSViewActive(active, true);
565         }
566         for (const auto& node : expiringItem_) {
567             if (node.second.second == nullptr) {
568                 continue;
569             }
570             node.second.second->SetJSViewActive(active, true);
571         }
572     }
573 
PaintDebugBoundaryTreeAll(bool flag)574     void PaintDebugBoundaryTreeAll(bool flag)
575     {
576         for (const auto& node : cachedItems_) {
577             if (node.second.second == nullptr) {
578                 continue;
579             }
580             node.second.second->PaintDebugBoundaryTreeAll(flag);
581         }
582         for (const auto& node : expiringItem_) {
583             if (node.second.second == nullptr) {
584                 continue;
585             }
586             node.second.second->PaintDebugBoundaryTreeAll(flag);
587         }
588     }
589 
NotifyItemDeleted(UINode * node,const std::string & key)590     void NotifyItemDeleted(UINode* node, const std::string& key)
591     {
592         OnItemDeleted(node, key);
593     }
594 
595     void GetAllItems(std::vector<UINode*>& items);
596 
SetShowCached(int32_t start,int32_t end)597     void SetShowCached(int32_t start, int32_t end)
598     {
599         startShowCached_ = start;
600         endShowCached_ = end;
601     }
602 
603 protected:
604     virtual int32_t OnGetTotalCount() = 0;
605 
OnItemDeleted(UINode * node,const std::string & key)606     virtual void OnItemDeleted(UINode* node, const std::string& key) {};
607 
DeleteExpiringItemImmediately()608     virtual bool DeleteExpiringItemImmediately()
609     {
610         return false;
611     }
612 
613     virtual LazyForEachChild OnGetChildByIndex(
614         int32_t index, std::unordered_map<std::string, LazyForEachCacheChild>& cachedItems) = 0;
615 
616     virtual LazyForEachChild OnGetChildByIndexNew(int32_t index,
617         std::map<int32_t, LazyForEachChild>& cachedItems,
618         std::unordered_map<std::string, LazyForEachCacheChild>& expiringItems) = 0;
619 
620     virtual void OnExpandChildrenOnInitialInNG() = 0;
621 
622     virtual void NotifyDataChanged(size_t index, const RefPtr<UINode>& lazyForEachNode, bool isRebuild = true) = 0;
623 
624     virtual void NotifyDataDeleted(const RefPtr<UINode>& lazyForEachNode, size_t index, bool removeIds) = 0;
625 
626     virtual void NotifyDataAdded(size_t index) = 0;
627 
628     virtual void KeepRemovedItemInCache(NG::LazyForEachChild node,
629         std::unordered_map<std::string, NG::LazyForEachCacheChild>& cachedItems) = 0;
630 
631 private:
632     void RecycleItemsOutOfBoundary();
633     void RecycleChildByIndex(int32_t index);
634 
635     std::map<int32_t, LazyForEachChild> cachedItems_;
636     std::unordered_map<std::string, LazyForEachCacheChild> expiringItem_;
637     std::list<std::pair<std::string, RefPtr<UINode>>> nodeList_;
638     std::map<int32_t, OperationInfo> operationList_;
639     enum class OP { ADD, DEL, CHANGE, MOVE, EXCHANGE, RELOAD };
640     std::map<std::string, OP> operationTypeMap = {{"add", OP::ADD},
641         {"delete", OP::DEL},
642         {"change", OP::CHANGE},
643         {"move", OP::MOVE},
644         {"exchange", OP::EXCHANGE},
645         {"reload", OP::RELOAD}};
646     std::list<int32_t> outOfBoundaryNodes_;
647     std::optional<std::pair<int32_t, int32_t>> moveFromTo_;
648 
649     int32_t startIndex_ = -1;
650     int32_t endIndex_ = -1;
651     int32_t cacheCount_ = 0;
652     int32_t startShowCached_ = 0;
653     int32_t endShowCached_ = 0;
654     int32_t preBuildingIndex_ = -1;
655     int32_t totalCountOfOriginalDataset_ = 0;
656     int32_t historicalTotalCount_ = 0;
657     bool needTransition = false;
658     bool isLoop_ = false;
659     bool useNewInterface_ = false;
660     ACE_DISALLOW_COPY_AND_MOVE(LazyForEachBuilder);
661 };
662 } // namespace OHOS::Ace::NG
663 
664 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_SYNTAX_FOREACH_LAZY_FOR_EACH_BUILDER_H
665