• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "core/components_ng/syntax/repeat_virtual_scroll_node.h"
17 
18 #include "core/pipeline_ng/pipeline_context.h"
19 
20 namespace OHOS::Ace::NG {
21 
22 // REPEAT
GetOrCreateRepeatNode(int32_t nodeId,uint32_t totalCount,const std::map<std::string,std::pair<bool,uint32_t>> & templateCachedCountMap,const std::function<void (uint32_t)> & onCreateNode,const std::function<void (const std::string &,uint32_t)> & onUpdateNode,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetKeys4Range,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetTypes4Range,const std::function<void (int32_t,int32_t)> & onSetActiveRange,bool reusable)23 RefPtr<RepeatVirtualScrollNode> RepeatVirtualScrollNode::GetOrCreateRepeatNode(int32_t nodeId, uint32_t totalCount,
24     const std::map<std::string, std::pair<bool, uint32_t>>& templateCachedCountMap,
25     const std::function<void(uint32_t)>& onCreateNode,
26     const std::function<void(const std::string&, uint32_t)>& onUpdateNode,
27     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetKeys4Range,
28     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetTypes4Range,
29     const std::function<void(int32_t, int32_t)>& onSetActiveRange,
30     bool reusable)
31 {
32     auto node = ElementRegister::GetInstance()->GetSpecificItemById<RepeatVirtualScrollNode>(nodeId);
33     if (node) {
34         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).GetOrCreateRepeatNode Found RepeatVirtualScrollNode",
35             static_cast<int32_t>(node->GetId()));
36         node->UpdateTotalCount(totalCount);
37         return node;
38     }
39     node = MakeRefPtr<RepeatVirtualScrollNode>(
40         nodeId, totalCount, templateCachedCountMap, onCreateNode, onUpdateNode, onGetKeys4Range, onGetTypes4Range,
41         onSetActiveRange, reusable);
42 
43     ElementRegister::GetInstance()->AddUINode(node);
44     return node;
45 }
46 
RepeatVirtualScrollNode(int32_t nodeId,int32_t totalCount,const std::map<std::string,std::pair<bool,uint32_t>> & templateCachedCountMap,const std::function<void (uint32_t)> & onCreateNode,const std::function<void (const std::string &,uint32_t)> & onUpdateNode,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetKeys4Range,const std::function<std::list<std::string> (uint32_t,uint32_t)> & onGetTypes4Range,const std::function<void (int32_t,int32_t)> & onSetActiveRange,bool reusable)47 RepeatVirtualScrollNode::RepeatVirtualScrollNode(int32_t nodeId, int32_t totalCount,
48     const std::map<std::string, std::pair<bool, uint32_t>>& templateCachedCountMap,
49     const std::function<void(uint32_t)>& onCreateNode,
50     const std::function<void(const std::string&, uint32_t)>& onUpdateNode,
51     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetKeys4Range,
52     const std::function<std::list<std::string>(uint32_t, uint32_t)>& onGetTypes4Range,
53     const std::function<void(int32_t, int32_t)>& onSetActiveRange,
54     bool reusable)
55     : ForEachBaseNode(V2::JS_REPEAT_ETS_TAG, nodeId), totalCount_(totalCount),
56       caches_(templateCachedCountMap, onCreateNode, onUpdateNode, onGetKeys4Range, onGetTypes4Range, reusable),
57       onSetActiveRange_(onSetActiveRange),
58       postUpdateTaskHasBeenScheduled_(false),
59       reusable_(reusable)
60 {
61 }
62 
UpdateTotalCount(uint32_t totalCount)63 void RepeatVirtualScrollNode::UpdateTotalCount(uint32_t totalCount)
64 {
65     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).UpdateTotalCount TotalCount: %{public}d",
66         static_cast<int32_t>(GetId()), totalCount);
67         // set active range when deleting all.
68         if (totalCount == 0 && totalCount != totalCount_) {
69             DoSetActiveChildRange(-1, -1, 0, 0, false);
70         }
71     totalCount_ = totalCount;
72 }
73 
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)74 void RepeatVirtualScrollNode::DoSetActiveChildRange(
75     int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
76 {
77     // cacheStart and cacheEnd are not always equal to the cacheCount of container when sliding screen,
78     // when disabling reuse, nodes may move out of L1 and then move in again, which causes extra construction and
79     // destruction. So set cacheStart and cacheEnd equal to the cacheCount of container.
80     if (!reusable_) {
81         cacheStart = containerCacheCount_;
82         cacheEnd = containerCacheCount_;
83     }
84     if (showCache) {
85         start -= cacheStart;
86         end += cacheEnd;
87         cacheStart = 0;
88         cacheEnd = 0;
89     }
90     ACE_SCOPED_TRACE("Repeat.DoSetActiveChildRange start[%d] - end[%d]; cacheStart[%d], cacheEnd[%d]",
91         start, end, cacheStart, cacheEnd);
92     CheckActiveRange(start, end, cacheStart, cacheEnd);
93 
94     bool needSync = caches_.RebuildL1([start, end, cacheStart, cacheEnd, weak = WeakClaim(this)](
95         int32_t index, const RefPtr<UINode>& node) -> bool {
96             auto repeatNode = weak.Upgrade();
97             CHECK_NULL_RETURN(repeatNode, false);
98             if (node == nullptr) {
99                 return false;
100             }
101             auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
102             if (!frameNode) {
103                 return false;
104             }
105             if (repeatNode->CheckNode4IndexInL1(index, start, end, cacheStart, cacheEnd, frameNode)) {
106                 // keep in Repeat L1
107                 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).DoSetActiveChildRange "
108                     "in visible, index %{public}d -> child Id %{public}d: keep in L1",
109                     static_cast<int32_t>(repeatNode->GetId()), static_cast<int32_t>(index), frameNode->GetId());
110                 return true;
111             }
112             TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).DoSetActiveChildRange out of visible, "
113                 "index %{public}d -> child Id %{public}d: SetActive(false), detach, move to spare items L2",
114                 static_cast<int32_t>(repeatNode->GetId()), index, frameNode->GetId());
115 
116             // move active node into L2 cached. check transition flag.
117             if (node->OnRemoveFromParent(true)) {
118                 // OnRemoveFromParent returns true means the child can be removed from tree immediately.
119                 repeatNode->RemoveDisappearingChild(node);
120             } else {
121                 repeatNode->AddDisappearingChild(node);
122             }
123 
124             return false;
125         });
126     if (needSync) {
127         UINode::MarkNeedSyncRenderTree(false);
128         children_.clear();
129         PostIdleTask();
130     }
131 }
132 
CheckNode4IndexInL1(int32_t index,int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,RefPtr<FrameNode> & frameNode)133 bool RepeatVirtualScrollNode::CheckNode4IndexInL1(int32_t index, int32_t start, int32_t end,
134     int32_t cacheStart, int32_t cacheEnd, RefPtr<FrameNode>& frameNode)
135 {
136     if (((start <= index) && (index <= end)) || ((end < start) && (index <= end || start <= index))) {
137         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).CheckNode4IndexInL1 "
138             "in range: index %{public}d -> child Id %{public}d: SetActive(true)",
139             static_cast<int32_t>(GetId()), index, static_cast<int32_t>(frameNode->GetId()));
140         frameNode->SetActive(true);
141     } else {
142         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).CheckNode4IndexInL1 "
143             "out of range: index %{public}d -> child Id %{public}d: SetActive(false)",
144             static_cast<int32_t>(GetId()), index, frameNode->GetId());
145         frameNode->SetActive(false);
146     }
147 
148     auto totalCount = static_cast<int32_t>(totalCount_);
149     if ((start - cacheStart <= index) && (index <= end + cacheEnd)) {
150         return true;
151     }
152     if (isLoop_) {
153         if (((end < start) && (start - cacheStart <= index || index <= end + cacheEnd)) ||
154             ((start - cacheStart < 0) && (index >= start - cacheStart + totalCount)) ||
155             ((end + cacheEnd >= totalCount) && (index <= end + cacheEnd - totalCount))) {
156             return true;
157         }
158     }
159     return false;
160 }
161 
CheckActiveRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd)162 void RepeatVirtualScrollNode::CheckActiveRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd)
163 {
164     // get normalized active range (with positive indices only)
165     const int32_t signed_totalCount = static_cast<int32_t>(totalCount_);
166     int32_t nStart = start - cacheStart;
167     int32_t nEnd = end + cacheEnd;
168     const int32_t divider = 2;
169 
170     if (start > end) { // swiper-loop scenario
171         nStart = std::min(nStart, signed_totalCount);
172         nEnd = std::max(nEnd, 0);
173         if (nStart <= nEnd) { // overlapped
174             nStart = signed_totalCount / divider + 1;
175             nEnd = signed_totalCount / divider;
176         }
177     } else {
178         if (nStart >= signed_totalCount || nEnd < 0) {
179             nStart = 0;
180             nEnd = 0;
181         } else {
182             nStart = std::max(nStart, 0);
183             // start <= end <= totalCount - 1
184             nEnd = std::min(std::max(nEnd, nStart), signed_totalCount - 1);
185         }
186     }
187 
188     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).DoSetActiveChildRange start: %{public}d - end: %{public}d; "
189         "cacheStart: %{public}d, cacheEnd: %{public}d: ==> keep in L1: %{public}d - %{public}d",
190         static_cast<int32_t>(GetId()), start, end, cacheStart, cacheEnd, nStart, nEnd);
191 
192     // memorize active range
193     caches_.SetLastActiveRange(static_cast<uint32_t>(nStart), static_cast<uint32_t>(nEnd));
194 
195     // notify TS side
196     onSetActiveRange_(nStart, nEnd);
197 }
198 
DropFromL1(const std::string & key)199 void RepeatVirtualScrollNode::DropFromL1(const std::string& key)
200 {
201     RefPtr<UINode> node = caches_.DropFromL1(key);
202     if (node == nullptr) {
203         return;
204     }
205 
206     auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
207     if (frameNode) {
208         frameNode->SetActive(false);
209     }
210     // move active node into L2 cached.
211     // check transition flag.
212     if (node->OnRemoveFromParent(true)) {
213         // OnRemoveFromParent returns true means the child can be removed from tree immediately.
214         RemoveDisappearingChild(node);
215     } else {
216         // else move child into disappearing children, skip syncing render tree
217         AddDisappearingChild(node);
218     }
219 
220     UINode::MarkNeedSyncRenderTree(false);
221     children_.clear();
222     // re-assemble children_
223     PostIdleTask();
224 }
225 
DoSetActiveChildRange(const std::set<int32_t> & activeItems,const std::set<int32_t> & cachedItems,int32_t baseIndex)226 void RepeatVirtualScrollNode::DoSetActiveChildRange(
227     const std::set<int32_t>& activeItems, const std::set<int32_t>& cachedItems, int32_t baseIndex)
228 {
229     // Notify TS side. Verify line below when DoSetActiveChildRange() will start to be used.
230     // Call onSetActiveRange_ here;
231 
232     bool needSync = caches_.RebuildL1([&activeItems, &cachedItems, baseIndex, weak = WeakClaim(this)](
233         int32_t index, RefPtr<UINode> node) -> bool {
234             auto repeatNode = weak.Upgrade();
235             CHECK_NULL_RETURN(repeatNode, false);
236             if (node == nullptr) {
237                 return false;
238             }
239             auto frameNode = AceType::DynamicCast<FrameNode>(node->GetFrameChildByIndex(0, true));
240             if (!frameNode) {
241                 return false;
242             }
243             if (activeItems.find(index + baseIndex) != activeItems.end()) {
244                 frameNode->SetActive(true);
245                 return true;
246             } else {
247                 frameNode->SetActive(false);
248             }
249             if (cachedItems.find(index + baseIndex) != cachedItems.end()) {
250                 return true;
251             }
252             if (node->OnRemoveFromParent(true)) {
253                 repeatNode->RemoveDisappearingChild(node);
254             } else {
255                 repeatNode->AddDisappearingChild(node);
256             }
257 
258             return false;
259         });
260     if (needSync) {
261         UINode::MarkNeedSyncRenderTree(false);
262         children_.clear();
263         PostIdleTask();
264     }
265 }
266 
UpdateRenderState(bool visibleItemsChanged)267 void RepeatVirtualScrollNode::UpdateRenderState(bool visibleItemsChanged)
268 {
269     TAG_LOGD(AceLogTag::ACE_REPEAT,
270         "Repeat(%{public}d).UpdateRenderState visibleItemsChanged: %{public}d",
271         static_cast<int32_t>(GetId()), visibleItemsChanged);
272 
273     if (visibleItemsChanged) {
274         // empty the cache index -> key
275         // C++ will need to ask all new keys from JS side
276         caches_.InvalidateKeyAndTTypeCaches();
277         children_.clear();
278 
279         if (auto frameNode = GetParentFrameNode()) {
280             frameNode->ChildrenUpdatedFrom(0);
281         }
282     } else {
283         auto lastIndexInActiveRange = caches_.GetLastActiveRange().second;
284         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).UpdateRenderState lastIndexInActiveRange: %{public}d",
285             static_cast<int32_t>(GetId()), lastIndexInActiveRange);
286 
287         if (auto frameNode = GetParentFrameNode()) {
288             frameNode->ChildrenUpdatedFrom(lastIndexInActiveRange + 1);
289         }
290     }
291 
292     MarkNeedSyncRenderTree(true);
293     MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT | PROPERTY_UPDATE_BY_CHILD_REQUEST);
294 }
295 
296 // STATE_MGMT_NOTE: added
297 // index N-th item
298 // needBuild: true - if found in cache, then return, if not in cache then return newly build
299 //            false: - if found in cache, then return, if not found in cache then return nullptr
300 // isCache: true indicates prebuild item (only used by List/Grid/Waterflow, this item should go to L2 cache,
301 //          do not add to the tree,
302 //          isCache==false this item is for display or near display area
303 // addToRenderTree: true  - set it to active state, call SetActive
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)304 RefPtr<UINode> RepeatVirtualScrollNode::GetFrameChildByIndex(
305     uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
306 {
307     ACE_SCOPED_TRACE("Repeat.GetFrameChildByIndex index[%d], needBuild[%d] isCache[%d] addToRenderTree[%d]",
308         static_cast<int32_t>(index), static_cast<int32_t>(needBuild),
309         static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
310 
311     // whether child is reused or created
312     bool isChildReused = true;
313 
314     const auto& key = caches_.GetKey4Index(index, true);
315     if (!key) {
316         TAG_LOGE(AceLogTag::ACE_REPEAT, "GetKey4Index fail to get key for %{public}d", index);
317         return nullptr;
318     }
319 
320     TAG_LOGD(AceLogTag::ACE_REPEAT,
321         "Repeat(%{public}d).GetFrameChildByIndex (index: %{public}d, key %{public}s, needBuild: %{public}d, "
322         "isCache: %{public}d, addToRenderTree: %{public}d) ...",
323         static_cast<int32_t>(GetId()), static_cast<int32_t>(index), key->c_str(), static_cast<int32_t>(needBuild),
324         static_cast<int32_t>(isCache), static_cast<int32_t>(addToRenderTree));
325 
326     // search if index -> key -> Node exist
327     // will update the same key item if needs.
328     auto node4Index = GetFromCaches(index);
329     if (!node4Index && !needBuild) {
330         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).GetFrameChildByIndex index %{public}d, key '%{public}s' "
331             "not in caches && needBuild==false, GetFrameChildByIndex returns nullptr .",
332             static_cast<int32_t>(GetId()), static_cast<int32_t>(index), key->c_str());
333         return nullptr;
334     }
335 
336     // node4Index needs to be created or updated on JS side
337     if (!node4Index) {
338         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).GetFrameChildByIndex index %{public}d -> key '%{public}s' "
339             "not in caches && needBuild==true", static_cast<int32_t>(GetId()), static_cast<int32_t>(index),
340             key->c_str());
341 
342         // ask TS to update a Node when enable reuse, if possible
343         // if no suitable node, request to create a new node
344         if (reusable_) {
345             node4Index = caches_.UpdateFromL2(index);
346         }
347         if (!node4Index) {
348             node4Index = caches_.CreateNewNode(index);
349             isChildReused = false;
350         }
351 
352         if (!node4Index) {
353             TAG_LOGW(AceLogTag::ACE_REPEAT, "index %{public}d -> key '%{public}s' not in caches and failed to build.",
354                 static_cast<int32_t>(index), key->c_str());
355             return nullptr;
356         }
357     }
358 
359     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).GetFrameChildByIndex index %{public}d -> key '%{public}s', "
360         "needBuild==true, node: %{public}s .", static_cast<int32_t>(GetId()), static_cast<int32_t>(index),
361         key->c_str(), caches_.DumpUINode(node4Index).c_str());
362 
363     node4Index->UpdateThemeScopeId(GetThemeScopeId());
364 
365     if (isActive_) {
366         node4Index->SetJSViewActive(true);
367     }
368 
369     if (addToRenderTree && !isCache) {
370         TAG_LOGD(AceLogTag::ACE_REPEAT,
371             "Repeat(%{public}d).GetFrameChildByIndex index %{public}d isCache==false setActive and adding to L1 cache",
372             static_cast<int32_t>(GetId()), static_cast<int32_t>(index));
373         node4Index->SetActive(true);
374     }
375 
376     if (caches_.IsInL1Cache(key.value())) {
377         return node4Index->GetFrameChildByIndex(0, needBuild);
378     }
379 
380     // refresh the cached ttype and verify it hasn't changed
381     if (caches_.CheckTTypeChanged(index)) {
382         return GetFrameChildByIndex(index, needBuild, isCache, addToRenderTree);
383     }
384 
385     // if the item was in L2 cache, move item to L1 cache.
386     caches_.AddKeyToL1WithNodeUpdate(key.value(), index, isChildReused);
387 
388     if (node4Index->GetDepth() != GetDepth() + 1) {
389         node4Index->SetDepth(GetDepth() + 1);
390     }
391     // attach to repeat node and pass context to it.
392     node4Index->SetParent(WeakClaim(this));
393     if (IsOnMainTree()) {
394         node4Index->AttachToMainTree(false, GetContext());
395     }
396 
397     MarkNeedSyncRenderTree();
398     children_.clear();
399     // re-assemble children_
400     PostIdleTask();
401 
402     auto childNode = node4Index->GetFrameChildByIndex(0, needBuild);
403     if (childNode && onMoveEvent_) {
404         InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
405     }
406 
407     // this is new node or node from L2 cache
408     if (childNode) {
409         TAG_LOGD(AceLogTag::ACE_REPEAT,
410             "Repeat(%{public}d).GetFrameChildByIndex index %{public}d, its child is %{public}d, returning child.",
411             static_cast<int32_t>(GetId()), static_cast<int32_t>(index), static_cast<int32_t>(childNode->GetId()));
412     }
413 
414     return childNode;
415 }
416 
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool)417 int32_t RepeatVirtualScrollNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool /*isExpanded*/)
418 {
419     return caches_.GetFrameNodeIndex(node);
420 }
421 
GetChildren(bool) const422 const std::list<RefPtr<UINode>>& RepeatVirtualScrollNode::GetChildren(bool /*notDetach*/) const
423 {
424     if (!children_.empty()) {
425         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).GetChildren just returns non-empty children_",
426             static_cast<int32_t>(GetId()));
427         return children_;
428     }
429 
430     // can not modify l1_cache while iterating
431     // GetChildren is overloaded, can not change it to non-const
432     // need to order the child.
433     std::map<int32_t, RefPtr<UINode>> children;
434     caches_.ForEachL1IndexUINode(children);
435     for (const auto& [index, child] : children) {
436         const_cast<RepeatVirtualScrollNode*>(this)->RemoveDisappearingChild(child);
437         children_.emplace_back(child);
438     }
439     return children_;
440 }
441 
OnRecycle()442 void RepeatVirtualScrollNode::OnRecycle()
443 {
444     for (auto& [key, child]: caches_.GetAllNodes()) {
445         if (caches_.IsInL1Cache(key) && child.item) {
446             child.item->OnRecycle();
447         }
448     }
449 }
450 
OnReuse()451 void RepeatVirtualScrollNode::OnReuse()
452 {
453     for (auto& [key, child]: caches_.GetAllNodes()) {
454         if (caches_.IsInL1Cache(key) && child.item) {
455             child.item->OnReuse();
456         }
457     }
458 }
459 
UpdateChildrenFreezeState(bool isFreeze,bool isForceUpdateFreezeVaule)460 void RepeatVirtualScrollNode::UpdateChildrenFreezeState(bool isFreeze, bool isForceUpdateFreezeVaule)
461 {
462     const auto& allChildren = caches_.GetAllNodes();
463     for (auto& child : allChildren) {
464         if (child.second.item) {
465             child.second.item->SetFreeze(isFreeze);
466         }
467     }
468 }
469 
RecycleItems(int32_t from,int32_t to)470 void RepeatVirtualScrollNode::RecycleItems(int32_t from, int32_t to)
471 {
472     TAG_LOGD(AceLogTag::ACE_REPEAT,
473         "Repeat(%{public}d).RecycleItems Layout prediction instructs to move Repeat items from index %{public}d up to "
474         "smaller than %{public}d to the reusable items cache",
475         static_cast<int32_t>(GetId()), from - startIndex_, to - startIndex_);
476 
477     offscreenItems_.from = from;
478     offscreenItems_.to = to;
479     for (auto i = from; i < to; i++) {
480         if (i >= startIndex_ && i < startIndex_ + static_cast<int32_t>(totalCount_)) {
481             caches_.RecycleItemsByIndex(i - startIndex_);
482         }
483     }
484 }
485 
SetNodeIndexOffset(int32_t start,int32_t)486 void RepeatVirtualScrollNode::SetNodeIndexOffset(int32_t start, int32_t /*count*/)
487 {
488     startIndex_ = start;
489 }
490 
FrameCount() const491 int32_t RepeatVirtualScrollNode::FrameCount() const
492 {
493     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).FrameCount returns %{public}d",
494         static_cast<int32_t>(GetId()), static_cast<int32_t>(totalCount_));
495     return totalCount_;
496 }
497 
PostIdleTask()498 void RepeatVirtualScrollNode::PostIdleTask()
499 {
500     if (postUpdateTaskHasBeenScheduled_) {
501         return;
502     }
503     TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask Posting idle task",
504         static_cast<int32_t>(GetId()));
505     postUpdateTaskHasBeenScheduled_ = true;
506     auto* context = GetContext();
507     CHECK_NULL_VOID(context);
508 
509     context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t /*deadline*/, bool /*canUseLongPredictTask*/) {
510         ACE_SCOPED_TRACE("Repeat.IdleTask");
511         auto node = weak.Upgrade();
512         CHECK_NULL_VOID(node);
513         node->postUpdateTaskHasBeenScheduled_ = false;
514         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask idle task calls GetChildren",
515             static_cast<int32_t>(node->GetId()));
516         node->GetChildren();
517         node->caches_.Purge();
518         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask ========== after caches.purge =========== ",
519             static_cast<int32_t>(node->GetId()));
520         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask %{public}s",
521             static_cast<int32_t>(node->GetId()), node->caches_.DumpL1().c_str());
522         TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask %{public}s",
523             static_cast<int32_t>(node->GetId()), node->caches_.DumpL2().c_str());
524     });
525 }
526 
OnConfigurationUpdate(const ConfigurationChange & configurationChange)527 void RepeatVirtualScrollNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
528 {
529     if ((configurationChange.colorModeUpdate || configurationChange.fontUpdate)) {
530         const auto& children = caches_.GetAllNodes();
531         for (const auto& [key, child] : children) {
532             if (child.item) {
533                 child.item->UpdateConfigurationUpdate(configurationChange);
534             }
535         }
536     }
537 }
538 
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)539 void RepeatVirtualScrollNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
540 {
541     // To do
542 }
543 
544 // FOREAch
MoveData(int32_t from,int32_t to)545 void RepeatVirtualScrollNode::MoveData(int32_t from, int32_t to) {}
546 
GetFrameNode(int32_t index)547 RefPtr<FrameNode> RepeatVirtualScrollNode::GetFrameNode(int32_t index)
548 {
549     return AceType::DynamicCast<FrameNode>(GetFrameChildByIndex(index, false, false));
550 }
551 
InitDragManager(const RefPtr<UINode> & child)552 void RepeatVirtualScrollNode::InitDragManager(const RefPtr<UINode>& child)
553 {
554     // To do
555 }
556 
InitAllChildrenDragManager(bool init)557 void RepeatVirtualScrollNode::InitAllChildrenDragManager(bool init)
558 {
559     // To do
560 }
561 
562 } // namespace OHOS::Ace::NG
563