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