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