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