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