• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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/dialog_tween/render_dialog_tween.h"
17 
18 #include "base/log/event_report.h"
19 #include "core/components/dialog/dialog_theme.h"
20 #include "core/components/stack/stack_element.h"
21 #include "core/event/ace_event_helper.h"
22 
23 namespace OHOS::Ace {
24 namespace {
25 
26 // Using UX spec: Constrain max height within 4/5 of screen height.
27 constexpr double DIALOG_HEIGHT_RATIO = 0.8;
28 constexpr double DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE = 0.9;
29 constexpr double DIALOG_HEIGHT_RATIO_FOR_CAR = 0.95;
30 constexpr double DIALOG_DRAG_RATIO = 0.5;
31 constexpr int32_t POSITIVE_SUCCESS_ID = 0;
32 constexpr int32_t NEGATIVE_SUCCESS_ID = 1;
33 constexpr int32_t NEUTRAL_SUCCESS_ID = 2;
34 
35 } // namespace
36 
RenderDialogTween()37 RenderDialogTween::RenderDialogTween()
38 {
39     clickDetector_ = AceType::MakeRefPtr<ClickRecognizer>();
40     clickDetector_->SetOnClick([weak = WeakClaim(this)](const ClickInfo& info) {
41         auto dialog = weak.Upgrade();
42         if (dialog) {
43             dialog->HandleClick(info.GetLocalLocation());
44         }
45     });
46     dragDetector_ = AceType::MakeRefPtr<DragRecognizer>(Axis::FREE);
47     dragDetector_->SetOnDragStart([weak = WeakClaim(this)](const DragStartInfo& startInfo) {
48         auto dialog = weak.Upgrade();
49         if (dialog) {
50             dialog->dragStart_ = startInfo.GetLocalLocation().GetX();
51             dialog->dragY_ = startInfo.GetLocalLocation().GetY();
52             dialog->dragX_ = startInfo.GetLocalLocation().GetX();
53             dialog->lastPositionX_ = startInfo.GetLocalLocation().GetX();
54             dialog->lastPositionY_ = startInfo.GetLocalLocation().GetY();
55             dialog->init_ = false;
56             if (dialog->maskDragRegion_.ContainsInRegion(dialog->dragX_, dialog->dragY_)) {
57                 dialog->isDragging_ = true;
58             } else {
59                 dialog->isDragging_ = false;
60             }
61         }
62     });
63     dragDetector_->SetOnDragEnd([weak = WeakClaim(this)](const DragEndInfo& endInfo) {
64         auto dialog = weak.Upgrade();
65         if (dialog) {
66             double dragEnd = endInfo.GetLocalLocation().GetX();
67             if (!dialog->isDragging_ &&
68                 GreatOrEqual(dragEnd - dialog->dragStart_, dialog->GetLayoutSize().Width() * DIALOG_DRAG_RATIO)) {
69                 dialog->PopDialog();
70             }
71             dialog->lastPositionX_ = endInfo.GetLocalLocation().GetX();
72             dialog->lastPositionY_ = endInfo.GetLocalLocation().GetY();
73         }
74     });
75     dragDetector_->SetOnDragUpdate([weak = WeakClaim(this)](const DragUpdateInfo& info) {
76         auto dialog = weak.Upgrade();
77         if (dialog) {
78             if (dialog->isDragable_ && dialog->isDragging_) {
79                 dialog->HandleDragUpdate(info.GetLocalLocation());
80             }
81         }
82     });
83     init_ = true;
84 }
85 
~RenderDialogTween()86 RenderDialogTween::~RenderDialogTween()
87 {
88     if (!popDialog_ && onStatusChanged_) {
89         onStatusChanged_(false);
90         popDialog_ = true;
91     }
92     auto dialogTweenComponent = weakDialogTweenComponent_.Upgrade();
93     if (dialogTweenComponent) {
94         RemoveBackendEvent(dialogTweenComponent);
95     }
96 
97     auto accessibilityNode = accessibilityNode_.Upgrade();
98     if (accessibilityNode) {
99         accessibilityNode->ClearRect();
100     }
101 }
102 
Create()103 RefPtr<RenderNode> RenderDialogTween::Create()
104 {
105     return AceType::MakeRefPtr<RenderDialogTween>();
106 }
107 
Update(const RefPtr<Component> & component)108 void RenderDialogTween::Update(const RefPtr<Component>& component)
109 {
110     const RefPtr<DialogTweenComponent> dialog = AceType::DynamicCast<DialogTweenComponent>(component);
111     if (!dialog) {
112         LOGE("RenderDialogTween update with nullptr");
113         EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
114         return;
115     }
116     weakDialogTweenComponent_ = dialog;
117     autoCancel_ = dialog->GetAutoCancel();
118     onSuccess_ = AceAsyncEvent<void(int32_t)>::Create(dialog->GetOnSuccessId(), context_);
119     onCancel_ = AceAsyncEvent<void()>::Create(dialog->GetOnCancelId(), context_);
120     onComplete_ = AceAsyncEvent<void()>::Create(dialog->GetOnCompleteId(), context_);
121     onStatusChanged_ = dialog->GetOnStatusChanged();
122     animator_ = dialog->GetParentAnimator();
123     composedId_ = dialog->GetComposedId();
124     dialogId_ = dialog->GetDialogId();
125     customDialogId_ = dialog->GetCustomDialogId();
126     data_ = dialog->GetData();
127     isLimit_ = dialog->GetDialogLimit();
128     isSetMargin_ = dialog->IsSetMargin();
129     isDragable_ = dialog->IsDragable();
130     if (isSetMargin_) {
131         margin_ = dialog->GetMargin();
132     }
133     alignment_ = dialog->GetAlignment();
134     offset_ = dialog->GetOffset();
135     gridCount_ = dialog->GetGridCount();
136 
137     if (dialog->IsMenu()) {
138         auto menuSuccessId = dialog->GetMenuSuccessId();
139         for (size_t index = 0; index < menuSuccessId.size(); ++index) {
140             const auto context = GetContext().Upgrade();
141             if (context && context->GetIsDeclarative()) {
142                 BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
143                     menuSuccessId[index], [weak = WeakClaim(this), index](const ClickInfo& info) {
144                         auto dialog = weak.Upgrade();
145                         dialog->CallOnSuccess(index);
146                     });
147             } else {
148                 BackEndEventManager<void()>::GetInstance().BindBackendEvent(
149                     menuSuccessId[index], [weak = WeakClaim(this), index]() {
150                         auto dialog = weak.Upgrade();
151                         dialog->CallOnSuccess(index);
152                     });
153             }
154         }
155     }
156     BindButtonEvent(dialog);
157     MarkNeedLayout();
158 }
159 
BindButtonEvent(const RefPtr<DialogTweenComponent> & dialog)160 void RenderDialogTween::BindButtonEvent(const RefPtr<DialogTweenComponent>& dialog)
161 {
162     auto context = context_.Upgrade();
163     if (context && context->GetIsDeclarative()) {
164         BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
165             dialog->GetOnPositiveSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
166                 auto dialog = weak.Upgrade();
167                 dialog->CallOnSuccess(POSITIVE_SUCCESS_ID);
168             });
169 
170         BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
171             dialog->GetOnNegativeSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
172                 auto dialog = weak.Upgrade();
173                 dialog->CallOnSuccess(NEGATIVE_SUCCESS_ID);
174             });
175 
176         BackEndEventManager<void(const ClickInfo&)>::GetInstance().BindBackendEvent(
177             dialog->GetOnNeutralSuccessId(), [weak = WeakClaim(this)](const ClickInfo& info) {
178                 auto dialog = weak.Upgrade();
179                 dialog->CallOnSuccess(NEUTRAL_SUCCESS_ID);
180             });
181         return;
182     }
183 
184     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
185         dialog->GetOnPositiveSuccessId(), [weak = WeakClaim(this)]() {
186             auto dialog = weak.Upgrade();
187             dialog->CallOnSuccess(POSITIVE_SUCCESS_ID);
188         });
189 
190     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
191         dialog->GetOnNegativeSuccessId(), [weak = WeakClaim(this)]() {
192             auto dialog = weak.Upgrade();
193             dialog->CallOnSuccess(NEGATIVE_SUCCESS_ID);
194         });
195 
196     BackEndEventManager<void()>::GetInstance().BindBackendEvent(
197         dialog->GetOnNeutralSuccessId(), [weak = WeakClaim(this)]() {
198             auto dialog = weak.Upgrade();
199             dialog->CallOnSuccess(NEUTRAL_SUCCESS_ID);
200         });
201 }
202 
HandleDragUpdate(const Offset & currentPoint)203 void RenderDialogTween::HandleDragUpdate(const Offset& currentPoint)
204 {
205     dragX_ = currentPoint.GetX();
206     dragY_ = currentPoint.GetY();
207     MarkNeedLayout();
208 }
209 
CallOnSuccess(int32_t successType)210 void RenderDialogTween::CallOnSuccess(int32_t successType)
211 {
212     if (onStatusChanged_) {
213         popDialog_ = true;
214     }
215     const auto context = context_.Upgrade();
216     if (!context) {
217         LOGE("the context is null");
218         return;
219     }
220     const auto& lastStack = context->GetLastStack();
221     if (!lastStack) {
222         LOGE("the lastStack is null");
223         return;
224     }
225     if (animator_) {
226         animator_->AddStopListener([successType, lastStack, weak = WeakClaim(this), dialogId = dialogId_] {
227             auto dialog = weak.Upgrade();
228             if (!dialog) {
229                 return;
230             }
231             lastStack->PopDialog(dialogId);
232             if (dialog->onSuccess_) {
233                 dialog->onSuccess_(successType);
234             }
235             if (dialog->onComplete_) {
236                 dialog->onComplete_();
237             }
238             if (dialog->onStatusChanged_) {
239                 dialog->onStatusChanged_(false);
240             }
241         });
242         animator_->Play();
243     } else {
244         lastStack->PopDialog(dialogId_);
245         if (onSuccess_) {
246             onSuccess_(successType);
247         }
248         if (onComplete_) {
249             onComplete_();
250         }
251         if (onStatusChanged_) {
252             onStatusChanged_(false);
253         }
254     }
255     RemoveAccessibilityNode();
256 }
257 
GetMaxWidthBasedOnGridType(const RefPtr<GridColumnInfo> & info,GridSizeType type,DeviceType deviceType)258 double RenderDialogTween::GetMaxWidthBasedOnGridType(
259     const RefPtr<GridColumnInfo>& info, GridSizeType type, DeviceType deviceType)
260 {
261     if (gridCount_ > 0) {
262         return info->GetWidth(std::min(gridCount_, info->GetParent()->GetColumns()));
263     }
264 
265     if (deviceType == DeviceType::WATCH || deviceType == DeviceType::WEARABLE) {
266         if (type == GridSizeType::SM) {
267             return info->GetWidth(3);
268         } else if (type == GridSizeType::MD) {
269             return info->GetWidth(4);
270         } else if (type == GridSizeType::LG) {
271             return info->GetWidth(5);
272         } else {
273             LOGI("GetMaxWidthBasedOnGridType is undefined");
274             return info->GetWidth(5);
275         }
276     } else if (deviceType == DeviceType::PHONE) {
277         if (type == GridSizeType::SM) {
278             return info->GetWidth(4);
279         } else if (type == GridSizeType::MD) {
280             return info->GetWidth(5);
281         } else if (type == GridSizeType::LG) {
282             return info->GetWidth(6);
283         } else {
284             LOGI("GetMaxWidthBasedOnGridType is undefined");
285             return info->GetWidth(6);
286         }
287     } else if (deviceType == DeviceType::CAR) {
288         if (type == GridSizeType::SM) {
289             return info->GetWidth(4);
290         } else if (type == GridSizeType::MD) {
291             return info->GetWidth(6);
292         } else if (type == GridSizeType::LG) {
293             return info->GetWidth(8);
294         } else {
295             LOGI("GetMaxWidthBasedOnGridType is undefined");
296             return info->GetWidth(8);
297         }
298     } else {
299         if (type == GridSizeType::SM) {
300             return info->GetWidth(2);
301         } else if (type == GridSizeType::MD) {
302             return info->GetWidth(3);
303         } else if (type == GridSizeType::LG) {
304             return info->GetWidth(4);
305         } else {
306             LOGI("GetMaxWidthBasedOnGridType is undefined");
307             return info->GetWidth(4);
308         }
309     }
310 }
311 
PerformLayout()312 void RenderDialogTween::PerformLayout()
313 {
314     LayoutParam innerLayout = GetLayoutParam();
315     auto maxSize = innerLayout.GetMaxSize();
316     // If max size is INFINITE, use viewport of parent.
317     if (maxSize == Size(std::numeric_limits<double>::max(), std::numeric_limits<double>::max())) {
318         auto parent = GetParent().Upgrade();
319         if (parent) {
320             maxSize = parent->GetChildViewPort();
321         }
322     }
323     innerLayout.SetMaxSize(maxSize);
324     ComputeInnerLayoutParam(innerLayout);
325     if (GetChildren().empty()) {
326         SetLayoutSize(maxSize);
327         return;
328     }
329     const auto& child = GetChildren().front();
330     child->Layout(innerLayout);
331     auto childSize = child->GetLayoutSize();
332     topLeftPoint_ = ComputeChildPosition(childSize);
333     child->SetPosition(topLeftPoint_);
334     UpdateTouchRegion(topLeftPoint_, maxSize, childSize);
335     SetLayoutSize(maxSize);
336     lastPositionX_ = dragX_;
337     lastPositionY_ = dragY_;
338 }
339 
ComputeInnerLayoutParam(LayoutParam & innerLayout)340 void RenderDialogTween::ComputeInnerLayoutParam(LayoutParam& innerLayout)
341 {
342     auto maxSize = innerLayout.GetMaxSize();
343     // Set different layout param for different devices
344     auto gridSizeType = ScreenSystemManager::GetInstance().GetSize(maxSize.Width());
345     RefPtr<GridColumnInfo> columnInfo;
346     auto deviceType = SystemProperties::GetDeviceType();
347     if (deviceType == DeviceType::CAR) {
348         columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::CAR_DIALOG);
349     } else {
350         columnInfo = GridSystemManager::GetInstance().GetInfoByType(GridColumnType::DIALOG);
351     }
352     columnInfo->GetParent()->BuildColumnWidth(maxSize.Width());
353     auto width = GetMaxWidthBasedOnGridType(columnInfo, gridSizeType, deviceType);
354     if (!isLimit_) {
355         innerLayout.SetMinSize(Size(0.0, 0.0));
356         innerLayout.SetMaxSize(Size(maxSize.Width(), maxSize.Height()));
357     } else if (deviceType == DeviceType::WATCH || deviceType == DeviceType::WEARABLE) {
358         innerLayout.SetMinSize(Size(width, 0.0));
359         innerLayout.SetMaxSize(Size(width, maxSize.Height()));
360     } else if (deviceType == DeviceType::PHONE) {
361         if (SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
362             innerLayout.SetMinSize(Size(width, 0.0));
363             innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_LANDSCAPE));
364         } else {
365             innerLayout.SetMinSize(Size(width, 0.0));
366             innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO));
367         }
368     } else if (deviceType == DeviceType::CAR) {
369         innerLayout.SetMinSize(Size(width, 0.0));
370         innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO_FOR_CAR));
371     } else {
372         innerLayout.SetMinSize(Size(width, 0.0));
373         innerLayout.SetMaxSize(Size(width, maxSize.Height() * DIALOG_HEIGHT_RATIO));
374     }
375 }
376 
ComputeChildPosition(const Size & childSize) const377 Offset RenderDialogTween::ComputeChildPosition(const Size& childSize) const
378 {
379     Offset topLeftPoint;
380     auto context = context_.Upgrade();
381     auto theme = GetTheme<DialogTheme>();
382     if (!theme || !context) {
383         return topLeftPoint;
384     }
385 
386     auto maxSize = GetLayoutParam().GetMaxSize();
387     // If max size is INFINITE, use viewport of parent.
388     if (maxSize == Size(std::numeric_limits<double>::max(), std::numeric_limits<double>::max())) {
389         auto parent = GetParent().Upgrade();
390         if (parent) {
391             maxSize = parent->GetChildViewPort();
392         }
393     }
394     if (isDragging_) {
395         topLeftPoint =
396             Offset(topLeftPoint_.GetX() + (dragX_ - lastPositionX_), topLeftPoint_.GetY() + (dragY_ - lastPositionY_));
397         return topLeftPoint;
398     }
399 
400     Offset dialogOffset =
401         Offset(NormalizePercentToPx(offset_.GetX(), false, true), NormalizePercentToPx(offset_.GetY(), true, true));
402     if (offset_.GetX().Unit() == DimensionUnit::PERCENT) {
403         dialogOffset.SetX(offset_.GetX().Value() * childSize.Width());
404     } else {
405         dialogOffset.SetX(NormalizeToPx(offset_.GetX()));
406     }
407     if (offset_.GetY().Unit() == DimensionUnit::PERCENT) {
408         dialogOffset.SetY(offset_.GetY().Value() * childSize.Height());
409     } else {
410         dialogOffset.SetY(NormalizeToPx(offset_.GetY()));
411     }
412     if (init_) {
413         if (SetAlignmentSwitch(maxSize, childSize, topLeftPoint)) {
414             return topLeftPoint + dialogOffset;
415         }
416 
417         if (context->GetIsDeclarative()) {
418             topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
419             return topLeftPoint + dialogOffset;
420         }
421 
422         // Set different positions for different devices
423         if (SystemProperties::GetDeviceType() == DeviceType::PHONE &&
424             SystemProperties::GetDeviceOrientation() == DeviceOrientation::PORTRAIT) {
425             topLeftPoint = Offset((maxSize.Width() - childSize.Width()) / 2.0,
426                 maxSize.Height() - childSize.Height() - (isSetMargin_ ? 0.0 : NormalizeToPx(theme->GetMarginBottom())));
427         } else {
428             topLeftPoint =
429                 Offset((maxSize.Width() - childSize.Width()) / 2.0, (maxSize.Height() - childSize.Height()) / 2.0);
430         }
431     }
432     return topLeftPoint + dialogOffset;
433 }
434 
SetAlignmentSwitch(const Size & maxSize,const Size & childSize,Offset & topLeftPoint) const435 bool RenderDialogTween::SetAlignmentSwitch(const Size& maxSize, const Size& childSize, Offset& topLeftPoint) const
436 {
437     // If alignment is setted, compute position with alignment and offset.
438     if (alignment_ != DialogAlignment::DEFAULT) {
439         switch (alignment_) {
440             case DialogAlignment::TOP:
441                 topLeftPoint = Offset((maxSize.Width() - childSize.Width()) / 2.0, 0.0);
442                 break;
443             case DialogAlignment::CENTER:
444                 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
445                 break;
446             case DialogAlignment::BOTTOM:
447                 topLeftPoint =
448                     Offset((maxSize.Width() - childSize.Width()) / 2.0, maxSize.Height() - childSize.Height());
449                 break;
450             case DialogAlignment::TOP_START:
451                 topLeftPoint = Offset(0.0, 0.0);
452                 break;
453             case DialogAlignment::TOP_END:
454                 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), 0.0);
455                 break;
456             case DialogAlignment::CENTER_START:
457                 topLeftPoint = Offset(0.0, maxSize.Height() - childSize.Height()) / 2.0;
458                 break;
459             case DialogAlignment::CENTER_END:
460                 topLeftPoint =
461                     Offset(maxSize.Width() - childSize.Width(), (maxSize.Height() - childSize.Height()) / 2.0);
462                 break;
463             case DialogAlignment::BOTTOM_START:
464                 topLeftPoint = Offset(0.0, maxSize.Height() - childSize.Height());
465                 break;
466             case DialogAlignment::BOTTOM_END:
467                 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height());
468                 break;
469             default:
470                 topLeftPoint = Offset(maxSize.Width() - childSize.Width(), maxSize.Height() - childSize.Height()) / 2.0;
471                 break;
472         }
473         return true;
474     }
475     return false;
476 }
477 
UpdateTouchRegion(const Offset & topLeftPoint,const Size & maxSize,const Size & childSize)478 void RenderDialogTween::UpdateTouchRegion(const Offset& topLeftPoint, const Size& maxSize, const Size& childSize)
479 {
480     double left = margin_.Left().Unit() == DimensionUnit::PERCENT ? margin_.Left().Value() * maxSize.Width()
481                                                                   : NormalizeToPx(margin_.Left());
482     double top = margin_.Top().Unit() == DimensionUnit::PERCENT ? margin_.Top().Value() * maxSize.Height()
483                                                                 : NormalizeToPx(margin_.Top());
484     Offset touchTopLeft = topLeftPoint + (isSetMargin_ ? Offset(left, top) : Offset(0.0, 0.0));
485 
486     double right = margin_.Right().Unit() == DimensionUnit::PERCENT ? margin_.Right().Value() * maxSize.Width()
487                                                                     : NormalizeToPx(margin_.Right());
488     double bottom = margin_.Bottom().Unit() == DimensionUnit::PERCENT ? margin_.Bottom().Value() * maxSize.Height()
489                                                                       : NormalizeToPx(margin_.Bottom());
490     Offset touchBottomRight = topLeftPoint + childSize - (isSetMargin_ ? Offset(right, bottom) : Offset(0.0, 0.0));
491 
492     Offset dragBottomRight = touchBottomRight;
493     dragBottomRight.SetY(touchTopLeft.GetY() + DRAG_BAR_HEIGHT);
494 
495     maskTouchRegion_ = TouchRegion(touchTopLeft, touchBottomRight);
496     maskDragRegion_ = TouchRegion(touchTopLeft, dragBottomRight);
497 }
498 
OnPaintFinish()499 void RenderDialogTween::OnPaintFinish()
500 {
501     InitAccessibilityEventListener();
502     if (onStatusChanged_) {
503         onStatusChanged_(true);
504     }
505 }
506 
HandleClick(const Offset & clickPosition)507 void RenderDialogTween::HandleClick(const Offset& clickPosition)
508 {
509     if (autoCancel_ && !maskTouchRegion_.ContainsInRegion(clickPosition.GetX(), clickPosition.GetY())) {
510         PopDialog();
511     }
512 }
513 
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)514 void RenderDialogTween::OnTouchTestHit(
515     const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
516 {
517     clickDetector_->SetCoordinateOffset(coordinateOffset);
518     result.emplace_back(clickDetector_);
519     if (isDragable_) {
520         dragDetector_->SetCoordinateOffset(coordinateOffset);
521         result.emplace_back(dragDetector_);
522     }
523 }
524 
PopDialog()525 bool RenderDialogTween::PopDialog()
526 {
527     if (onStatusChanged_) {
528         popDialog_ = true;
529     }
530     const auto context = context_.Upgrade();
531     if (!context) {
532         LOGE("the context is null");
533         return false;
534     }
535     const auto& lastStack = context->GetLastStack();
536     if (!lastStack) {
537         LOGE("the lastStack is null");
538         return false;
539     }
540     if (animator_) {
541         animator_->AddStopListener([lastStack, weak = AceType::WeakClaim(this), dialogId = dialogId_] {
542             auto dialog = weak.Upgrade();
543             if (!dialog) {
544                 return;
545             }
546             lastStack->PopDialog(dialogId);
547             if (dialog->onCancel_) {
548                 dialog->onCancel_();
549             }
550             if (dialog->onComplete_) {
551                 dialog->onComplete_();
552             }
553             if (dialog->onStatusChanged_) {
554                 dialog->onStatusChanged_(false);
555             }
556         });
557         animator_->Play();
558     } else {
559         lastStack->PopDialog(dialogId_);
560         if (onCancel_) {
561             onCancel_();
562         }
563         if (onComplete_) {
564             onComplete_();
565         }
566         if (onStatusChanged_) {
567             onStatusChanged_(false);
568         }
569     }
570     RemoveAccessibilityNode();
571     return true;
572 }
573 
SetAnimator(const RefPtr<Animator> & animator)574 void RenderDialogTween::SetAnimator(const RefPtr<Animator>& animator)
575 {
576     animator_ = animator;
577 }
578 
InitAccessibilityEventListener()579 void RenderDialogTween::InitAccessibilityEventListener()
580 {
581     const auto& accessibilityNode = GetAccessibilityNode().Upgrade();
582     if (!accessibilityNode) {
583         return;
584     }
585     accessibilityNode->SetFocusableState(true);
586     accessibilityNode->SetText(data_);
587 
588     accessibilityNode->AddSupportAction(AceAction::CUSTOM_ACTION);
589     accessibilityNode->AddSupportAction(AceAction::ACTION_CLICK);
590     accessibilityNode->AddSupportAction(AceAction::ACTION_FOCUS);
591     accessibilityNode->AddSupportAction(AceAction::ACTION_LONG_CLICK);
592     accessibilityNode->AddSupportAction(AceAction::GLOBAL_ACTION_BACK);
593     accessibilityNode->SetLongClickableState(true);
594 
595     accessibilityNode->SetActionLongClickImpl([weakPtr = WeakClaim(this)]() {
596         const auto& dialogTween = weakPtr.Upgrade();
597         if (dialogTween) {
598             dialogTween->PopDialog();
599         }
600     });
601 
602     // RenderDialogTween's size is 0*0, use parent's rect,
603     // or no child on dialog can get focused by click in accessibility mode
604     auto parent = accessibilityNode->GetParentNode();
605     if (parent) {
606         accessibilityNode->SetRect(parent->GetRect());
607     }
608 }
609 
RemoveAccessibilityNode()610 void RenderDialogTween::RemoveAccessibilityNode()
611 {
612     auto context = context_.Upgrade();
613     if (!context) {
614         return;
615     }
616 
617     const auto& accessibilityManager = context->GetAccessibilityManager();
618     if (accessibilityManager) {
619         // no new accessibility node is created with DialogTween in JS app
620         if (context->GetIsDeclarative()) {
621             accessibilityManager->RemoveAccessibilityNodeById(composedId_);
622         }
623 #if defined(PREVIEW)
624         auto node = accessibilityManager->GetAccessibilityNodeById(customDialogId_);
625         accessibilityManager->ClearNodeRectInfo(node, true);
626 #endif
627     }
628 }
629 
RemoveBackendEvent(const RefPtr<DialogTweenComponent> & component)630 void RenderDialogTween::RemoveBackendEvent(const RefPtr<DialogTweenComponent>& component)
631 {
632     auto context = context_.Upgrade();
633     if (context && context->GetIsDeclarative()) {
634         BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
635             component->GetOnPositiveSuccessId());
636         BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
637             component->GetOnNegativeSuccessId());
638         BackEndEventManager<void(const ClickInfo&)>::GetInstance().RemoveBackEndEvent(
639             component->GetOnNeutralSuccessId());
640     } else {
641         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnPositiveSuccessId());
642         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnNegativeSuccessId());
643         BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnNeutralSuccessId());
644     }
645     BackEndEventManager<void(int32_t)>::GetInstance().RemoveBackEndEvent(component->GetOnSuccessId());
646     BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnCancelId());
647     BackEndEventManager<void()>::GetInstance().RemoveBackEndEvent(component->GetOnCompleteId());
648 }
649 
HandleMouseEvent(const MouseEvent & event)650 bool RenderDialogTween::HandleMouseEvent(const MouseEvent& event)
651 {
652     if (event.button != MouseButton::NONE_BUTTON && event.button != MouseButton::LEFT_BUTTON &&
653         event.action == MouseAction::PRESS) {
654         HandleClick({ event.x, event.y });
655     }
656     return true;
657 }
658 
659 } // namespace OHOS::Ace
660