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/dialog_component.h"
17
18 #include <atomic>
19
20 #include "base/geometry/dimension.h"
21 #include "base/i18n/localization.h"
22 #include "base/log/log.h"
23 #include "base/resource/internal_resource.h"
24 #include "base/utils/system_properties.h"
25 #include "core/animation/curve_animation.h"
26 #include "core/animation/curves.h"
27 #include "core/animation/keyframe.h"
28 #include "core/animation/keyframe_animation.h"
29 #include "core/components/box/box_component.h"
30 #include "core/components/button/button_theme.h"
31 #include "core/components/common/layout/constants.h"
32 #include "core/components/common/properties/color.h"
33 #include "core/components/common/properties/decoration.h"
34 #include "core/components/dialog/action_sheet/action_sheet_component.h"
35 #include "core/components/dialog/alert_dialog_component.h"
36 #include "core/components/dialog/dialog_element.h"
37 #include "core/components/dialog/render_dialog.h"
38 #include "core/components/drag_bar/drag_bar_component.h"
39 #include "core/components/focus_collaboration/focus_collaboration_component.h"
40 #include "core/components/focusable/focusable_component.h"
41 #include "core/components/image/image_component.h"
42 #include "core/components/scroll/scroll_component.h"
43 #include "core/components/theme/theme_manager.h"
44 #include "core/components/wrap/wrap_component.h"
45 #include "core/components_v2/inspector/inspector_composed_component.h"
46 #include "core/components_v2/inspector/inspector_constants.h"
47 #include "core/pipeline/pipeline_context.h"
48
49 namespace OHOS::Ace {
50 namespace {
51
52 constexpr double PHONE_ENTER_CURVE_X0 = 0.38;
53 constexpr double PHONE_ENTER_CURVE_Y0 = 1.33;
54 constexpr double PHONE_ENTER_CURVE_X1 = 0.60;
55 constexpr double PHONE_ENTER_CURVE_Y1 = 1.0;
56 constexpr double PHONE_OPACITY_MIDDLE_IN = 0.375;
57 constexpr Dimension CAR_TITLE_MIN_HEIGHT = 64.0_vp;
58 constexpr int32_t PLATFORM_VERSION_EIGHT = 8;
59
60 } // namespace
61
62 static std::atomic<int32_t> g_dialogId(0);
63
64 const char CALLBACK_SUCCESS[] = "success";
65 const char CALLBACK_CANCEL[] = "cancel";
66 const char CALLBACK_COMPLETE[] = "complete";
67 const char DIALOG_TWEEN_NAME[] = "tween";
68 const int32_t DIALOG_BUTTONS_COUNT_WATCH = 2;
69 const char DIALOG_OK[] = "common.ok";
70 const char DIALOG_CANCEL[] = "common.cancel";
71 const char SEPARATE[] = " ";
72
DialogComponent()73 DialogComponent::DialogComponent()
74 {
75 dialogId_ = GenerateDialogId();
76 }
77
CreateElement()78 RefPtr<Element> DialogComponent::CreateElement()
79 {
80 return AceType::MakeRefPtr<DialogElement>();
81 }
82
CreateRenderNode()83 RefPtr<RenderNode> DialogComponent::CreateRenderNode()
84 {
85 return RenderDialog::Create();
86 }
87
GenerateDialogId()88 int32_t DialogComponent::GenerateDialogId()
89 {
90 return g_dialogId.fetch_add(1, std::memory_order_relaxed);
91 }
92
BuildChild(const RefPtr<ThemeManager> & themeManager)93 void DialogComponent::BuildChild(const RefPtr<ThemeManager>& themeManager)
94 {
95 if (!themeManager) {
96 return;
97 }
98 dialogTheme_ = AceType::DynamicCast<DialogTheme>(themeManager->GetTheme(DialogTheme::TypeId()));
99 if (!dialogTheme_) {
100 return;
101 }
102 if (!isDeviceTypeSet_) {
103 deviceType_ = SystemProperties::GetDeviceType();
104 }
105 bool isLimit = true;
106 auto box = BuildBox(isLimit);
107 auto transition = BuildAnimation(box);
108 BuildDialogTween(transition, isLimit, margin_);
109
110 auto focusCollaboration = AceType::MakeRefPtr<FocusCollaborationComponent>();
111 if (!HasCustomChild()) {
112 std::list<RefPtr<Component>> columnChildren;
113 auto column = AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, columnChildren);
114 column->SetMainAxisSize(MainAxisSize::MIN);
115 BuildTitle(column);
116 BuildContent(column);
117 if (isMenu_) {
118 BuildMenu(column);
119 } else {
120 BuildActions(themeManager, column);
121 }
122 BuildFocusChild(column, focusCollaboration);
123 } else {
124 // build custom child
125 BuildFocusChild(customComponent_, focusCollaboration);
126 if (IsDragable()) {
127 BuildDragBar(focusCollaboration);
128 }
129 }
130 if (deviceType_ == DeviceType::WATCH) {
131 auto scroll = AceType::MakeRefPtr<ScrollComponent>(focusCollaboration);
132 box->SetChild(scroll);
133 } else {
134 box->SetChild(focusCollaboration);
135 }
136 box->SetTextDirection(GetTextDirection());
137 }
138
BuildBox(bool & isLimit)139 RefPtr<BoxComponent> DialogComponent::BuildBox(bool& isLimit)
140 {
141 auto box = AceType::MakeRefPtr<BoxComponent>();
142 // If use custom style, don't set default style.
143 if (properties_.customStyle) {
144 isLimit = false;
145 return box;
146 }
147
148 box->NeedMaterial(true);
149 auto backDecoration = AceType::MakeRefPtr<Decoration>();
150 backDecoration->SetBackgroundColor(backgroundColor_);
151 Border border;
152 border.SetBorderRadius(dialogTheme_->GetRadius());
153 backDecoration->SetBorder(border);
154
155 if (deviceType_ == DeviceType::WATCH) {
156 box->SetFlex(BoxFlex::FLEX_XY);
157 } else {
158 box->SetFlex(BoxFlex::FLEX_X);
159 }
160 box->SetBackDecoration(backDecoration);
161 if (height_.IsValid()) {
162 box->SetHeight(height_.Value(), height_.Unit());
163 isLimit = false;
164 }
165 if (width_.IsValid()) {
166 box->SetWidth(width_.Value(), width_.Unit());
167 isLimit = false;
168 }
169 if (isSetMargin_) {
170 box->SetMargin(margin_);
171 }
172 return box;
173 }
174
BuildDialogTween(const RefPtr<TransitionComponent> & transition,bool isLimit,Edge margin)175 void DialogComponent::BuildDialogTween(const RefPtr<TransitionComponent>& transition, bool isLimit, Edge margin)
176 {
177 auto dialogTween = AceType::MakeRefPtr<DialogTweenComponent>();
178 auto controller = AceType::MakeRefPtr<Animator>(context_);
179 dialogTween->SetAnimator(controller);
180 if (animator_) {
181 animator_->AddProxyController(controller);
182 }
183 dialogTween->SetParentAnimator(animator_);
184 dialogTween->SetAutoCancel(autoCancel_);
185 dialogTween->SetChild(transition);
186 dialogTween->SetTextDirection(GetTextDirection());
187 dialogTween->SetOnSuccessId(onSuccessId_);
188 dialogTween->SetOnCancelId(onCancelId_);
189 dialogTween->SetOnCompleteId(onCompleteId_);
190 dialogTween->SetOnStatusChanged(properties_.onStatusChanged);
191 dialogTween->SetDialogId(dialogId_);
192 if (isMenu_) {
193 dialogTween->SetIsMenu(true);
194 dialogTween->SetMenuSuccessId(menuSuccessId_);
195 }
196 dialogTween->SetOnPositiveSuccessId(onPositiveSuccessId_);
197 dialogTween->SetOnNegativeSuccessId(onNegativeSuccessId_);
198 dialogTween->SetOnNeutralSuccessId(onNeutralSuccessId_);
199 dialogTween->SetData(data_);
200 dialogTween->SetDialogLimit(isLimit);
201 dialogTween->SetDragable(dragable_);
202 if (isSetMargin_) {
203 dialogTween->SetMargin(margin);
204 }
205 dialogTween->SetAlignment(properties_.alignment);
206 dialogTween->SetOffset(properties_.offset);
207 dialogTween->SetGridCount(properties_.gridCount);
208 if (dialogTweenBox_) {
209 const auto& dialogComposed = GenerateComposed(V2::DIALOG_COMPONENT_TAG, dialogTween, false);
210 dialogTween->SetComposedId(dialogTweenComposedId_);
211 dialogTween->SetCustomDialogId(customDialogId_);
212 dialogTweenBox_->SetChild(dialogComposed);
213 }
214 }
215
BuildFocusChild(const RefPtr<Component> & child,const RefPtr<FocusCollaborationComponent> & collaboration)216 void DialogComponent::BuildFocusChild(
217 const RefPtr<Component>& child, const RefPtr<FocusCollaborationComponent>& collaboration)
218 {
219 if (HasCustomChild()) {
220 // for custom child
221 collaboration->InsertChild(0, child);
222 } else if (actions_.empty()) {
223 auto focusable = AceType::MakeRefPtr<FocusableComponent>(child);
224 focusable->SetFocusable(true);
225 focusable->SetFocusNode(true);
226 collaboration->InsertChild(0, focusable);
227 } else {
228 collaboration->InsertChild(0, child);
229 }
230 }
231
BuildDragBar(const RefPtr<FocusCollaborationComponent> & collaboration)232 void DialogComponent::BuildDragBar(const RefPtr<FocusCollaborationComponent>& collaboration)
233 {
234 auto dragBar = AceType::MakeRefPtr<DragBarComponent>();
235 auto boxForContent = AceType::MakeRefPtr<BoxComponent>();
236 boxForContent->SetFlex(BoxFlex::FLEX_X);
237 auto column =
238 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, std::list<RefPtr<Component>>());
239 column->SetCrossAxisSize(CrossAxisSize::MAX);
240 auto mode = PanelMode::HALF;
241 dragBar->SetPanelMode(mode);
242 dragBar->SetHasDragBar(dragable_);
243 column->AppendChild(dragBar);
244 collaboration->InsertChild(1, column);
245 }
246
BuildTitle(const RefPtr<ColumnComponent> & column)247 void DialogComponent::BuildTitle(const RefPtr<ColumnComponent>& column)
248 {
249 if (!title_) {
250 return;
251 }
252 auto titlePadding = AceType::MakeRefPtr<PaddingComponent>();
253 if (titlePadding_ == Edge::NONE) {
254 titlePadding_ = (!content_ && actions_.empty()) ? dialogTheme_->GetTitleDefaultPadding()
255 : dialogTheme_->GetTitleAdjustPadding();
256 }
257 auto textBox = AceType::MakeRefPtr<BoxComponent>();
258 textBox->SetDeliverMinToChild(false);
259 textBox->SetChild(title_);
260 titlePadding->SetPadding(std::move(titlePadding_));
261 titlePadding->SetChild(textBox);
262 std::list<RefPtr<Component>> rowChildren;
263 RefPtr<RowComponent> row;
264 if (deviceType_ == DeviceType::PHONE) {
265 row = AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, rowChildren);
266 } else {
267 row = AceType::MakeRefPtr<RowComponent>(FlexAlign::CENTER, FlexAlign::CENTER, rowChildren);
268 }
269 auto pipeline = context_.Upgrade();
270 if (pipeline && pipeline->GetMinPlatformVersion() > PLATFORM_VERSION_EIGHT) {
271 row = AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, rowChildren);
272 }
273 row->SetStretchToParent(true);
274 if (SystemProperties::GetDeviceType() == DeviceType::CAR) {
275 auto box = AceType::MakeRefPtr<BoxComponent>();
276 box->SetMinHeight(CAR_TITLE_MIN_HEIGHT);
277 box->SetChild(titlePadding);
278 row->AppendChild(box);
279 } else {
280 row->AppendChild(titlePadding);
281 }
282
283 auto titleFlex = AceType::MakeRefPtr<FlexItemComponent>(0, 0, 0.0, row);
284 column->AppendChild(GenerateComposed(V2::TEXT_COMPONENT_TAG, titleFlex, true));
285 }
286
BuildContent(const RefPtr<ColumnComponent> & column)287 void DialogComponent::BuildContent(const RefPtr<ColumnComponent>& column)
288 {
289 if (!content_) {
290 return;
291 }
292 auto contentPadding = AceType::MakeRefPtr<PaddingComponent>();
293 if (contentPadding_ == Edge::NONE) {
294 if (!title_) {
295 contentPadding_ = actions_.empty() ? dialogTheme_->GetDefaultPadding() : dialogTheme_->GetAdjustPadding();
296 } else {
297 contentPadding_ =
298 actions_.empty() ? dialogTheme_->GetContentDefaultPadding() : dialogTheme_->GetContentAdjustPadding();
299 }
300 }
301 contentPadding->SetPadding(std::move(contentPadding_));
302 RefPtr<FlexItemComponent> contentFlex;
303 if (deviceType_ == DeviceType::WATCH) {
304 contentPadding->SetChild(content_);
305 contentFlex = AceType::MakeRefPtr<FlexItemComponent>(0, 0, 0.0, contentPadding);
306 } else {
307 auto scroll = AceType::MakeRefPtr<ScrollComponent>(content_);
308 contentPadding->SetChild(scroll);
309 contentFlex = AceType::MakeRefPtr<FlexItemComponent>(0, 1, 0.0, contentPadding);
310 }
311 column->AppendChild(GenerateComposed(V2::TEXT_COMPONENT_TAG, contentFlex, true));
312 }
313
BuildMenu(const RefPtr<ColumnComponent> & column)314 void DialogComponent::BuildMenu(const RefPtr<ColumnComponent>& column)
315 {
316 if (actions_.empty()) {
317 LOGW("the action is empty");
318 return;
319 }
320
321 std::list<RefPtr<Component>> columnChildren;
322 auto actionIter = actions_.begin();
323 for (size_t index = 0; index < actions_.size(); ++index) {
324 std::list<RefPtr<Component>> rowChildren;
325 auto buttonRow = AceType::MakeRefPtr<RowComponent>(FlexAlign::CENTER, FlexAlign::CENTER, rowChildren);
326 auto rowItem = AceType::MakeRefPtr<FlexItemComponent>(
327 1, 1, 0.0, BuildButton(*actionIter, menuSuccessId_[index], Edge::NONE, false));
328 buttonRow->AppendChild(rowItem);
329 auto columnItem = AceType::MakeRefPtr<FlexItemComponent>(0.0, 1, 0.0, buttonRow);
330 column->AppendChild(columnItem);
331 ++actionIter;
332 }
333 }
334
BuildActions(const RefPtr<ThemeManager> & themeManager,const RefPtr<ColumnComponent> & column)335 void DialogComponent::BuildActions(const RefPtr<ThemeManager>& themeManager, const RefPtr<ColumnComponent>& column)
336 {
337 if (deviceType_ == DeviceType::WATCH) {
338 BuildActionsForWatch(column);
339 return;
340 }
341
342 if (actions_.empty()) {
343 LOGW("the action is empty");
344 return;
345 }
346
347 auto actionsPadding = AceType::MakeRefPtr<PaddingComponent>();
348 actionsPadding->SetPadding(dialogTheme_->GetActionsPadding());
349 if (actions_.size() == 1) { // the button in dialog is one.
350 std::list<RefPtr<Component>> rowChildren;
351 auto row = AceType::MakeRefPtr<RowComponent>(FlexAlign::SPACE_AROUND, FlexAlign::FLEX_START, rowChildren);
352 row->SetStretchToParent(true);
353 row->AppendChild(AceType::MakeRefPtr<FlexItemComponent>(
354 1, 1, 0.0, BuildButton(actions_.front(), onPositiveSuccessId_, Edge::NONE, true)));
355 actionsPadding->SetChild(row);
356 } else if (actions_.size() == 2) { // the button in dialog is two.
357 std::list<RefPtr<Component>> rowChildren;
358 auto row = AceType::MakeRefPtr<RowComponent>(FlexAlign::SPACE_AROUND, FlexAlign::CENTER, rowChildren);
359 row->SetStretchToParent(true);
360 row->AppendChild(AceType::MakeRefPtr<FlexItemComponent>(
361 1, 1, 0.0, BuildButton(actions_.front(), onPositiveSuccessId_, Edge::NONE)));
362 row->AppendChild(AceType::MakeRefPtr<FlexItemComponent>(0, 0, 0.0, BuildDivider(themeManager)));
363 row->AppendChild(AceType::MakeRefPtr<FlexItemComponent>(
364 1, 1, 0.0, BuildButton(actions_.back(), onNegativeSuccessId_, Edge::NONE, true)));
365 actionsPadding->SetChild(row);
366 } else { // the button in dialog is more than two.
367 std::list<RefPtr<Component>> wrapChildren;
368 auto wrap = AceType::MakeRefPtr<WrapComponent>(wrapChildren);
369 wrap->SetDialogStretch(true);
370 wrap->SetMainAlignment(WrapAlignment::CENTER);
371 wrap->SetSpacing(dialogTheme_->GetButtonSpacingHorizontal());
372 wrap->SetContentSpacing(dialogTheme_->GetButtonSpacingVertical());
373 int32_t num = 0;
374 for (const auto& action : actions_) {
375 ++num;
376 if (num == 1) {
377 wrap->AppendChild(BuildButton(action, onPositiveSuccessId_, Edge::NONE));
378 } else if (num == 2) {
379 wrap->AppendChild(BuildButton(action, onNegativeSuccessId_, Edge::NONE, true));
380 } else if (num == 3) {
381 wrap->AppendChild(BuildButton(action, onNeutralSuccessId_, Edge::NONE));
382 } else {
383 break;
384 }
385 }
386 actionsPadding->SetChild(wrap);
387 }
388 auto actionsFlex = AceType::MakeRefPtr<FlexItemComponent>(0, 0, 0.0, actionsPadding);
389 column->AppendChild(actionsFlex);
390 }
391
BuildActionsForWatch(const OHOS::Ace::RefPtr<OHOS::Ace::ColumnComponent> & column)392 void DialogComponent::BuildActionsForWatch(const OHOS::Ace::RefPtr<OHOS::Ace::ColumnComponent>& column)
393 {
394 if (actions_.empty() || actions_.size() != DIALOG_BUTTONS_COUNT_WATCH) {
395 return;
396 }
397
398 std::list<RefPtr<Component>> rowChildren;
399 auto row = AceType::MakeRefPtr<RowComponent>(FlexAlign::SPACE_BETWEEN, FlexAlign::FLEX_START, rowChildren);
400 row->SetStretchToParent(true);
401 row->AppendChild(BuildButton(actions_.front(), onPositiveSuccessId_, dialogTheme_->GetButtonPaddingRight()));
402 row->AppendChild(BuildButton(actions_.back(), onNegativeSuccessId_, dialogTheme_->GetButtonPaddingLeft(), true));
403 auto actionsPadding = AceType::MakeRefPtr<PaddingComponent>();
404 actionsPadding->SetPadding(dialogTheme_->GetDefaultPadding());
405 actionsPadding->SetChild(row);
406 auto actionsFlex = AceType::MakeRefPtr<FlexItemComponent>(0, 0, 0.0, actionsPadding);
407 column->AppendChild(actionsFlex);
408 }
409
BuildButton(const RefPtr<ButtonComponent> & button,const EventMarker & callbackId,const Edge & edge,bool isAutoFocus)410 RefPtr<Component> DialogComponent::BuildButton(
411 const RefPtr<ButtonComponent>& button, const EventMarker& callbackId, const Edge& edge, bool isAutoFocus)
412 {
413 button->SetClickedEventId(callbackId);
414 button->SetAutoFocusState(isAutoFocus);
415 auto buttonPadding = AceType::MakeRefPtr<PaddingComponent>();
416 buttonPadding->SetPadding(edge);
417 buttonPadding->SetChild(button);
418 return GenerateComposed(V2::BUTTON_COMPONENT_TAG, buttonPadding, true);
419 }
420
BuildAnimation(const RefPtr<BoxComponent> & child)421 RefPtr<TransitionComponent> DialogComponent::BuildAnimation(const RefPtr<BoxComponent>& child)
422 {
423 if (deviceType_ == DeviceType::PHONE) {
424 return BuildAnimationForPhone(child);
425 }
426 // Build scale animation for in.
427 auto scaleFrameStart =
428 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetScaleStart());
429 auto scaleFrameEnd = AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetScaleEnd());
430 auto scaleAnimationIn = AceType::MakeRefPtr<KeyframeAnimation<float>>();
431 scaleAnimationIn->AddKeyframe(scaleFrameStart);
432 scaleAnimationIn->AddKeyframe(scaleFrameEnd);
433 scaleAnimationIn->SetCurve(Curves::FRICTION);
434 // Build opacity animation for in.
435 auto opacityKeyframeStart =
436 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetOpacityStart());
437 auto opacityKeyframeEnd =
438 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetOpacityEnd());
439 auto opacityAnimationIn = AceType::MakeRefPtr<KeyframeAnimation<float>>();
440 opacityAnimationIn->AddKeyframe(opacityKeyframeStart);
441 opacityAnimationIn->AddKeyframe(opacityKeyframeEnd);
442 opacityAnimationIn->SetCurve(Curves::FRICTION);
443 // Build tween option for in
444 TweenOption tweenOptionIn;
445 tweenOptionIn.SetTransformFloatAnimation(AnimationType::SCALE, scaleAnimationIn);
446 tweenOptionIn.SetOpacityAnimation(opacityAnimationIn);
447 tweenOptionIn.SetDuration(dialogTheme_->GetAnimationDurationIn());
448 tweenOptionIn.SetFillMode(FillMode::FORWARDS);
449
450 // Build scale animation for out.
451 auto scaleFrameStartOut =
452 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetScaleEnd());
453 auto scaleFrameEndOut =
454 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetScaleStart());
455 auto scaleAnimationOut = AceType::MakeRefPtr<KeyframeAnimation<float>>();
456 scaleAnimationOut->AddKeyframe(scaleFrameStartOut);
457 scaleAnimationOut->AddKeyframe(scaleFrameEndOut);
458 scaleAnimationOut->SetCurve(Curves::SMOOTH);
459 // Build opacity animation for out.
460 auto opacityKeyframeStartOut =
461 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetOpacityEnd());
462 auto opacityKeyframeEndOut =
463 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetOpacityStart());
464 auto opacityAnimationOut = AceType::MakeRefPtr<KeyframeAnimation<float>>();
465 opacityAnimationOut->AddKeyframe(opacityKeyframeStartOut);
466 opacityAnimationOut->AddKeyframe(opacityKeyframeEndOut);
467 opacityAnimationOut->SetCurve(Curves::SMOOTH);
468 // Build tween option for out
469 TweenOption tweenOptionOut;
470 tweenOptionOut.SetTransformFloatAnimation(AnimationType::SCALE, scaleAnimationOut);
471 tweenOptionOut.SetOpacityAnimation(opacityAnimationOut);
472 tweenOptionOut.SetDuration(dialogTheme_->GetAnimationDurationOut());
473 tweenOptionOut.SetFillMode(FillMode::FORWARDS);
474
475 // Build transition
476 auto transition =
477 AceType::MakeRefPtr<TransitionComponent>(TweenComponent::AllocTweenComponentId(), DIALOG_TWEEN_NAME, child);
478 transition->SetIsFirstFrameShow(false);
479 transition->SetTransitionOption(tweenOptionIn, tweenOptionOut);
480 return transition;
481 }
482
BuildAnimationForPhone(const RefPtr<Component> & child)483 RefPtr<TransitionComponent> DialogComponent::BuildAnimationForPhone(const RefPtr<Component>& child)
484 {
485 // Build scale animation for in.
486 auto scaleFrameStart =
487 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetScaleStart());
488 auto scaleFrameEnd = AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetScaleEnd());
489 auto scaleAnimationIn = AceType::MakeRefPtr<KeyframeAnimation<float>>();
490 scaleAnimationIn->AddKeyframe(scaleFrameStart);
491 scaleAnimationIn->AddKeyframe(scaleFrameEnd);
492 auto dialogCurve = AceType::MakeRefPtr<CubicCurve>(
493 PHONE_ENTER_CURVE_X0, PHONE_ENTER_CURVE_Y0, PHONE_ENTER_CURVE_X1, PHONE_ENTER_CURVE_Y1);
494 scaleAnimationIn->SetCurve(dialogCurve);
495 // Build opacity animation for in.
496 auto opacityKeyframeStart =
497 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetOpacityStart());
498 auto opacityKeyframeMiddle =
499 AceType::MakeRefPtr<Keyframe<float>>(PHONE_OPACITY_MIDDLE_IN, dialogTheme_->GetOpacityEnd());
500 auto opacityKeyframeEnd =
501 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetOpacityEnd());
502 auto opacityAnimationIn = AceType::MakeRefPtr<KeyframeAnimation<float>>();
503 opacityAnimationIn->AddKeyframe(opacityKeyframeStart);
504 opacityAnimationIn->AddKeyframe(opacityKeyframeMiddle);
505 opacityAnimationIn->AddKeyframe(opacityKeyframeEnd);
506 opacityAnimationIn->SetCurve(Curves::SHARP);
507 // Build tween option for in
508 TweenOption tweenOptionIn;
509 tweenOptionIn.SetTransformFloatAnimation(AnimationType::SCALE, scaleAnimationIn);
510 tweenOptionIn.SetOpacityAnimation(opacityAnimationIn);
511 tweenOptionIn.SetDuration(dialogTheme_->GetAnimationDurationIn());
512 tweenOptionIn.SetFillMode(FillMode::FORWARDS);
513 // Build scale animation for out.
514 auto scaleFrameStartOut =
515 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetScaleEnd());
516 auto scaleFrameEndOut =
517 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetScaleStart());
518 auto scaleAnimationOut = AceType::MakeRefPtr<KeyframeAnimation<float>>();
519 scaleAnimationOut->AddKeyframe(scaleFrameStartOut);
520 scaleAnimationOut->AddKeyframe(scaleFrameEndOut);
521 scaleAnimationOut->SetCurve(Curves::SMOOTH);
522 // Build opacity animation for out.
523 auto opacityKeyframeStartOut =
524 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameStart(), dialogTheme_->GetOpacityEnd());
525 auto opacityKeyframeEndOut =
526 AceType::MakeRefPtr<Keyframe<float>>(dialogTheme_->GetFrameEnd(), dialogTheme_->GetOpacityStart());
527 auto opacityAnimationOut = AceType::MakeRefPtr<KeyframeAnimation<float>>();
528 opacityAnimationOut->AddKeyframe(opacityKeyframeStartOut);
529 opacityAnimationOut->AddKeyframe(opacityKeyframeEndOut);
530 opacityAnimationOut->SetCurve(Curves::SMOOTH);
531 // Build tween option for out
532 TweenOption tweenOptionOut;
533 tweenOptionOut.SetTransformFloatAnimation(AnimationType::SCALE, scaleAnimationOut);
534 tweenOptionOut.SetOpacityAnimation(opacityAnimationOut);
535 tweenOptionOut.SetDuration(dialogTheme_->GetAnimationDurationOut());
536 tweenOptionOut.SetFillMode(FillMode::FORWARDS);
537 auto transition =
538 AceType::MakeRefPtr<TransitionComponent>(TweenComponent::AllocTweenComponentId(), DIALOG_TWEEN_NAME, child);
539 transition->SetIsFirstFrameShow(false);
540 transition->SetTransitionOption(tweenOptionIn, tweenOptionOut);
541 return transition;
542 }
543
GenerateComposed(const std::string & name,const RefPtr<Component> & child,bool isDialogTweenChild)544 RefPtr<Component> DialogComponent::GenerateComposed(
545 const std::string& name, const RefPtr<Component>& child, bool isDialogTweenChild)
546 {
547 const auto& pipelineContext = context_.Upgrade();
548 if (pipelineContext) {
549 const auto& accessibilityManager = pipelineContext->GetAccessibilityManager();
550 if (!accessibilityManager) {
551 return child;
552 }
553 // use accessibility node already created with dom node in JS app
554 int32_t composedId = customDialogId_;
555 if (composedId == -1) {
556 composedId = accessibilityManager->GenerateNextAccessibilityId();
557 }
558 if (!pipelineContext->GetIsDeclarative()) {
559 const auto& composed = AceType::MakeRefPtr<ComposedComponent>(std::to_string(composedId), name, child);
560 if (isDialogTweenChild) {
561 accessibilityManager->CreateSpecializedNode(name, composedId, dialogTweenComposedId_);
562 } else {
563 dialogTweenComposedId_ = composedId;
564 }
565 return composed;
566 }
567 #if !defined(PREVIEW)
568 return AceType::MakeRefPtr<V2::InspectorComposedComponent>(
569 V2::InspectorComposedComponent::GenerateId(), name, child);
570 #endif
571 }
572 return child;
573 }
574
BuildDivider(const RefPtr<ThemeManager> & themeManager)575 RefPtr<Component> DialogComponent::BuildDivider(const RefPtr<ThemeManager>& themeManager)
576 {
577 if (!themeManager) {
578 return nullptr;
579 }
580 auto padding = AceType::MakeRefPtr<PaddingComponent>();
581 auto dialogTheme = AceType::DynamicCast<DialogTheme>(themeManager->GetTheme(DialogTheme::TypeId()));
582 if (!dialogTheme) {
583 return nullptr;
584 }
585 if (SystemProperties::GetDeviceType() == DeviceType::TV) {
586 padding->SetPadding(Edge(dialogTheme->GetButtonSpacingHorizontal(), Dimension(0.0, DimensionUnit::VP),
587 Dimension(0.0, DimensionUnit::VP), Dimension(0.0, DimensionUnit::VP)));
588 return padding;
589 }
590 padding->SetPadding(dialogTheme->GetDividerPadding());
591 auto dividerBox = AceType::MakeRefPtr<BoxComponent>();
592 dividerBox->SetWidth(dialogTheme->GetDividerWidth().Value(), dialogTheme->GetDividerWidth().Unit());
593 dividerBox->SetHeight(dialogTheme->GetDividerHeight().Value(), dialogTheme->GetDividerHeight().Unit());
594 auto backDecoration = AceType::MakeRefPtr<Decoration>();
595 backDecoration->SetBackgroundColor(dialogTheme->GetDividerColor());
596 dividerBox->SetBackDecoration(backDecoration);
597 padding->SetChild(dividerBox);
598 return padding;
599 }
600
Build(const DialogProperties & dialogProperties,const WeakPtr<PipelineContext> & context)601 RefPtr<DialogComponent> DialogBuilder::Build(
602 const DialogProperties& dialogProperties, const WeakPtr<PipelineContext>& context)
603 {
604 auto dialog = BuildDialogWithType(dialogProperties.type);
605 dialog->SetDialogProperties(dialogProperties);
606 auto pipelineContext = context.Upgrade();
607 if (!pipelineContext) {
608 return dialog;
609 }
610 auto themeManager = pipelineContext->GetThemeManager();
611 if (!themeManager) {
612 return dialog;
613 }
614 auto dialogTheme = AceType::DynamicCast<DialogTheme>(themeManager->GetTheme(DialogTheme::TypeId()));
615 if (!dialogTheme) {
616 return dialog;
617 }
618 std::string data;
619 dialog->SetContext(context);
620 dialog->SetBackgroundColor(dialogTheme->GetBackgroundColor());
621 // Set title and content of dialog
622 BuildTitleAndContent(dialog, dialogProperties, dialogTheme, data);
623 // Set buttons of dialog
624 BuildButtons(themeManager, dialog, dialogProperties.buttons, dialogTheme, data);
625 // Build DialogTween
626 auto controller = AceType::MakeRefPtr<Animator>(context);
627 dialog->SetAnimator(controller);
628 dialog->SetAutoCancel(dialogProperties.autoCancel);
629 dialog->SetData(data);
630 // Set eventMarker of dialog component
631 if (!dialogProperties.callbacks.empty()) {
632 for (const auto& callback : dialogProperties.callbacks) {
633 if (callback.first == CALLBACK_SUCCESS) {
634 dialog->SetOnSuccessId(callback.second);
635 }
636 if (callback.first == CALLBACK_CANCEL) {
637 dialog->SetOnCancelId(callback.second);
638 }
639 if (callback.first == CALLBACK_COMPLETE) {
640 dialog->SetOnCompleteId(callback.second);
641 }
642 }
643 }
644 // Set menu evenMarker
645 if (dialogProperties.isMenu) {
646 dialog->SetIsMenu(true);
647 for (size_t index = 0; index < dialogProperties.buttons.size(); ++index) {
648 dialog->GetMenuSuccessId().emplace_back(BackEndEventManager<void()>::GetInstance().GetAvailableMarker());
649 }
650 }
651 return BuildAnimation(dialog, dialogTheme);
652 }
653
BuildDialogWithType(DialogType type)654 RefPtr<DialogComponent> DialogBuilder::BuildDialogWithType(DialogType type)
655 {
656 RefPtr<DialogComponent> dialog;
657 // Create different dialog according to type.
658 switch (type) {
659 case DialogType::ALERT_DIALOG: {
660 dialog = AceType::MakeRefPtr<AlertDialogComponent>();
661 dialog->SetOnSuccessId(BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker());
662 break;
663 }
664 case DialogType::ACTION_SHEET: {
665 dialog = AceType::MakeRefPtr<ActionSheetComponent>();
666 dialog->SetIsMenu(true);
667 dialog->SetOnSuccessId(BackEndEventManager<void(int32_t)>::GetInstance().GetAvailableMarker());
668 break;
669 }
670 default:
671 dialog = AceType::MakeRefPtr<DialogComponent>();
672 break;
673 }
674 return dialog;
675 }
676
BuildTitleAndContent(const RefPtr<DialogComponent> & dialog,const DialogProperties & dialogProperties,const RefPtr<DialogTheme> & dialogTheme,std::string & data)677 void DialogBuilder::BuildTitleAndContent(const RefPtr<DialogComponent>& dialog,
678 const DialogProperties& dialogProperties, const RefPtr<DialogTheme>& dialogTheme, std::string& data)
679 {
680 auto deviceType = SystemProperties::GetDeviceType();
681 if ((deviceType != DeviceType::WATCH) && (!dialogProperties.title.empty())) {
682 auto titleComponent = AceType::MakeRefPtr<TextComponent>(dialogProperties.title);
683 auto style = dialogTheme->GetTitleTextStyle();
684 style.SetMaxLines(dialogTheme->GetTitleMaxLines());
685 style.SetTextOverflow(TextOverflow::ELLIPSIS);
686 style.SetAdaptTextSize(style.GetFontSize(), dialogTheme->GetTitleMinFontSize());
687 titleComponent->SetTextStyle(style);
688 titleComponent->SetFocusColor(style.GetTextColor());
689 dialog->SetTitle(titleComponent);
690 data += dialogProperties.title + SEPARATE;
691 }
692 if (!dialogProperties.content.empty()) {
693 auto contentComponent = AceType::MakeRefPtr<TextComponent>(dialogProperties.content);
694 auto contentStyle = dialogTheme->GetContentTextStyle();
695 if (deviceType == DeviceType::WATCH) {
696 std::vector<TextSizeGroup> preferTextSizeGroups;
697 preferTextSizeGroups.push_back({ contentStyle.GetFontSize(), 1 });
698 preferTextSizeGroups.push_back({ dialogTheme->GetContentMinFontSize(), UINT32_MAX, TextOverflow::NONE });
699 contentStyle.SetPreferTextSizeGroups(preferTextSizeGroups);
700 contentStyle.SetTextAlign(TextAlign::CENTER);
701 }
702 contentComponent->SetTextStyle(contentStyle);
703 contentComponent->SetFocusColor(dialogTheme->GetContentTextStyle().GetTextColor());
704 dialog->SetContent(contentComponent);
705 data += dialogProperties.content + SEPARATE;
706 }
707 }
708
BuildButtons(const RefPtr<ThemeManager> & themeManager,const RefPtr<DialogComponent> & dialog,const std::vector<ButtonInfo> & buttons,const RefPtr<DialogTheme> & dialogTheme,std::string & data)709 void DialogBuilder::BuildButtons(const RefPtr<ThemeManager>& themeManager, const RefPtr<DialogComponent>& dialog,
710 const std::vector<ButtonInfo>& buttons, const RefPtr<DialogTheme>& dialogTheme,
711 std::string& data)
712 {
713 if (SystemProperties::GetDeviceType() == DeviceType::WATCH) {
714 BuildButtonsForWatch(themeManager, dialog, data);
715 return;
716 }
717 if (buttons.empty()) {
718 return;
719 }
720 auto buttonTheme = AceType::DynamicCast<ButtonTheme>(themeManager->GetTheme(ButtonTheme::TypeId()));
721 if (!buttonTheme) {
722 return;
723 }
724 int32_t buttonIndex = 0;
725 std::list<RefPtr<ButtonComponent>> buttonComponents;
726 for (const auto& button : buttons) {
727 if (button.text.empty()) {
728 continue;
729 }
730 data += button.text + SEPARATE;
731
732 // Init text style in button.
733 TextStyle buttonTextStyle = buttonTheme->GetTextStyle();
734 const Color TEXT_COLOR = Color::FromString("#0a59f4");
735 buttonTextStyle.SetTextColor(TEXT_COLOR);
736 buttonTextStyle.SetAdaptTextSize(buttonTheme->GetMaxFontSize(), buttonTheme->GetMinFontSize());
737 buttonTextStyle.SetMaxLines(1);
738 buttonTextStyle.SetTextOverflow(TextOverflow::ELLIPSIS);
739 if (SystemProperties::GetDeviceType() == DeviceType::CAR) {
740 buttonTextStyle.SetAdaptTextSize(dialogTheme->GetButtonTextSize(), dialogTheme->GetMinButtonTextSize());
741 buttonTextStyle.SetFontWeight(FontWeight::MEDIUM);
742 buttonTextStyle.SetFontSize(dialogTheme->GetButtonTextSize());
743 buttonTextStyle.SetAdaptTextSize(dialogTheme->GetButtonTextSize(), dialogTheme->GetMinButtonTextSize());
744 if (buttonIndex != static_cast<int32_t>(buttons.size()) - 1) {
745 buttonTextStyle.SetTextColor(dialogTheme->GetCommonButtonTextColor());
746 } else {
747 buttonTextStyle.SetTextColor(dialogTheme->GetEmphasizeButtonTextColor());
748 }
749 }
750
751 RefPtr<ButtonComponent> buttonComponent;
752 if (!button.textColor.empty()) {
753 buttonTextStyle.SetTextColor(Color::FromString(button.textColor, 0xff000000, Color(0xff0a59f4)));
754 buttonComponent = ButtonBuilder::Build(
755 themeManager, button.text, buttonTextStyle, Color::FromString(button.textColor), true);
756 } else {
757 buttonComponent =
758 ButtonBuilder::Build(themeManager, button.text, buttonTextStyle, buttonTextStyle.GetTextColor(), true);
759 }
760 buttonComponent->SetBackgroundColor(Color::TRANSPARENT);
761 if (SystemProperties::GetDeviceType() == DeviceType::CAR) {
762 buttonComponent->SetHeight(dialogTheme->GetButtonHeight());
763 buttonComponent->SetRectRadius(dialogTheme->GetButtonHeight() / 2.0);
764 if (buttonIndex != static_cast<int32_t>(buttons.size()) - 1) {
765 buttonComponent->SetBackgroundColor(dialogTheme->GetCommonButtonBgColor());
766 } else {
767 buttonComponent->SetBackgroundColor(dialogTheme->GetEmphasizeButtonBgColor());
768 }
769 }
770 buttonComponent->SetHoverColor(Color::FromString("#0C000000"));
771 buttonComponent->SetClickedColor(dialogTheme->GetButtonClickedColor());
772 // If background color of button is setted by developer, use it.
773 if (button.isBgColorSetted) {
774 buttonComponent->SetBackgroundColor(button.bgColor);
775 buttonComponent->SetHoverColor(button.bgColor.BlendColorWithAlpha(dialogTheme->GetButtonClickedColor()));
776 buttonComponent->SetClickedColor(button.bgColor.BlendColorWithAlpha(dialogTheme->GetButtonClickedColor()));
777 }
778 buttonComponent->SetType(ButtonType::TEXT);
779 buttonComponents.emplace_back(buttonComponent);
780 ++buttonIndex;
781 }
782 dialog->SetActions(buttonComponents);
783 }
784
BuildButtonsForWatch(const RefPtr<ThemeManager> & themeManager,const RefPtr<DialogComponent> & dialog,std::string & data)785 void DialogBuilder::BuildButtonsForWatch(
786 const RefPtr<ThemeManager>& themeManager, const RefPtr<DialogComponent>& dialog, std::string& data)
787 {
788 auto buttonTheme = AceType::DynamicCast<ButtonTheme>(themeManager->GetTheme(ButtonTheme::TypeId()));
789 auto dialogTheme = AceType::DynamicCast<DialogTheme>(themeManager->GetTheme(DialogTheme::TypeId()));
790 if (!buttonTheme || !dialogTheme) {
791 return;
792 }
793 std::string buttonText;
794 std::list<RefPtr<ButtonComponent>> buttonComponents;
795 for (int32_t i = 1; i <= DIALOG_BUTTONS_COUNT_WATCH; ++i) {
796 auto buttonPadding = AceType::MakeRefPtr<PaddingComponent>();
797 buttonPadding->SetPadding(buttonTheme->GetMinCircleButtonPadding());
798 RefPtr<ImageComponent> buttonIcon;
799 if (i == 1) {
800 buttonText = Localization::GetInstance()->GetEntryLetters(DIALOG_CANCEL);
801 buttonIcon = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::WRONG_SVG);
802 } else {
803 buttonText = Localization::GetInstance()->GetEntryLetters(DIALOG_OK);
804 buttonIcon = AceType::MakeRefPtr<ImageComponent>(InternalResource::ResourceId::CORRECT_SVG);
805 }
806 data += buttonText + SEPARATE;
807 buttonIcon->SetWidth(buttonTheme->GetMinCircleButtonIcon());
808 buttonIcon->SetHeight(buttonTheme->GetMinCircleButtonIcon());
809 buttonPadding->SetChild(buttonIcon);
810 std::list<RefPtr<Component>> buttonChildren;
811 buttonChildren.emplace_back(buttonPadding);
812 auto buttonComponent = AceType::MakeRefPtr<ButtonComponent>(buttonChildren);
813 buttonComponent->SetWidth(buttonTheme->GetMinCircleButtonDiameter());
814 buttonComponent->SetHeight(buttonTheme->GetMinCircleButtonDiameter());
815 buttonComponent->SetRectRadius(buttonTheme->GetMinCircleButtonDiameter() / 2.0);
816 buttonComponent->SetBackgroundColor(buttonTheme->GetBgColor());
817 buttonComponent->SetClickedColor(buttonTheme->GetClickedColor());
818 if (i == 2) {
819 buttonComponent->SetBackgroundColor(dialogTheme->GetButtonBackgroundColor());
820 buttonComponent->SetClickedColor(dialogTheme->GetButtonClickedColor());
821 }
822 buttonComponent->SetFocusColor(buttonTheme->GetBgFocusColor());
823 buttonComponent->SetFocusAnimationColor(buttonTheme->GetBgFocusColor());
824 buttonComponent->SetAccessibilityText(buttonText);
825 buttonComponents.emplace_back(buttonComponent);
826 }
827 dialog->SetActions(buttonComponents);
828 }
829
BuildAnimation(const RefPtr<DialogComponent> & dialogChild,const RefPtr<DialogTheme> & dialogTheme)830 RefPtr<DialogComponent> DialogBuilder::BuildAnimation(
831 const RefPtr<DialogComponent>& dialogChild, const RefPtr<DialogTheme>& dialogTheme)
832 {
833 auto tweenBox = AceType::MakeRefPtr<BoxComponent>();
834 auto decoration = AceType::MakeRefPtr<Decoration>();
835 decoration->SetBackgroundColor(Color(dialogTheme->GetMaskColorEnd()));
836 tweenBox->SetBackDecoration(decoration);
837 const auto& colorAnimation = AceType::MakeRefPtr<CurveAnimation<Color>>(
838 dialogTheme->GetMaskColorStart(), dialogTheme->GetMaskColorEnd(), Curves::LINEAR);
839 // Build tween option of in
840 TweenOption tweenOptionIn;
841 tweenOptionIn.SetColorAnimation(colorAnimation);
842 tweenOptionIn.SetDuration(dialogTheme->GetAnimationDurationIn());
843 tweenOptionIn.SetFillMode(FillMode::FORWARDS);
844 // Build tween option of out
845 const auto& colorAnimationOut = AceType::MakeRefPtr<CurveAnimation<Color>>(
846 dialogTheme->GetMaskColorEnd(), dialogTheme->GetMaskColorStart(), Curves::LINEAR);
847 TweenOption tweenOptionOut;
848 tweenOptionOut.SetColorAnimation(colorAnimationOut);
849 tweenOptionOut.SetDuration(dialogTheme->GetAnimationDurationOut());
850 tweenOptionOut.SetFillMode(FillMode::FORWARDS);
851 // Build transition
852 auto transition =
853 AceType::MakeRefPtr<TransitionComponent>(TweenComponent::AllocTweenComponentId(), "transition", tweenBox);
854 transition->SetIsFirstFrameShow(false);
855 transition->SetTransitionOption(tweenOptionIn, tweenOptionOut);
856
857 dialogChild->SetChild(transition);
858 dialogChild->SetDialogTweenBox(tweenBox);
859 return dialogChild;
860 }
861
862 } // namespace OHOS::Ace