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