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