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