• 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/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