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 -> node not in caches and failed to build.",
354 static_cast<int32_t>(index));
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 if (child) {
437 const_cast<RepeatVirtualScrollNode*>(this)->RemoveDisappearingChild(child);
438 }
439 children_.emplace_back(child);
440 }
441 return children_;
442 }
443
GetChildrenForInspector(bool needCacheNode) const444 const std::list<RefPtr<UINode>>& RepeatVirtualScrollNode::GetChildrenForInspector(bool needCacheNode) const
445 {
446 return children_;
447 }
448
OnRecycle()449 void RepeatVirtualScrollNode::OnRecycle()
450 {
451 for (auto& [key, child]: caches_.GetAllNodes()) {
452 if (caches_.IsInL1Cache(key) && child.item) {
453 child.item->OnRecycle();
454 }
455 }
456 }
457
OnReuse()458 void RepeatVirtualScrollNode::OnReuse()
459 {
460 for (auto& [key, child]: caches_.GetAllNodes()) {
461 if (caches_.IsInL1Cache(key) && child.item) {
462 child.item->OnReuse();
463 }
464 }
465 }
466
UpdateChildrenFreezeState(bool isFreeze,bool isForceUpdateFreezeVaule)467 void RepeatVirtualScrollNode::UpdateChildrenFreezeState(bool isFreeze, bool isForceUpdateFreezeVaule)
468 {
469 const auto& allChildren = caches_.GetAllNodes();
470 for (auto& child : allChildren) {
471 if (child.second.item) {
472 child.second.item->SetFreeze(isFreeze);
473 }
474 }
475 }
476
RecycleItems(int32_t from,int32_t to)477 void RepeatVirtualScrollNode::RecycleItems(int32_t from, int32_t to)
478 {
479 TAG_LOGD(AceLogTag::ACE_REPEAT,
480 "Repeat(%{public}d).RecycleItems Layout prediction instructs to move Repeat items from index %{public}d up to "
481 "smaller than %{public}d to the reusable items cache",
482 static_cast<int32_t>(GetId()), from - startIndex_, to - startIndex_);
483
484 offscreenItems_.from = from;
485 offscreenItems_.to = to;
486 }
487
SetNodeIndexOffset(int32_t start,int32_t)488 void RepeatVirtualScrollNode::SetNodeIndexOffset(int32_t start, int32_t /*count*/)
489 {
490 startIndex_ = start;
491 }
492
FrameCount() const493 int32_t RepeatVirtualScrollNode::FrameCount() const
494 {
495 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).FrameCount returns %{public}d",
496 static_cast<int32_t>(GetId()), static_cast<int32_t>(totalCount_));
497 return totalCount_;
498 }
499
PostIdleTask()500 void RepeatVirtualScrollNode::PostIdleTask()
501 {
502 if (postUpdateTaskHasBeenScheduled_) {
503 return;
504 }
505 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask Posting idle task",
506 static_cast<int32_t>(GetId()));
507 postUpdateTaskHasBeenScheduled_ = true;
508 auto* context = GetContext();
509 CHECK_NULL_VOID(context);
510
511 context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t /*deadline*/, bool /*canUseLongPredictTask*/) {
512 ACE_SCOPED_TRACE("Repeat.IdleTask");
513 auto node = weak.Upgrade();
514 CHECK_NULL_VOID(node);
515 node->postUpdateTaskHasBeenScheduled_ = false;
516 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask idle task calls GetChildren",
517 static_cast<int32_t>(node->GetId()));
518 node->GetChildren();
519 node->caches_.Purge();
520 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask ========== after caches.purge =========== ",
521 static_cast<int32_t>(node->GetId()));
522 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask %{public}s",
523 static_cast<int32_t>(node->GetId()), node->caches_.DumpL1().c_str());
524 TAG_LOGD(AceLogTag::ACE_REPEAT, "Repeat(%{public}d).PostIdleTask %{public}s",
525 static_cast<int32_t>(node->GetId()), node->caches_.DumpL2().c_str());
526 });
527 }
528
OnConfigurationUpdate(const ConfigurationChange & configurationChange)529 void RepeatVirtualScrollNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
530 {
531 if ((configurationChange.colorModeUpdate || configurationChange.fontUpdate)) {
532 const auto& children = caches_.GetAllNodes();
533 for (const auto& [key, child] : children) {
534 if (child.item) {
535 child.item->UpdateConfigurationUpdate(configurationChange);
536 }
537 }
538 }
539 }
540
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)541 void RepeatVirtualScrollNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
542 {
543 // To do
544 }
545
546 // FOREAch
MoveData(int32_t from,int32_t to)547 void RepeatVirtualScrollNode::MoveData(int32_t from, int32_t to) {}
548
GetFrameNode(int32_t index)549 RefPtr<FrameNode> RepeatVirtualScrollNode::GetFrameNode(int32_t index)
550 {
551 return AceType::DynamicCast<FrameNode>(GetFrameChildByIndex(index, false, false));
552 }
553
InitDragManager(const RefPtr<UINode> & child)554 void RepeatVirtualScrollNode::InitDragManager(const RefPtr<UINode>& child)
555 {
556 // To do
557 }
558
InitAllChildrenDragManager(bool init)559 void RepeatVirtualScrollNode::InitAllChildrenDragManager(bool init)
560 {
561 // To do
562 }
563
564 } // namespace OHOS::Ace::NG
565