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_ = false;
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 MarkNeedSyncRenderTree(true);
129 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
130 }
131
OnDataAdded(size_t index)132 void LazyForEachNode::OnDataAdded(size_t index)
133 {
134 ACE_SCOPED_TRACE("LazyForEach OnDataAdded");
135 auto insertIndex = static_cast<int32_t>(index);
136 if (builder_) {
137 builder_->SetUseNewInterface(false);
138 builder_->OnDataAdded(index);
139 }
140 tempChildren_.clear();
141 tempChildren_.swap(children_);
142 NotifyChangeWithCount(insertIndex, 1, NotificationType::START_AND_END_CHANGE_POSITION);
143 MarkNeedSyncRenderTree(true);
144 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
145 }
146
OnDataBulkAdded(size_t index,size_t count)147 void LazyForEachNode::OnDataBulkAdded(size_t index, size_t count)
148 {
149 ACE_SCOPED_TRACE("LazyForEach OnDataBulkAdded");
150 auto insertIndex = static_cast<int32_t>(index);
151 if (builder_) {
152 builder_->SetUseNewInterface(false);
153 builder_->OnDataBulkAdded(index, count);
154 }
155 tempChildren_.clear();
156 tempChildren_.swap(children_);
157 NotifyChangeWithCount(insertIndex, static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
158 MarkNeedSyncRenderTree(true);
159 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
160 }
161
OnDataDeleted(size_t index)162 void LazyForEachNode::OnDataDeleted(size_t index)
163 {
164 ACE_SCOPED_TRACE("LazyForEach OnDataDeleted");
165 auto deletedIndex = static_cast<int32_t>(index);
166 if (builder_) {
167 builder_->SetUseNewInterface(false);
168 auto node = builder_->OnDataDeleted(index);
169
170 if (node) {
171 if (!node->OnRemoveFromParent(true)) {
172 AddDisappearingChild(node);
173 } else {
174 node->DetachFromMainTree();
175 }
176 builder_->ProcessOffscreenNode(node, true);
177 }
178 }
179 tempChildren_.clear();
180 tempChildren_.swap(children_);
181 NotifyChangeWithCount(deletedIndex, -1, NotificationType::START_AND_END_CHANGE_POSITION);
182 MarkNeedSyncRenderTree(true);
183 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
184 }
185
OnDataBulkDeleted(size_t index,size_t count)186 void LazyForEachNode::OnDataBulkDeleted(size_t index, size_t count)
187 {
188 ACE_SCOPED_TRACE("LazyForEach OnDataBulkDeleted");
189 auto deletedIndex = static_cast<int32_t>(index);
190 if (builder_) {
191 builder_->SetUseNewInterface(false);
192 const auto& nodeList = builder_->OnDataBulkDeleted(index, count);
193 for (const auto& node : nodeList) {
194 if (node.second == nullptr) {
195 continue;
196 }
197 if (!node.second->OnRemoveFromParent(true)) {
198 AddDisappearingChild(node.second);
199 } else {
200 node.second->DetachFromMainTree();
201 }
202 builder_->ProcessOffscreenNode(node.second, true);
203 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
204 }
205 builder_->clearDeletedNodes();
206 }
207 tempChildren_.clear();
208 tempChildren_.swap(children_);
209 NotifyChangeWithCount(deletedIndex, -static_cast<int32_t>(count), NotificationType::START_AND_END_CHANGE_POSITION);
210 MarkNeedSyncRenderTree(true);
211 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
212 }
213
OnDataChanged(size_t index)214 void LazyForEachNode::OnDataChanged(size_t index)
215 {
216 auto changedIndex = static_cast<int32_t>(index);
217 if (builder_) {
218 builder_->SetUseNewInterface(false);
219 builder_->OnDataChanged(index);
220 }
221 tempChildren_.clear();
222 tempChildren_.swap(children_);
223 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_AND_END_CHANGE_POSITION);
224 MarkNeedSyncRenderTree(true);
225 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
226 }
227
OnDataBulkChanged(size_t index,size_t count)228 void LazyForEachNode::OnDataBulkChanged(size_t index, size_t count)
229 {
230 ACE_SCOPED_TRACE("LazyForEach OnDataBulkChanged");
231 auto changedIndex = static_cast<int32_t>(index);
232 if (builder_) {
233 builder_->SetUseNewInterface(false);
234 const auto& nodeList = builder_->OnDataBulkChanged(index, count);
235 for (const auto& node : nodeList) {
236 if (node.second == nullptr) {
237 continue;
238 }
239 if (!node.second->OnRemoveFromParent(true)) {
240 AddDisappearingChild(node.second);
241 } else {
242 node.second->DetachFromMainTree();
243 }
244 builder_->ProcessOffscreenNode(node.second, true);
245 builder_->NotifyItemDeleted(RawPtr(node.second), node.first);
246 }
247 builder_->clearDeletedNodes();
248 }
249 tempChildren_.clear();
250 tempChildren_.swap(children_);
251 NotifyChangeWithCount(changedIndex, 0, NotificationType::START_CHANGE_POSITION);
252 NotifyChangeWithCount(changedIndex + static_cast<int32_t>(count) - 1, 0, NotificationType::END_CHANGE_POSITION);
253 MarkNeedSyncRenderTree(true);
254 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
255 }
256
OnDataMoveToNewPlace(size_t from,size_t to)257 void LazyForEachNode::OnDataMoveToNewPlace(size_t from, size_t to)
258 {
259 if (builder_) {
260 builder_->SetUseNewInterface(false);
261 builder_->OnDataMoveToNewPlace(from, to);
262 }
263 tempChildren_.clear();
264 tempChildren_.swap(children_);
265 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
266 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
267 MarkNeedSyncRenderTree(true);
268 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
269 }
270
OnDataMoved(size_t from,size_t to)271 void LazyForEachNode::OnDataMoved(size_t from, size_t to)
272 {
273 if (builder_) {
274 builder_->SetUseNewInterface(false);
275 builder_->OnDataMoved(from, to);
276 }
277 tempChildren_.clear();
278 tempChildren_.swap(children_);
279 NotifyChangeWithCount(static_cast<int32_t>(std::min(from, to)), 0, NotificationType::START_CHANGE_POSITION);
280 NotifyChangeWithCount(static_cast<int32_t>(std::max(from, to)), 0, NotificationType::END_CHANGE_POSITION);
281 MarkNeedSyncRenderTree(true);
282 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
283 }
284
OnDatasetChange(const std::list<V2::Operation> & DataOperations)285 void LazyForEachNode::OnDatasetChange(const std::list<V2::Operation>& DataOperations)
286 {
287 ACE_SCOPED_TRACE("LazyForEach OnDatasetChange");
288 int32_t initialChangedIndex = 0;
289 if (builder_) {
290 builder_->SetUseNewInterface(true);
291 std::pair<int32_t, std::list<RefPtr<UINode>>> pair = builder_->OnDatasetChange(DataOperations);
292 initialChangedIndex = pair.first;
293 std::list<RefPtr<UINode>> nodeList_ = pair.second;
294 for (auto& node : nodeList_) {
295 if (node == nullptr) {
296 continue;
297 }
298 if (!node->OnRemoveFromParent(true)) {
299 AddDisappearingChild(node);
300 } else {
301 node->DetachFromMainTree();
302 }
303 builder_->ProcessOffscreenNode(node, true);
304 }
305 builder_->clearDeletedNodes();
306 }
307 tempChildren_.clear();
308 tempChildren_.swap(children_);
309 NotifyChangeWithCount(initialChangedIndex, 0, NotificationType::START_CHANGE_POSITION);
310 ParseOperations(DataOperations);
311 MarkNeedSyncRenderTree(true);
312 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
313 }
314
MarkNeedSyncRenderTree(bool needRebuild)315 void LazyForEachNode::MarkNeedSyncRenderTree(bool needRebuild)
316 {
317 if (needMarkParent_) {
318 UINode::MarkNeedSyncRenderTree(needRebuild);
319 }
320 }
321
GetFrameChildByIndex(uint32_t index,bool needBuild,bool isCache,bool addToRenderTree)322 RefPtr<UINode> LazyForEachNode::GetFrameChildByIndex(uint32_t index, bool needBuild, bool isCache, bool addToRenderTree)
323 {
324 if (index >= static_cast<uint32_t>(FrameCount())) {
325 return nullptr;
326 }
327 auto child = builder_->GetChildByIndex(index, needBuild, isCache);
328 if (!child.second) {
329 return nullptr;
330 }
331 if (isCache) {
332 child.second->SetParent(WeakClaim(this));
333 child.second->SetJSViewActive(false, true);
334 return child.second->GetFrameChildByIndex(0, needBuild);
335 }
336 if (isActive_) {
337 child.second->SetJSViewActive(true, true);
338 }
339 if (addToRenderTree) {
340 child.second->SetActive(true);
341 }
342 if (child.second->GetDepth() != GetDepth() + 1) {
343 child.second->SetDepth(GetDepth() + 1);
344 }
345 MarkNeedSyncRenderTree();
346 tempChildren_.clear();
347 tempChildren_.swap(children_);
348 child.second->SetParent(WeakClaim(this));
349 if (IsOnMainTree()) {
350 child.second->AttachToMainTree(false, GetContext());
351 }
352 PostIdleTask();
353 auto childNode = child.second->GetFrameChildByIndex(0, needBuild);
354 if (onMoveEvent_) {
355 InitDragManager(AceType::DynamicCast<FrameNode>(childNode));
356 }
357 return childNode;
358 }
359
GetIndexByUINode(const RefPtr<UINode> & uiNode) const360 int32_t LazyForEachNode::GetIndexByUINode(const RefPtr<UINode>& uiNode) const
361 {
362 if (!builder_) {
363 return -1;
364 }
365 auto items = builder_->GetAllChildren();
366 for (auto& [index, item] : items) {
367 if (item.second == uiNode) {
368 return index;
369 }
370 }
371 return -1;
372 }
373
RecycleItems(int32_t from,int32_t to)374 void LazyForEachNode::RecycleItems(int32_t from, int32_t to)
375 {
376 if (!builder_) {
377 return;
378 }
379 tempChildren_.clear();
380 tempChildren_.swap(children_);
381 for (auto index = from; index < to; index++) {
382 if (index >= startIndex_ && index < startIndex_ + count_) {
383 builder_->RecordOutOfBoundaryNodes(index - startIndex_);
384 }
385 }
386 PostIdleTask();
387 }
388
DoRemoveChildInRenderTree(uint32_t index,bool isAll)389 void LazyForEachNode::DoRemoveChildInRenderTree(uint32_t index, bool isAll)
390 {
391 if (!builder_) {
392 return;
393 }
394 tempChildren_.clear();
395 tempChildren_.swap(children_);
396 if (isAll) {
397 builder_->RemoveAllChild();
398 MarkNeedSyncRenderTree();
399 PostIdleTask();
400 }
401 }
402
DoSetActiveChildRange(int32_t start,int32_t end,int32_t cacheStart,int32_t cacheEnd)403 void LazyForEachNode::DoSetActiveChildRange(int32_t start, int32_t end, int32_t cacheStart, int32_t cacheEnd)
404 {
405 if (!builder_) {
406 return;
407 }
408 if (builder_->SetActiveChildRange(start, end)) {
409 tempChildren_.clear();
410 tempChildren_.swap(children_);
411 MarkNeedSyncRenderTree();
412 PostIdleTask();
413 }
414 }
415
GetChildren(bool notDetach) const416 const std::list<RefPtr<UINode>>& LazyForEachNode::GetChildren(bool notDetach) const
417 {
418 if (children_.empty()) {
419 LoadChildren(notDetach);
420
421 // if measure not done, return previous children
422 if (notDetach && children_.empty()) {
423 return tempChildren_;
424 }
425
426 tempChildren_.clear();
427 }
428 return children_;
429 }
430
UpdateChildrenFreezeState(bool isFreeze)431 void LazyForEachNode::UpdateChildrenFreezeState(bool isFreeze)
432 {
433 if (!builder_) {
434 return;
435 }
436 std::vector<UINode*> children;
437 builder_->GetAllItems(children);
438 for (const auto& child : children) {
439 if (child) {
440 child->SetFreeze(isFreeze);
441 }
442 }
443 }
444
LoadChildren(bool notDetach) const445 void LazyForEachNode::LoadChildren(bool notDetach) const
446 {
447 std::list<std::pair<std::string, RefPtr<UINode>>> childList;
448 const auto& items = builder_->GetItems(childList);
449
450 if (!notDetach) {
451 for (auto& node : childList) {
452 if (!node.second->OnRemoveFromParent(true)) {
453 const_cast<LazyForEachNode*>(this)->AddDisappearingChild(node.second);
454 } else {
455 node.second->DetachFromMainTree();
456 }
457 }
458 }
459
460 for (const auto& [index, item] : items) {
461 if (item.second) {
462 const_cast<LazyForEachNode*>(this)->RemoveDisappearingChild(item.second);
463 children_.push_back(item.second);
464 }
465 }
466 }
467
OnConfigurationUpdate(const ConfigurationChange & configurationChange)468 void LazyForEachNode::OnConfigurationUpdate(const ConfigurationChange& configurationChange)
469 {
470 if (configurationChange.IsNeedUpdate() && builder_) {
471 auto map = builder_->GetCachedUINodeMap();
472 for (auto& it : map) {
473 auto node = DynamicCast<UINode>(it.second.second);
474 if (node) {
475 node->UpdateConfigurationUpdate(configurationChange);
476 }
477 }
478 }
479 }
480
SetOnMove(std::function<void (int32_t,int32_t)> && onMove)481 void LazyForEachNode::SetOnMove(std::function<void(int32_t, int32_t)>&& onMove)
482 {
483 if (onMove && !onMoveEvent_) {
484 InitAllChilrenDragManager(true);
485 } else if (!onMove && onMoveEvent_) {
486 InitAllChilrenDragManager(false);
487 }
488 onMoveEvent_ = onMove;
489 }
490
MoveData(int32_t from,int32_t to)491 void LazyForEachNode::MoveData(int32_t from, int32_t to)
492 {
493 if (builder_) {
494 builder_->OnDataMoveToNewPlace(from, to);
495 builder_->UpdateMoveFromTo(from, to);
496 }
497 tempChildren_.clear();
498 tempChildren_.swap(children_);
499 MarkNeedSyncRenderTree(true);
500 MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
501 }
502
FireOnMove(int32_t from,int32_t to)503 void LazyForEachNode::FireOnMove(int32_t from, int32_t to)
504 {
505 if (builder_) {
506 builder_->ResetMoveFromTo();
507 }
508 ForEachBaseNode::FireOnMove(from, to);
509 }
510
GetFrameNode(int32_t index)511 RefPtr<FrameNode> LazyForEachNode::GetFrameNode(int32_t index)
512 {
513 CHECK_NULL_RETURN(builder_, nullptr);
514 auto child = builder_->GetChildByIndex(index, false, false);
515 CHECK_NULL_RETURN(child.second, nullptr);
516 return AceType::DynamicCast<FrameNode>(child.second->GetFrameChildByIndex(0, true));
517 }
518
GetFrameNodeIndex(const RefPtr<FrameNode> & node,bool isExpanded)519 int32_t LazyForEachNode::GetFrameNodeIndex(const RefPtr<FrameNode>& node, bool isExpanded)
520 {
521 if (!isExpanded) {
522 return UINode::GetFrameNodeIndex(node, false);
523 }
524 CHECK_NULL_RETURN(builder_, -1);
525 return builder_->GetChildIndex(node);
526 }
527
InitDragManager(const RefPtr<FrameNode> & childNode)528 void LazyForEachNode::InitDragManager(const RefPtr<FrameNode>& childNode)
529 {
530 CHECK_NULL_VOID(childNode);
531 auto parentNode = GetParentFrameNode();
532 CHECK_NULL_VOID(parentNode);
533 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
534 return;
535 }
536 auto pattern = childNode->GetPattern<ListItemPattern>();
537 CHECK_NULL_VOID(pattern);
538 pattern->InitDragManager(AceType::Claim(this));
539 }
540
InitAllChilrenDragManager(bool init)541 void LazyForEachNode::InitAllChilrenDragManager(bool init)
542 {
543 auto parentNode = GetParentFrameNode();
544 CHECK_NULL_VOID(parentNode);
545 if (parentNode->GetTag() != V2::LIST_ETS_TAG) {
546 return;
547 }
548 const auto& children = GetChildren();
549 for (const auto& child : children) {
550 if (!child) {
551 continue;
552 }
553 auto childNode = child->GetFrameChildByIndex(0, false);
554 auto listItem = AceType::DynamicCast<FrameNode>(childNode);
555 if (!listItem) {
556 continue;
557 }
558
559 auto pattern = listItem->GetPattern<ListItemPattern>();
560 if (!pattern) {
561 continue;
562 }
563 if (init) {
564 pattern->InitDragManager(AceType::Claim(this));
565 } else {
566 pattern->DeInitDragManager();
567 }
568 }
569 }
570
NotifyChangeWithCount(int32_t index,int32_t count,NotificationType notificationType) const571 void LazyForEachNode::NotifyChangeWithCount(int32_t index, int32_t count, NotificationType notificationType) const
572 {
573 auto parent = GetParent();
574 int64_t accessibilityId = GetAccessibilityId();
575 if (parent) {
576 parent->NotifyChange(index, count, accessibilityId, notificationType);
577 }
578 }
579
ParseOperations(const std::list<V2::Operation> & dataOperations)580 void LazyForEachNode::ParseOperations(const std::list<V2::Operation>& dataOperations)
581 {
582 std::map<std::string, int32_t> operationTypeMap = { { "add", 1 }, { "delete", 2 }, { "change", 3 }, { "move", 4 },
583 { "exchange", 5 }, { "reload", 6 } };
584 constexpr int ADDOP = 1;
585 constexpr int DELETEOP = 2;
586 constexpr int CHANGEOP = 3;
587 constexpr int MOVEOP = 4;
588 constexpr int EXCHANGEOP = 5;
589 constexpr int RELOADOP = 6;
590 for (const auto& operation : dataOperations) {
591 switch (operationTypeMap[operation.type]) {
592 case ADDOP:
593 NotifyChangeWithCount(operation.index, operation.count, NotificationType::END_CHANGE_POSITION);
594 break;
595 case DELETEOP:
596 NotifyChangeWithCount(operation.index, -operation.count, NotificationType::END_CHANGE_POSITION);
597 break;
598 case CHANGEOP:
599 NotifyChangeWithCount(operation.index + operation.count - 1, 0, NotificationType::END_CHANGE_POSITION);
600 break;
601 case MOVEOP:
602 NotifyChangeWithCount(std::max(operation.coupleIndex.first, operation.coupleIndex.second), 0,
603 NotificationType::END_CHANGE_POSITION);
604 break;
605 case EXCHANGEOP:
606 NotifyChangeWithCount(operation.coupleIndex.second, 0, NotificationType::END_CHANGE_POSITION);
607 break;
608 case RELOADOP:
609 NotifyChangeWithCount(static_cast<int32_t>(FrameCount()), 0, NotificationType::END_CHANGE_POSITION);
610 break;
611 }
612 }
613 }
614 } // namespace OHOS::Ace::NG
615