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