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