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 #include "core/components_ng/syntax/lazy_for_each_node.h"
17
18 #include <utility>
19
20 #include "base/log/ace_trace.h"
21 #include "base/log/dump_log.h"
22 #include "base/memory/referenced.h"
23 #include "base/utils/time_util.h"
24 #include "base/utils/utils.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/list/list_item_pattern.h"
27 #include "core/components_ng/property/property.h"
28 #include "core/components_ng/syntax/lazy_layout_wrapper_builder.h"
29 #include "core/components_v2/inspector/inspector_constants.h"
30 #include "core/pipeline/base/element_register.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace::NG {
34
GetOrCreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)35 RefPtr<LazyForEachNode> LazyForEachNode::GetOrCreateLazyForEachNode(
36 int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
37 {
38 auto node = ElementRegister::GetInstance()->GetSpecificItemById<LazyForEachNode>(nodeId);
39 if (node) {
40 if (node->builder_ != forEachBuilder) {
41 TAG_LOGI(AceLogTag::ACE_LAZY_FOREACH, "replace old lazy for each builder");
42 node->builder_ = forEachBuilder;
43 }
44 return node;
45 }
46 node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
47 ElementRegister::GetInstance()->AddUINode(node);
48 node->RegisterBuilderListener();
49 return node;
50 }
51
CreateLazyForEachNode(int32_t nodeId,const RefPtr<LazyForEachBuilder> & forEachBuilder)52 RefPtr<LazyForEachNode> LazyForEachNode::CreateLazyForEachNode(
53 int32_t nodeId, const RefPtr<LazyForEachBuilder>& forEachBuilder)
54 {
55 auto node = MakeRefPtr<LazyForEachNode>(nodeId, forEachBuilder);
56 ElementRegister::GetInstance()->AddUINode(node);
57 return node;
58 }
59
AdjustLayoutWrapperTree(const RefPtr<LayoutWrapperNode> & parent,bool forceMeasure,bool forceLayout)60 void LazyForEachNode::AdjustLayoutWrapperTree(
61 const RefPtr<LayoutWrapperNode>& parent, bool forceMeasure, bool forceLayout)
62 {
63 CHECK_NULL_VOID(builder_);
64 auto lazyLayoutWrapperBuilder = MakeRefPtr<LazyLayoutWrapperBuilder>(builder_, WeakClaim(this));
65 if (parent->GetHostTag() == V2::SWIPER_ETS_TAG) {
66 lazyLayoutWrapperBuilder->SetLazySwiper();
67 }
68 lazyLayoutWrapperBuilder->UpdateForceFlag(forceMeasure, forceLayout);
69 parent->SetLayoutWrapperBuilder(lazyLayoutWrapperBuilder);
70 }
71
BuildAllChildren()72 void LazyForEachNode::BuildAllChildren()
73 {
74 for (int i = 0; i < FrameCount(); i++) {
75 GetFrameChildByIndex(i, true);
76 }
77 tempChildren_.clear();
78 tempChildren_.swap(children_);
79 auto items = builder_->GetAllChildren();
80 for (auto& [index, item] : items) {
81 if (item.second) {
82 RemoveDisappearingChild(item.second);
83 children_.push_back(item.second);
84 }
85 }
86 }
87
PostIdleTask()88 void LazyForEachNode::PostIdleTask()
89 {
90 if (needPredict_) {
91 return;
92 }
93 needPredict_ = true;
94 auto context = GetContext();
95 CHECK_NULL_VOID(context);
96 context->AddPredictTask([weak = AceType::WeakClaim(this)](int64_t deadline, bool canUseLongPredictTask) {
97 ACE_SCOPED_TRACE("LazyForEach predict");
98 auto node = weak.Upgrade();
99 CHECK_NULL_VOID(node);
100 node->needPredict_ = false;
101 auto canRunLongPredictTask = node->requestLongPredict_ && canUseLongPredictTask;
102 if (node->builder_) {
103 node->GetChildren();
104 auto preBuildResult = node->builder_->PreBuild(deadline, node->itemConstraint_, canRunLongPredictTask);
105 if (!preBuildResult) {
106 node->PostIdleTask();
107 } else {
108 node->requestLongPredict_ = true;
109 node->itemConstraint_.reset();
110 }
111 }
112 });
113 }
114
OnDataReloaded()115 void LazyForEachNode::OnDataReloaded()
116 {
117 ACE_SCOPED_TRACE("LazyForEach OnDataReloaded");
118 tempChildren_.clear();
119 tempChildren_.swap(children_);
120 if (builder_) {
121 builder_->SetUseNewInterface(false);
122 builder_->OnDataReloaded();
123 if (FrameCount() == 0) {
124 PostIdleTask();
125 }
126 }
127 NotifyChangeWithCount(0, 0, NotificationType::START_CHANGE_POSITION);
128 NotifyChangeWithCount(static_cast<int32_t>(FrameCount()), 0, NotificationType::END_CHANGE_POSITION);
129 MarkNeedSyncRenderTree(true);
130 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
131 }
132
OnDataAdded(size_t index)133 void LazyForEachNode::OnDataAdded(size_t index)
134 {
135 ACE_SCOPED_TRACE("LazyForEach OnDataAdded");
136 auto insertIndex = static_cast<int32_t>(index);
137 if (builder_) {
138 builder_->SetUseNewInterface(false);
139 builder_->OnDataAdded(index);
140 }
141 tempChildren_.clear();
142 tempChildren_.swap(children_);
143 NotifyChangeWithCount(insertIndex, 1, NotificationType::START_AND_END_CHANGE_POSITION);
144 MarkNeedSyncRenderTree(true);
145 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
146 }
147
OnDataBulkAdded(size_t index,size_t count)148 void LazyForEachNode::OnDataBulkAdded(size_t index, size_t count)
149 {
150 ACE_SCOPED_TRACE("LazyForEach OnDataBulkAdded");
151 auto insertIndex = static_cast<int32_t>(index);
152 if (builder_) {
153 builder_->SetUseNewInterface(false);
154 builder_->OnDataBulkAdded(index, count);
155 }
156 tempChildren_.clear();
157 tempChildren_.swap(children_);
158 NotifyChangeWithCount(insertIndex, static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
159 MarkNeedSyncRenderTree(true);
160 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
161 }
162
OnDataDeleted(size_t index)163 void LazyForEachNode::OnDataDeleted(size_t index)
164 {
165 ACE_SCOPED_TRACE("LazyForEach OnDataDeleted");
166 auto deletedIndex = static_cast<int32_t>(index);
167 if (builder_) {
168 builder_->SetUseNewInterface(false);
169 auto node = builder_->OnDataDeleted(index);
170
171 if (node) {
172 if (!node->OnRemoveFromParent(true)) {
173 AddDisappearingChild(node);
174 } else {
175 node->DetachFromMainTree();
176 }
177 builder_->ProcessOffscreenNode(node, true);
178 }
179 }
180 tempChildren_.clear();
181 tempChildren_.swap(children_);
182 NotifyChangeWithCount(deletedIndex, -1, NotificationType::START_AND_END_CHANGE_POSITION);
183 MarkNeedSyncRenderTree(true);
184 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
185 }
186
OnDataBulkDeleted(size_t index,size_t count)187 void LazyForEachNode::OnDataBulkDeleted(size_t index, size_t count)
188 {
189 ACE_SCOPED_TRACE("LazyForEach OnDataBulkDeleted");
190 auto deletedIndex = static_cast<int32_t>(index);
191 if (builder_) {
192 builder_->SetUseNewInterface(false);
193 const auto& nodeList = builder_->OnDataBulkDeleted(index, count);
194 for (const auto& node : nodeList) {
195 if (node.second == nullptr) {
196 continue;
197 }
198 if (!node.second->OnRemoveFromParent(true)) {
199 AddDisappearingChild(node.second);
200 } else {
201 node.second->DetachFromMainTree();
202 }
203 builder_->ProcessOffscreenNode(node.second, true);
204 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
205 }
206 builder_->clearDeletedNodes();
207 }
208 tempChildren_.clear();
209 tempChildren_.swap(children_);
210 NotifyChangeWithCount(deletedIndex, -static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
211 MarkNeedSyncRenderTree(true);
212 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
213 }
214
OnDataChanged(size_t index)215 void LazyForEachNode::OnDataChanged(size_t index)
216 {
217 auto changedIndex = static_cast<int32_t>(index);
218 if (builder_) {
219 builder_->SetUseNewInterface(false);
220 builder_->OnDataChanged(index);
221 }
222 tempChildren_.clear();
223 tempChildren_.swap(children_);
224 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_AND_END_CHANGE_POSITION);
225 MarkNeedSyncRenderTree(true);
226 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
227 }
228
OnDataBulkChanged(size_t index,size_t count)229 void LazyForEachNode::OnDataBulkChanged(size_t index, size_t count)
230 {
231 ACE_SCOPED_TRACE("LazyForEach OnDataBulkChanged");
232 auto changedIndex = static_cast<int32_t>(index);
233 if (builder_) {
234 builder_->SetUseNewInterface(false);
235 const auto& nodeList = builder_->OnDataBulkChanged(index, count);
236 for (const auto& node : nodeList) {
237 if (node.second == nullptr) {
238 continue;
239 }
240 if (!node.second->OnRemoveFromParent(true)) {
241 AddDisappearingChild(node.second);
242 } else {
243 node.second->DetachFromMainTree();
244 }
245 builder_->ProcessOffscreenNode(node.second, true);
246 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
247 }
248 builder_->clearDeletedNodes();
249 }
250 tempChildren_.clear();
251 tempChildren_.swap(children_);
252 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_CHANGE_POSITION);
253 NotifyChangeWithCount(changedIndex + static_cast<int32_t>(count) - 1, 0, NotificationType::END_CHANGE_POSITION);
254 MarkNeedSyncRenderTree(true);
255 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
256 }
257
OnDataMoveToNewPlace(size_t from,size_t to)258 void LazyForEachNode::OnDataMoveToNewPlace(size_t from, size_t to)
259 {
260 if (builder_) {
261 builder_->SetUseNewInterface(false);
262 builder_->OnDataMoveToNewPlace(from, to);
263 }
264 tempChildren_.clear();
265 tempChildren_.swap(children_);
266 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
267 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
268 MarkNeedSyncRenderTree(true);
269 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
270 }
271
OnDataMoved(size_t from,size_t to)272 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
273 {
274 if (builder_) {
275 builder_->SetUseNewInterface(false);
276 builder_->OnDataMoved(from, to);
277 }
278 tempChildren_.clear();
279 tempChildren_.swap(children_);
280 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
281 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
282 MarkNeedSyncRenderTree(true);
283 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
284 }
285
OnDatasetChange(const std::list<V2::Operation> & DataOperations)286 void LazyForEachNode::OnDatasetChange(const std::list<V2::Operation>& DataOperations)
287 {
288 ACE_SCOPED_TRACE("LazyForEach OnDatasetChange");
289 int32_t initialChangedIndex = 0;
290 if (builder_) {
291 builder_->SetUseNewInterface(true);
292 std::pair<int32_t, std::list<std::pair<std::string, RefPtr<UINode>>>> pair =
293 builder_->OnDatasetChange(DataOperations);
294 initialChangedIndex = pair.first;
295 std::list<std::pair<std::string, RefPtr<UINode>>> nodeList = pair.second;
296 for (const auto& node : nodeList) {
297 if (node.second == nullptr) {
298 continue;
299 }
300 if (!node.second->OnRemoveFromParent(true)) {
301 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
302 } else {
303 node.second->DetachFromMainTree();
304 }
305 builder_->ProcessOffscreenNode(node.second, true);
306 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
307 }
308 builder_->clearDeletedNodes();
309 }
310 tempChildren_.clear();
311 tempChildren_.swap(children_);
312 NotifyChangeWithCount(initialChangedIndex, 0, NotificationType::START_CHANGE_POSITION);
313 ParseOperations(DataOperations);
314 MarkNeedSyncRenderTree(true);
315 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
316 }
317
MarkNeedSyncRenderTree(bool needRebuild)318 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
319 {
320 if (needMarkParent_) {
321 UINode::MarkNeedSyncRenderTree(needRebuild);
322 }
323 }
324
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)325 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
326 {
327 if (index >= static_cast<uint32_t>(FrameCount())) {
328 return nullptr;
329 }
330 auto child = builder_->GetChildByIndex(index, needBuild, isCache);
331 if (!child.second) {
332 return nullptr;
333 }
334 if (isCache) {
335 child.second->SetParent(WeakClaim(this));
336 child.second->SetJSViewActive(false, true);
337 return child.second->GetFrameChildByIndex(0, needBuild);
338 }
339 if (isActive_) {
340 child.second->SetJSViewActive(true, true);
341 }
342 if (addToRenderTree) {
343 child.second->SetActive(true);
344 }
345 if (child.second->GetDepth() != GetDepth() + 1) {
346 child.second->SetDepth(GetDepth() + 1);
347 }
348 MarkNeedSyncRenderTree();
349 tempChildren_.clear();
350 tempChildren_.swap(children_);
351 child.second->SetParent(WeakClaim(this));
352 if (IsOnMainTree()) {
353 child.second->AttachToMainTree(false, GetContext());
354 }
355 PostIdleTask();
356 auto childNode = child.second->GetFrameChildByIndex(0, needBuild);
357 if (onMoveEvent_) {
358 InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
359 }
360 return childNode;
361 }
362
GetIndexByUINode(const RefPtr<UINode> & uiNode) const363 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
364 {
365 if (!builder_) {
366 return -1;
367 }
368 auto items = builder_->GetAllChildren();
369 for (auto& [index, item] : items) {
370 if (item.second == uiNode) {
371 return index;
372 }
373 }
374 return -1;
375 }
376
RecycleItems(int32_t from,int32_t to)377 void LazyForEachNode::RecycleItems(int32_t from, int32_t to)
378 {
379 if (!builder_) {
380 return;
381 }
382 tempChildren_.clear();
383 tempChildren_.swap(children_);
384 for (auto index = from; index < to; index++) {
385 if (index >= startIndex_ && index < startIndex_ + count_) {
386 builder_->RecordOutOfBoundaryNodes(index - startIndex_);
387 }
388 }
389 PostIdleTask();
390 }
391
DoRemoveChildInRenderTree(uint32_t index,bool isAll)392 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
393 {
394 if (!builder_) {
395 return;
396 }
397 tempChildren_.clear();
398 tempChildren_.swap(children_);
399 if (isAll) {
400 builder_->RemoveAllChild();
401 MarkNeedSyncRenderTree();
402 PostIdleTask();
403 }
404 }
405
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd,bool showCache)406 void LazyForEachNode::DoSetActiveChildRange(
407 int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd, bool showCache)
408 {
409 if (!builder_) {
410 return;
411 }
412 if (showCache) {
413 start -= cacheStart;
414 end += cacheEnd;
415 builder_->SetShowCached(cacheStart, cacheEnd);
416 }
417 if (builder_->SetActiveChildRange(start, end)) {
418 tempChildren_.clear();
419 tempChildren_.swap(children_);
420 MarkNeedSyncRenderTree();
421 PostIdleTask();
422 }
423 }
424
GetChildren(bool notDetach) const425 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren(bool notDetach) const
426 {
427 if (children_.empty()) {
428 LoadChildren(notDetach);
429
430 // if measure not done, return previous children
431 if (notDetach && children_.empty()) {
432 return tempChildren_;
433 }
434
435 tempChildren_.clear();
436 }
437 return children_;
438 }
439
UpdateChildrenFreezeState(bool isFreeze)440 void LazyForEachNode::UpdateChildrenFreezeState(bool isFreeze)
441 {
442 if (!builder_) {
443 return;
444 }
445 std::vector<UINode*> children;
446 builder_->GetAllItems(children);
447 for (const auto& child : children) {
448 if (child) {
449 child->SetFreeze(isFreeze);
450 }
451 }
452 }
453
LoadChildren(bool notDetach) const454 void LazyForEachNode::LoadChildren(bool notDetach) const
455 {
456 std::list<std::pair<std::string, RefPtr<UINode>>> childList;
457 const auto& items = builder_->GetItems(childList);
458
459 if (!notDetach) {
460 for (auto& node : childList) {
461 if (!node.second->OnRemoveFromParent(true)) {
462 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
463 } else {
464 node.second->DetachFromMainTree();
465 }
466 }
467 }
468
469 for (const auto& [index, item] : items) {
470 if (item.second) {
471 const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
472 children_.push_back(item.second);
473 }
474 }
475 }
476
OnConfigurationUpdate(const ConfigurationChange & configurationChange)477 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
478 {
479 if (configurationChange.IsNeedUpdate() && builder_) {
480 auto map = builder_->GetCachedUINodeMap();
481 for (auto& it : map) {
482 auto node = DynamicCast<UINode>(it.second.second);
483 if (node) {
484 node->UpdateConfigurationUpdate(configurationChange);
485 }
486 }
487 }
488 }
489
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)490 void LazyForEachNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
491 {
492 if (onMove && !onMoveEvent_) {
493 InitAllChilrenDragManager(true);
494 } else if (!onMove && onMoveEvent_) {
495 InitAllChilrenDragManager(false);
496 }
497 onMoveEvent_ = onMove;
498 }
499
MoveData(int32_t from,int32_t to)500 void LazyForEachNode::MoveData(int32_t from, int32_t to)
501 {
502 if (builder_) {
503 builder_->OnDataMoveToNewPlace(from, to);
504 builder_->UpdateMoveFromTo(from, to);
505 }
506 tempChildren_.clear();
507 tempChildren_.swap(children_);
508 MarkNeedSyncRenderTree(true);
509 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
510 }
511
FireOnMove(int32_t from,int32_t to)512 void LazyForEachNode::FireOnMove(int32_t from, int32_t to)
513 {
514 if (builder_) {
515 builder_->ResetMoveFromTo();
516 }
517 ForEachBaseNode::FireOnMove(from, to);
518 }
519
GetFrameNode(int32_t index)520 RefPtr<FrameNode> LazyForEachNode::GetFrameNode(int32_t index)
521 {
522 CHECK_NULL_RETURN(builder_, nullptr);
523 auto child = builder_->GetChildByIndex(index, false, false);
524 CHECK_NULL_RETURN(child.second, nullptr);
525 return AceType::DynamicCast<FrameNode>(child.second->GetFrameChildByIndex(0, true));
526 }
527
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)528 int32_t LazyForEachNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
529 {
530 if (!isExpanded) {
531 return UINode::GetFrameNodeIndex(node, false);
532 }
533 CHECK_NULL_RETURN(builder_, -1);
534 return builder_->GetChildIndex(node);
535 }
536
InitDragManager(const RefPtr<FrameNode> & childNode)537 void LazyForEachNode::InitDragManager(const RefPtr<FrameNode>& childNode)
538 {
539 CHECK_NULL_VOID(childNode);
540 auto parentNode = GetParentFrameNode();
541 CHECK_NULL_VOID(parentNode);
542 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
543 return;
544 }
545 auto pattern = childNode->GetPattern<ListItemPattern>();
546 CHECK_NULL_VOID(pattern);
547 pattern->InitDragManager(AceType::Claim(this));
548 }
549
InitAllChilrenDragManager(bool init)550 void LazyForEachNode::InitAllChilrenDragManager(bool init)
551 {
552 auto parentNode = GetParentFrameNode();
553 CHECK_NULL_VOID(parentNode);
554 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
555 return;
556 }
557 const auto& children = GetChildren();
558 for (const auto& child : children) {
559 if (!child) {
560 continue;
561 }
562 auto childNode = child->GetFrameChildByIndex(0, false);
563 auto listItem = AceType::DynamicCast<FrameNode>(childNode);
564 if (!listItem) {
565 continue;
566 }
567
568 auto pattern = listItem->GetPattern<ListItemPattern>();
569 if (!pattern) {
570 continue;
571 }
572 if (init) {
573 pattern->InitDragManager(AceType::Claim(this));
574 } else {
575 pattern->DeInitDragManager();
576 }
577 }
578 }
579
NotifyChangeWithCount(int32_t index,int32_t count,NotificationType notificationType) const580 void LazyForEachNode::NotifyChangeWithCount(int32_t index, int32_t count, NotificationType notificationType) const
581 {
582 auto parent = GetParent();
583 int64_t accessibilityId = GetAccessibilityId();
584 if (parent) {
585 parent->NotifyChange(index, count, accessibilityId, notificationType);
586 }
587 }
588
ParseOperations(const std::list<V2::Operation> & dataOperations)589 void LazyForEachNode::ParseOperations(const std::list<V2::Operation>& dataOperations)
590 {
591 std::map<std::string, int32_t> operationTypeMap = { { "add", 1 }, { "delete", 2 }, { "change", 3 }, { "move", 4 },
592 { "exchange", 5 }, { "reload", 6 } };
593 constexpr int ADDOP = 1;
594 constexpr int DELETEOP = 2;
595 constexpr int CHANGEOP = 3;
596 constexpr int MOVEOP = 4;
597 constexpr int EXCHANGEOP = 5;
598 constexpr int RELOADOP = 6;
599 for (const auto& operation : dataOperations) {
600 switch (operationTypeMap[operation.type]) {
601 case ADDOP:
602 NotifyChangeWithCount(operation.index, operation.count, NotificationType::END_CHANGE_POSITION);
603 break;
604 case DELETEOP:
605 NotifyChangeWithCount(operation.index, -operation.count, NotificationType::END_CHANGE_POSITION);
606 break;
607 case CHANGEOP:
608 NotifyChangeWithCount(operation.index + operation.count - 1, 0, NotificationType::END_CHANGE_POSITION);
609 break;
610 case MOVEOP:
611 NotifyChangeWithCount(std::max(operation.coupleIndex.first, operation.coupleIndex.second), 0,
612 NotificationType::END_CHANGE_POSITION);
613 break;
614 case EXCHANGEOP:
615 NotifyChangeWithCount(operation.coupleIndex.second, 0, NotificationType::END_CHANGE_POSITION);
616 break;
617 case RELOADOP:
618 NotifyChangeWithCount(static_cast<int32_t>(FrameCount()), 0, NotificationType::END_CHANGE_POSITION);
619 break;
620 }
621 }
622 }
623 } // namespace OHOS::Ace::NG
624