1 /*
2 * Copyright (c) 2022-2023 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 #include "core/components_ng/pattern/dialog/dialog_pattern.h"
16
17 #include <climits>
18 #include <cstdint>
19 #include <cstring>
20 #include <optional>
21 #include <string>
22
23 #include "base/geometry/dimension.h"
24 #include "base/json/json_util.h"
25 #include "base/log/dump_log.h"
26 #include "base/log/log.h"
27 #include "base/memory/ace_type.h"
28 #include "base/memory/referenced.h"
29 #include "base/subwindow/subwindow_manager.h"
30 #include "base/utils/utils.h"
31 #include "bridge/common/dom/dom_type.h"
32 #include "core/common/ace_engine.h"
33 #include "core/common/container.h"
34 #include "core/common/recorder/event_recorder.h"
35 #include "core/components/button/button_theme.h"
36 #include "core/components/common/properties/alignment.h"
37 #include "core/components/theme/icon_theme.h"
38 #include "core/components_ng/base/frame_node.h"
39 #include "core/components_ng/base/inspector_filter.h"
40 #include "core/components_ng/base/ui_node.h"
41 #include "core/components_ng/base/view_stack_processor.h"
42 #include "core/components_ng/event/gesture_event_hub.h"
43 #include "core/components_ng/layout/layout_property.h"
44 #include "core/components_ng/pattern/button/button_layout_property.h"
45 #include "core/components_ng/pattern/button/button_pattern.h"
46 #include "core/components_ng/pattern/divider/divider_layout_property.h"
47 #include "core/components_ng/pattern/divider/divider_model_ng.h"
48 #include "core/components_ng/pattern/divider/divider_pattern.h"
49 #include "core/components_ng/pattern/flex/flex_layout_algorithm.h"
50 #include "core/components_ng/pattern/flex/flex_layout_property.h"
51 #include "core/components_ng/pattern/image/image_pattern.h"
52 #include "core/components_ng/pattern/linear_layout/linear_layout_pattern.h"
53 #include "core/components_ng/pattern/linear_layout/linear_layout_property.h"
54 #include "core/components_ng/pattern/list/list_pattern.h"
55 #include "core/components_ng/pattern/overlay/overlay_manager.h"
56 #include "core/components_ng/pattern/relative_container/relative_container_model_ng.h"
57 #include "core/components_ng/pattern/relative_container/relative_container_pattern.h"
58 #include "core/components_ng/pattern/scroll/scroll_pattern.h"
59 #include "core/components_ng/pattern/text/text_layout_property.h"
60 #include "core/components_ng/pattern/text/text_pattern.h"
61 #include "core/components_ng/property/calc_length.h"
62 #include "core/components_ng/property/measure_property.h"
63 #include "core/components_v2/inspector/inspector_constants.h"
64 #include "core/event/key_event.h"
65 #include "core/event/touch_event.h"
66 #include "core/pipeline/base/element_register.h"
67 #include "core/pipeline_ng/pipeline_context.h"
68
69 namespace OHOS::Ace::NG {
70
71 namespace {
72 constexpr int32_t SHEET_INFO_IDX = -2;
73 constexpr Dimension SHEET_IMAGE_MARGIN = 16.0_vp;
74 constexpr Dimension SHEET_DIVIDER_WIDTH = 1.0_px;
75 constexpr Dimension SHEET_LIST_PADDING = 24.0_vp;
76 constexpr Dimension DIALOG_BUTTON_TEXT_SIZE = 16.0_fp;
77 constexpr Color DEFAULT_BUTTON_COLOR = Color(0xff007dff);
78 const CalcLength SHEET_IMAGE_SIZE(40.0_vp);
79 constexpr int32_t THREE_BUTTON_MODE = 3;
80 constexpr int32_t TWO_BUTTON_MODE = 2;
81 constexpr int32_t ONE_BUTTON_MODE = 1;
82 constexpr int32_t START_CHILD_INDEX = 0;
83 constexpr uint32_t DIALOG_TITLE_MAXLINES = 1;
84 constexpr Dimension DIALOG_ONE_TITLE_ALL_HEIGHT = 56.0_vp;
85 constexpr Dimension DIALOG_TITLE_CONTENT_HEIGHT = 35.0_px;
86 constexpr int32_t DIALOG_TITLE_AVE_BY_2 = 2;
87 constexpr Dimension DIALOG_CONTENT_PADDING_TOP = 0.0_vp;
88 constexpr Dimension DIALOG_SUBTITLE_PADDING_LEFT = 24.0_vp;
89 constexpr Dimension DIALOG_SUBTITLE_PADDING_RIGHT = 24.0_vp;
90 constexpr Dimension DIALOG_TWO_TITLE_ZERO_SPACE = 0.0_vp;
91 constexpr Dimension DIALOG_TWO_TITLE_SPACE = 16.0_vp;
92 constexpr Dimension ADAPT_TITLE_MIN_FONT_SIZE = 16.0_fp;
93 constexpr Dimension ADAPT_SUBTITLE_MIN_FONT_SIZE = 12.0_fp;
94 constexpr uint32_t ADAPT_TITLE_MAX_LINES = 2;
95 constexpr Dimension DIALOG_BUTTON_BORDER_RADIUS = 20.0_vp;
96
GetBoolStr(bool isTure)97 std::string GetBoolStr(bool isTure)
98 {
99 return isTure ? "True" : "False";
100 }
101 } // namespace
102
OnModifyDone()103 void DialogPattern::OnModifyDone()
104 {
105 Pattern::OnModifyDone();
106 auto host = GetHost();
107 CHECK_NULL_VOID(host);
108 auto gestureHub = host->GetOrCreateGestureEventHub();
109 CHECK_NULL_VOID(gestureHub);
110
111 if (!onClick_) {
112 InitClickEvent(gestureHub);
113 }
114 auto focusHub = host->GetOrCreateFocusHub();
115 CHECK_NULL_VOID(focusHub);
116 RegisterOnKeyEvent(focusHub);
117 InitFocusEvent(focusHub);
118 }
119
OnAttachToFrameNode()120 void DialogPattern::OnAttachToFrameNode()
121 {
122 auto host = GetHost();
123 CHECK_NULL_VOID(host);
124 auto pipelineContext = host->GetContext();
125 CHECK_NULL_VOID(pipelineContext);
126 pipelineContext->AddWindowSizeChangeCallback(host->GetId());
127 InitHostWindowRect();
128 auto foldModeChangeCallback = [weak = WeakClaim(this)](FoldDisplayMode foldDisplayMode) {
129 auto pattern = weak.Upgrade();
130 CHECK_NULL_VOID(pattern);
131 pattern->isFoldStatusChanged_ = true;
132 };
133 auto callbackId = pipelineContext->RegisterFoldDisplayModeChangedCallback(std::move(foldModeChangeCallback));
134 UpdateFoldDisplayModeChangedCallbackId(callbackId);
135 }
136
OnDetachFromFrameNode(FrameNode * frameNode)137 void DialogPattern::OnDetachFromFrameNode(FrameNode* frameNode)
138 {
139 auto pipeline = PipelineContext::GetCurrentContext();
140 CHECK_NULL_VOID(pipeline);
141 pipeline->RemoveWindowSizeChangeCallback(frameNode->GetId());
142 if (HasFoldDisplayModeChangedCallbackId()) {
143 pipeline->UnRegisterFoldDisplayModeChangedCallback(foldDisplayModeChangedCallbackId_.value_or(-1));
144 }
145 }
146
OnFontConfigurationUpdate()147 void DialogPattern::OnFontConfigurationUpdate()
148 {
149 CHECK_NULL_VOID(buttonContainer_);
150 UpdatePropertyForElderly(dialogProperties_.buttons);
151 contentColumn_->RemoveChild(buttonContainer_);
152 auto buttonContainer = BuildButtons(dialogProperties_.buttons, dialogProperties_.buttonDirection);
153 CHECK_NULL_VOID(buttonContainer);
154 buttonContainer->MountToParent(contentColumn_);
155 UpdateTextFontScale();
156 if (isSuitableForElderly_ && NeedsButtonDirectionChange(dialogProperties_.buttons)) {
157 contentColumn_->RemoveChild(buttonContainer_);
158 auto buttonContainerNew = BuildButtons(dialogProperties_.buttons, DialogButtonDirection::VERTICAL);
159 CHECK_NULL_VOID(buttonContainerNew);
160 buttonContainerNew->MountToParent(contentColumn_);
161 buttonContainer_ = buttonContainerNew;
162 CheckScrollHeightIsNegative(contentColumn_, dialogProperties_);
163 UpdateTextFontScale();
164 }
165 }
166
InitClickEvent(const RefPtr<GestureEventHub> & gestureHub)167 void DialogPattern::InitClickEvent(const RefPtr<GestureEventHub>& gestureHub)
168 {
169 GestureEventFunc task = [weak = WeakClaim(this)](const GestureEvent& info) {
170 auto pattern = weak.Upgrade();
171 CHECK_NULL_VOID(pattern);
172 pattern->HandleClick(info);
173 };
174 onClick_ = MakeRefPtr<ClickEvent>(std::move(task));
175 gestureHub->AddClickEvent(onClick_);
176 }
177
HandleClick(const GestureEvent & info)178 void DialogPattern::HandleClick(const GestureEvent& info)
179 {
180 if (info.GetSourceDevice() == SourceType::KEYBOARD) {
181 return;
182 }
183 auto host = GetHost();
184 CHECK_NULL_VOID(host);
185 auto props = host->GetLayoutProperty<DialogLayoutProperty>();
186 CHECK_NULL_VOID(props);
187 auto globalOffset = host->GetPaintRectOffset();
188 auto autoCancel = props->GetAutoCancel().value_or(true);
189 if (autoCancel) {
190 auto content = DynamicCast<FrameNode>(host->GetChildAtIndex(0));
191 CHECK_NULL_VOID(content);
192 auto contentRect = content->GetGeometryNode()->GetFrameRect();
193 // close dialog if clicked outside content rect
194 auto&& clickPosition = info.GetGlobalLocation();
195 if (!contentRect.IsInRegion(
196 PointF(clickPosition.GetX() - globalOffset.GetX(), clickPosition.GetY() - globalOffset.GetY()))) {
197 auto pipeline = PipelineContext::GetCurrentContext();
198 CHECK_NULL_VOID(pipeline);
199 auto overlayManager = pipeline->GetOverlayManager();
200 CHECK_NULL_VOID(overlayManager);
201 if (this->CallDismissInNDK(static_cast<int32_t>(DialogDismissReason::DIALOG_TOUCH_OUTSIDE))) {
202 return;
203 } else if (this->ShouldDismiss()) {
204 overlayManager->SetDismissDialogId(host->GetId());
205 this->CallOnWillDismiss(static_cast<int32_t>(DialogDismissReason::DIALOG_TOUCH_OUTSIDE));
206 TAG_LOGI(AceLogTag::ACE_DIALOG, "Dialog Should Dismiss");
207 return;
208 }
209 PopDialog(-1);
210 if (overlayManager->isMaskNode(GetHost()->GetId())) {
211 overlayManager->PopModalDialog(GetHost()->GetId());
212 }
213 }
214 }
215 }
216
PopDialog(int32_t buttonIdx=-1)217 void DialogPattern::PopDialog(int32_t buttonIdx = -1)
218 {
219 auto host = GetHost();
220 CHECK_NULL_VOID(host);
221 auto pipeline = host->GetContext();
222 CHECK_NULL_VOID(pipeline);
223 auto overlayManager = pipeline->GetOverlayManager();
224 CHECK_NULL_VOID(overlayManager);
225 if (host->IsRemoving()) {
226 return;
227 }
228
229 auto hub = host->GetEventHub<DialogEventHub>();
230 if (buttonIdx != -1) {
231 hub->FireSuccessEvent(buttonIdx);
232 RecordEvent(buttonIdx);
233 } else {
234 // trigger onCancel callback
235 hub->FireCancelEvent();
236 RecordEvent(buttonIdx);
237 }
238 if (dialogProperties_.isShowInSubWindow) {
239 SubwindowManager::GetInstance()->DeleteHotAreas(
240 SubwindowManager::GetInstance()->GetDialogSubWindowId(), host->GetId());
241 SubwindowManager::GetInstance()->HideDialogSubWindow(SubwindowManager::GetInstance()->GetDialogSubWindowId());
242 }
243 overlayManager->CloseDialog(host);
244 }
245
RecordEvent(int32_t btnIndex) const246 void DialogPattern::RecordEvent(int32_t btnIndex) const
247 {
248 if (!Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
249 return;
250 }
251 std::string btnText;
252 if (btnIndex >= 0 && static_cast<size_t>(btnIndex) < dialogProperties_.buttons.size()) {
253 btnText = dialogProperties_.buttons.at(btnIndex).text;
254 }
255 Recorder::EventType eventType;
256 if (btnIndex == -1) {
257 eventType = Recorder::EventType::DIALOG_CANCEL;
258 } else {
259 eventType = Recorder::EventType::DIALOG_ACTION;
260 }
261 Recorder::EventParamsBuilder builder;
262 builder.SetEventType(eventType)
263 .SetText(btnText)
264 .SetExtra(Recorder::KEY_TITLE, title_)
265 .SetExtra(Recorder::KEY_SUB_TITLE, subtitle_);
266 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
267 }
268
269 // set render context properties of content frame
UpdateContentRenderContext(const RefPtr<FrameNode> & contentNode,const DialogProperties & props)270 void DialogPattern::UpdateContentRenderContext(const RefPtr<FrameNode>& contentNode, const DialogProperties& props)
271 {
272 auto contentRenderContext = contentNode->GetRenderContext();
273 CHECK_NULL_VOID(contentRenderContext);
274 contentRenderContext_ = contentRenderContext;
275 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN) &&
276 contentRenderContext->IsUniRenderEnabled() && props.isSysBlurStyle) {
277 BlurStyleOption styleOption;
278 styleOption.blurStyle = static_cast<BlurStyle>(
279 props.backgroundBlurStyle.value_or(static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)));
280 contentRenderContext->UpdateBackBlurStyle(styleOption);
281 contentRenderContext->UpdateBackgroundColor(props.backgroundColor.value_or(Color::TRANSPARENT));
282 } else {
283 contentRenderContext->UpdateBackgroundColor(props.backgroundColor.value_or(dialogTheme_->GetBackgroundColor()));
284 }
285 if (props.borderRadius.has_value()) {
286 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE)) {
287 auto radiusValue = props.borderRadius.value();
288 ParseBorderRadius(radiusValue);
289 contentRenderContext->UpdateBorderRadius(radiusValue);
290 } else {
291 contentRenderContext->UpdateBorderRadius(props.borderRadius.value());
292 }
293 } else {
294 BorderRadiusProperty radius;
295 radius.SetRadius(dialogTheme_->GetRadius().GetX());
296 contentRenderContext->UpdateBorderRadius(radius);
297 }
298 if (props.borderWidth.has_value()) {
299 auto layoutProps = contentNode->GetLayoutProperty<LinearLayoutProperty>();
300 CHECK_NULL_VOID(layoutProps);
301 layoutProps->UpdateBorderWidth(props.borderWidth.value());
302 contentRenderContext->UpdateBorderWidth(props.borderWidth.value());
303 contentNodeMap_[DialogContentNode::BORDERWIDTH] = contentNode;
304 }
305 if (props.borderStyle.has_value()) {
306 contentRenderContext->UpdateBorderStyle(props.borderStyle.value());
307 }
308 if (props.borderColor.has_value()) {
309 contentRenderContext->UpdateBorderColor(props.borderColor.value());
310 }
311 if (props.shadow.has_value()) {
312 contentRenderContext->UpdateBackShadow(props.shadow.value());
313 }
314 contentRenderContext->SetClipToBounds(true);
315 }
316
ParseBorderRadius(BorderRadiusProperty & raidus)317 void DialogPattern::ParseBorderRadius(BorderRadiusProperty& raidus)
318 {
319 if (!raidus.radiusTopLeft.has_value() || raidus.radiusTopLeft.value().Value() < 0) {
320 raidus.radiusTopLeft = dialogTheme_->GetRadius().GetX();
321 }
322 if (!raidus.radiusTopRight.has_value() || raidus.radiusTopRight.value().Value() < 0) {
323 raidus.radiusTopRight = dialogTheme_->GetRadius().GetX();
324 }
325 if (!raidus.radiusBottomLeft.has_value() || raidus.radiusBottomLeft.value().Value() < 0) {
326 raidus.radiusBottomLeft = dialogTheme_->GetRadius().GetX();
327 }
328 if (!raidus.radiusBottomRight.has_value() || raidus.radiusBottomRight.value().Value() < 0) {
329 raidus.radiusBottomRight = dialogTheme_->GetRadius().GetX();
330 }
331 }
332
CreateDialogScroll(const DialogProperties & dialogProps)333 RefPtr<FrameNode> DialogPattern::CreateDialogScroll(const DialogProperties& dialogProps)
334 {
335 auto scroll = FrameNode::CreateFrameNode(
336 V2::SCROLL_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<ScrollPattern>());
337 CHECK_NULL_RETURN(scroll, nullptr);
338 auto props = scroll->GetLayoutProperty<ScrollLayoutProperty>();
339 props->UpdateAxis(Axis::VERTICAL);
340 props->UpdateAlignment(Alignment::CENTER_LEFT);
341 // If title not exist, set scroll align center so that text align center.
342 auto scrollFlexAlign = dialogTheme_->GetScrollFlexAlign();
343 if ((dialogProps.title.empty() && dialogProps.subtitle.empty())) {
344 scrollFlexAlign = FlexAlign::CENTER;
345 }
346 props->UpdateAlignSelf(scrollFlexAlign);
347 return scroll;
348 }
349
BuildChild(const DialogProperties & props)350 void DialogPattern::BuildChild(const DialogProperties& props)
351 {
352 UpdatePropertyForElderly(props.buttons);
353 // append customNode
354 auto customNode = customNode_.Upgrade();
355 if (customNode) {
356 BuildCustomChild(props, customNode);
357 return;
358 }
359 // Make dialog Content Column
360 auto contentColumn = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
361 AceType::MakeRefPtr<LinearLayoutPattern>(true));
362 CHECK_NULL_VOID(contentColumn);
363 if (!props.title.empty() || !props.subtitle.empty()) {
364 auto title = BuildTitle(props);
365 CHECK_NULL_VOID(title);
366 titleContainer_ = title;
367 contentColumn->AddChild(title);
368 }
369
370 if (!props.content.empty()) {
371 auto content = BuildContent(props);
372 CHECK_NULL_VOID(content);
373 // create a scroll
374 auto scroll = CreateDialogScroll(props);
375 CHECK_NULL_VOID(scroll);
376 content->MountToParent(scroll);
377 scroll->MountToParent(contentColumn);
378 scroll->MarkModifyDone();
379 }
380
381 if (!props.customStyle) {
382 UpdateContentRenderContext(contentColumn, props);
383 if (props.height.has_value()) {
384 auto layoutProps = contentColumn->GetLayoutProperty<LinearLayoutProperty>();
385 CHECK_NULL_VOID(layoutProps);
386 layoutProps->UpdateMainAxisAlign(FlexAlign::SPACE_BETWEEN);
387 layoutProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
388 }
389 }
390
391 auto columnProp = AceType::DynamicCast<LinearLayoutProperty>(contentColumn->GetLayoutProperty());
392 CHECK_NULL_VOID(columnProp);
393 // content is full screen in Watch mode
394 auto measureType = dialogTheme_->GetColumnMeasureType();
395 columnProp->UpdateMeasureType(measureType);
396
397 // build ActionSheet child
398 if (props.type == DialogType::ACTION_SHEET && !props.sheetsInfo.empty()) {
399 auto sheetContainer = BuildSheet(props.sheetsInfo);
400 contentNodeMap_[DialogContentNode::SHEET] = sheetContainer;
401 CHECK_NULL_VOID(sheetContainer);
402 sheetContainer->MountToParent(contentColumn);
403 // scrollable
404 sheetContainer->MarkModifyDone();
405 }
406
407 // Make Menu node if hasMenu (actionMenu)
408 if (props.isMenu) {
409 bool hasTitle = !props.title.empty() || !props.subtitle.empty();
410 auto menu = BuildMenu(props.buttons, hasTitle);
411 CHECK_NULL_VOID(menu);
412 menu->MountToParent(contentColumn);
413 } else {
414 // build buttons
415 if (!props.buttons.empty()) {
416 auto buttonContainer = BuildButtons(props.buttons, props.buttonDirection);
417 CHECK_NULL_VOID(buttonContainer);
418 buttonContainer->MountToParent(contentColumn);
419 }
420 }
421
422 auto dialog = GetHost();
423 contentColumn->MountToParent(dialog);
424 UpdateTextFontScale();
425 if (isSuitableForElderly_ && NeedsButtonDirectionChange(props.buttons)) {
426 //remove buttonContainer when Button text is too long
427 contentColumn->RemoveChild(buttonContainer_);
428 auto buttonContainerNew = BuildButtons(props.buttons, DialogButtonDirection::VERTICAL);
429 buttonContainerNew->MountToParent(contentColumn);
430 buttonContainer_ = buttonContainerNew;
431 CheckScrollHeightIsNegative(contentColumn, props);
432 }
433 contentColumn_ = contentColumn;
434 UpdateTextFontScale();
435 }
436
BuildCustomChild(const DialogProperties & props,const RefPtr<UINode> & customNode)437 void DialogPattern::BuildCustomChild(const DialogProperties& props, const RefPtr<UINode>& customNode)
438 {
439 auto contentWrapper = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
440 AceType::MakeRefPtr<LinearLayoutPattern>(true));
441 CHECK_NULL_VOID(contentWrapper);
442 if (!props.customStyle) {
443 UpdateContentRenderContext(contentWrapper, props);
444 }
445 customNode->MountToParent(contentWrapper);
446 auto dialog = GetHost();
447 contentWrapper->MountToParent(dialog);
448 }
449
BuildMainTitle(const DialogProperties & dialogProperties)450 RefPtr<FrameNode> DialogPattern::BuildMainTitle(const DialogProperties& dialogProperties)
451 {
452 auto title = FrameNode::CreateFrameNode(
453 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
454 auto titleProp = AceType::DynamicCast<TextLayoutProperty>(title->GetLayoutProperty());
455 CHECK_NULL_RETURN(titleProp, nullptr);
456 titleProp->UpdateMaxLines(DIALOG_TITLE_MAXLINES);
457 titleProp->UpdateTextOverflow(TextOverflow::ELLIPSIS);
458 std::string titleContent = dialogProperties.title.empty() ? dialogProperties.subtitle : dialogProperties.title;
459 titleProp->UpdateContent(titleContent);
460 auto titleStyle = dialogTheme_->GetTitleTextStyle();
461 titleProp->UpdateFontSize(titleStyle.GetFontSize());
462 titleProp->UpdateFontWeight(titleStyle.GetFontWeight());
463 titleProp->UpdateTextColor(titleStyle.GetTextColor());
464 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
465 titleProp->UpdateAdaptMaxFontSize(dialogTheme_->GetTitleTextStyle().GetFontSize());
466 titleProp->UpdateAdaptMinFontSize(ADAPT_TITLE_MIN_FONT_SIZE);
467 titleProp->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
468 titleProp->UpdateMaxLines(ADAPT_TITLE_MAX_LINES);
469 }
470 PaddingProperty titlePadding;
471 auto paddingInTheme = (dialogProperties.content.empty() && dialogProperties.buttons.empty())
472 ? dialogTheme_->GetTitleDefaultPadding()
473 : dialogTheme_->GetTitleAdjustPadding();
474 titlePadding.left = CalcLength(paddingInTheme.Left());
475 titlePadding.right = CalcLength(paddingInTheme.Right());
476 if (!dialogProperties.title.empty() && !dialogProperties.subtitle.empty()) {
477 titlePadding.top = CalcLength(DIALOG_TWO_TITLE_SPACE);
478 titlePadding.bottom = CalcLength(DIALOG_TWO_TITLE_ZERO_SPACE);
479 } else {
480 auto padding =
481 DIALOG_ONE_TITLE_ALL_HEIGHT - Dimension(DIALOG_TITLE_CONTENT_HEIGHT.ConvertToVp(), DimensionUnit::VP);
482 titlePadding.top = CalcLength(padding / DIALOG_TITLE_AVE_BY_2);
483 titlePadding.bottom = CalcLength(padding / DIALOG_TITLE_AVE_BY_2);
484 }
485 titleProp->UpdatePadding(titlePadding);
486 // XTS inspector value
487 title_ = dialogProperties.title;
488 subtitle_ = dialogProperties.subtitle;
489 auto titleRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
490 AceType::MakeRefPtr<LinearLayoutPattern>(false));
491 CHECK_NULL_RETURN(titleRow, nullptr);
492 auto titleRowProps = titleRow->GetLayoutProperty<LinearLayoutProperty>();
493 CHECK_NULL_RETURN(titleRowProps, nullptr);
494 titleRowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
495 titleRowProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
496 title->MountToParent(titleRow);
497 title->MarkModifyDone();
498 contentNodeMap_[dialogProperties.title.empty() ? DialogContentNode::SUBTITLE : DialogContentNode::TITLE] = title;
499 return titleRow;
500 }
501
BuildSubTitle(const DialogProperties & dialogProperties)502 RefPtr<FrameNode> DialogPattern::BuildSubTitle(const DialogProperties& dialogProperties)
503 {
504 auto subtitle = FrameNode::CreateFrameNode(
505 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
506 auto titleProp = AceType::DynamicCast<TextLayoutProperty>(subtitle->GetLayoutProperty());
507 CHECK_NULL_RETURN(titleProp, nullptr);
508 auto titleStyle = dialogTheme_->GetSubTitleTextStyle();
509 titleProp->UpdateMaxLines(DIALOG_TITLE_MAXLINES);
510 titleProp->UpdateTextOverflow(TextOverflow::ELLIPSIS);
511 titleProp->UpdateContent(dialogProperties.subtitle);
512 titleProp->UpdateFontSize(titleStyle.GetFontSize());
513 titleProp->UpdateTextColor(titleStyle.GetTextColor());
514 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
515 titleProp->UpdateAdaptMaxFontSize(titleStyle.GetFontSize());
516 titleProp->UpdateAdaptMinFontSize(ADAPT_SUBTITLE_MIN_FONT_SIZE);
517 titleProp->UpdateHeightAdaptivePolicy(TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
518 titleProp->UpdateMaxLines(ADAPT_TITLE_MAX_LINES);
519 }
520 PaddingProperty titlePadding;
521 titlePadding.left = CalcLength(DIALOG_SUBTITLE_PADDING_LEFT);
522 titlePadding.right = CalcLength(DIALOG_SUBTITLE_PADDING_RIGHT);
523 titlePadding.top = CalcLength(DIALOG_TWO_TITLE_ZERO_SPACE);
524 titlePadding.bottom = CalcLength(DIALOG_TWO_TITLE_SPACE);
525 titleProp->UpdatePadding(titlePadding);
526
527 // XTS inspector value
528 subtitle_ = dialogProperties.subtitle;
529
530 auto subtitleRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
531 AceType::MakeRefPtr<LinearLayoutPattern>(false));
532 CHECK_NULL_RETURN(subtitleRow, nullptr);
533 auto subtitleRowProps = subtitleRow->GetLayoutProperty<LinearLayoutProperty>();
534 CHECK_NULL_RETURN(subtitleRowProps, nullptr);
535 subtitleRowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
536 subtitleRowProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
537 subtitle->MountToParent(subtitleRow);
538 subtitle->MarkModifyDone();
539 contentNodeMap_[DialogContentNode::SUBTITLE] = subtitle;
540 return subtitleRow;
541 }
542
BuildTitle(const DialogProperties & dialogProperties)543 RefPtr<FrameNode> DialogPattern::BuildTitle(const DialogProperties& dialogProperties)
544 {
545 auto titleRow = BuildMainTitle(dialogProperties);
546 if (!dialogProperties.title.empty() && !dialogProperties.subtitle.empty()) {
547 auto titleColumn = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG,
548 ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<LinearLayoutPattern>(true));
549 CHECK_NULL_RETURN(titleColumn, nullptr);
550 auto columnProps = titleColumn->GetLayoutProperty<LinearLayoutProperty>();
551 CHECK_NULL_RETURN(columnProps, nullptr);
552 columnProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
553 columnProps->UpdateMeasureType(MeasureType::MATCH_CONTENT);
554 auto subtitleRow = BuildSubTitle(dialogProperties);
555 titleColumn->AddChild(titleRow);
556 titleColumn->AddChild(subtitleRow);
557 return titleColumn;
558 }
559 return titleRow;
560 }
561
BuildContent(const DialogProperties & props)562 RefPtr<FrameNode> DialogPattern::BuildContent(const DialogProperties& props)
563 {
564 // Make Content node
565 auto contentNode = FrameNode::CreateFrameNode(
566 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
567 auto contentProp = AceType::DynamicCast<TextLayoutProperty>(contentNode->GetLayoutProperty());
568 CHECK_NULL_RETURN(contentProp, nullptr);
569 // textAlign always align start. When text line count 1 and title doesn't exist, set text center position.
570 contentProp->UpdateTextAlign(TextAlign::START);
571 contentProp->UpdateContent(props.content);
572 auto contentStyle = dialogTheme_->GetContentTextStyle();
573 contentProp->UpdateFontSize(contentStyle.GetFontSize());
574 contentProp->UpdateTextColor(contentStyle.GetTextColor());
575 // update padding
576 Edge contentPaddingInTheme;
577 PaddingProperty contentPadding;
578 if (!props.title.empty() || !props.subtitle.empty()) {
579 contentPaddingInTheme =
580 props.buttons.empty() ? dialogTheme_->GetDefaultPadding() : dialogTheme_->GetAdjustPadding();
581 contentPadding.top = CalcLength(DIALOG_CONTENT_PADDING_TOP);
582 } else {
583 contentPaddingInTheme =
584 props.buttons.empty() ? dialogTheme_->GetContentDefaultPadding() : dialogTheme_->GetContentAdjustPadding();
585 contentPadding.top = CalcLength(contentPaddingInTheme.Top());
586 }
587 contentPadding.left = CalcLength(contentPaddingInTheme.Left());
588 contentPadding.right = CalcLength(contentPaddingInTheme.Right());
589 contentPadding.bottom = CalcLength(contentPaddingInTheme.Bottom());
590 contentProp->UpdatePadding(contentPadding);
591
592 // XTS inspector value
593 message_ = props.content;
594 contentNode->MarkModifyDone();
595 contentNodeMap_[DialogContentNode::MESSAGE] = contentNode;
596 return contentNode;
597 }
598
599 // to close dialog when clicked, use button index in Prompt to trigger success callback
BindCloseCallBack(const RefPtr<GestureEventHub> & hub,int32_t buttonIdx)600 void DialogPattern::BindCloseCallBack(const RefPtr<GestureEventHub>& hub, int32_t buttonIdx)
601 {
602 auto host = GetHost();
603 auto closeCallback = [weak = WeakClaim(RawPtr(host)), buttonIdx](GestureEvent& /*info*/) {
604 auto dialog = weak.Upgrade();
605 CHECK_NULL_VOID(dialog);
606 dialog->GetPattern<DialogPattern>()->PopDialog(buttonIdx);
607 };
608
609 hub->AddClickEvent(AceType::MakeRefPtr<ClickEvent>(closeCallback));
610 }
611
ParseButtonFontColorAndBgColor(const ButtonInfo & params,std::string & textColor,std::optional<Color> & bgColor)612 void DialogPattern::ParseButtonFontColorAndBgColor(
613 const ButtonInfo& params, std::string& textColor, std::optional<Color>& bgColor)
614 {
615 // Parse Button Style
616 if (params.dlgButtonStyle.has_value()) {
617 switch (params.dlgButtonStyle.value()) {
618 case DialogButtonStyle::DEFAULT:
619 textColor = dialogTheme_->GetButtonDefaultFontColor().ColorToString();
620 bgColor = dialogTheme_->GetButtonDefaultBgColor();
621 break;
622 case DialogButtonStyle::HIGHTLIGHT:
623 textColor = dialogTheme_->GetButtonHighlightFontColor().ColorToString();
624 bgColor = dialogTheme_->GetButtonHighlightBgColor();
625 break;
626 default:
627 break;
628 }
629 }
630
631 // font color and background color
632 if (!params.textColor.empty()) {
633 textColor = params.textColor;
634 }
635 if (params.isBgColorSetted) {
636 bgColor = params.bgColor;
637 }
638
639 // Parse default focus
640 if (textColor.empty()) {
641 if (params.defaultFocus && isFirstDefaultFocus_) {
642 textColor = dialogTheme_->GetButtonHighlightFontColor().ColorToString();
643 } else {
644 textColor = dialogTheme_->GetButtonDefaultFontColor().ColorToString();
645 }
646 }
647 if (!bgColor.has_value()) {
648 if (params.defaultFocus && isFirstDefaultFocus_) {
649 bgColor = dialogTheme_->GetButtonHighlightBgColor();
650 isFirstDefaultFocus_ = false;
651 } else {
652 bgColor = dialogTheme_->GetButtonDefaultBgColor();
653 }
654 }
655 }
656
CreateButton(const ButtonInfo & params,int32_t index,bool isCancel,bool isVertical,int32_t length)657 RefPtr<FrameNode> DialogPattern::CreateButton(
658 const ButtonInfo& params, int32_t index, bool isCancel, bool isVertical, int32_t length)
659 {
660 auto buttonNode = FrameNode::CreateFrameNode(
661 V2::BUTTON_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<ButtonPattern>());
662 CHECK_NULL_RETURN(buttonNode, nullptr);
663 UpdateDialogButtonProperty(buttonNode, index, isVertical, length);
664 // parse button text color and background color
665 std::string textColor;
666 std::optional<Color> bgColor;
667 ParseButtonFontColorAndBgColor(params, textColor, bgColor);
668
669 // append text inside button
670 auto textNode = CreateButtonText(params.text, textColor);
671 CHECK_NULL_RETURN(textNode, nullptr);
672 textNode->MountToParent(buttonNode);
673 textNode->MarkModifyDone();
674 SetButtonEnabled(buttonNode, params.enabled);
675 auto hub = buttonNode->GetOrCreateGestureEventHub();
676 CHECK_NULL_RETURN(hub, nullptr);
677 // bind click event
678 if (params.action) {
679 hub->AddClickEvent(params.action);
680 }
681
682 if (params.isPrimary) {
683 auto focusHub = buttonNode->GetFocusHub();
684 CHECK_NULL_RETURN(focusHub, nullptr);
685 focusHub->SetIsDefaultFocus(params.isPrimary);
686 }
687
688 // to close dialog when clicked inside button rect
689 if (!isCancel) {
690 BindCloseCallBack(hub, index);
691 } else {
692 BindCloseCallBack(hub, -1);
693 }
694
695 // add scale animation
696 auto inputHub = buttonNode->GetOrCreateInputEventHub();
697 CHECK_NULL_RETURN(inputHub, nullptr);
698 inputHub->SetHoverEffect(HoverEffectType::AUTO);
699
700 // update background color
701 auto renderContext = buttonNode->GetRenderContext();
702 CHECK_NULL_RETURN(renderContext, nullptr);
703 renderContext->UpdateBackgroundColor(bgColor.value());
704
705 // set button default height
706 auto layoutProps = buttonNode->GetLayoutProperty();
707 CHECK_NULL_RETURN(layoutProps, nullptr);
708 auto pipeline = PipelineContext::GetCurrentContext();
709 CHECK_NULL_RETURN(pipeline, nullptr);
710 auto theme = pipeline->GetTheme<ButtonTheme>();
711 CHECK_NULL_RETURN(theme, nullptr);
712 if (!isSuitableForElderly_) {
713 layoutProps->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(theme->GetHeight())));
714 }
715 return buttonNode;
716 }
717
UpdateDialogButtonProperty(RefPtr<FrameNode> & buttonNode,int32_t index,bool isVertical,int32_t length)718 void DialogPattern::UpdateDialogButtonProperty(
719 RefPtr<FrameNode>& buttonNode, int32_t index, bool isVertical, int32_t length)
720 {
721 // update button padding
722 auto buttonProp = AceType::DynamicCast<ButtonLayoutProperty>(buttonNode->GetLayoutProperty());
723 buttonProp->UpdateType(ButtonType::NORMAL);
724 buttonProp->UpdateBorderRadius(BorderRadiusProperty(DIALOG_BUTTON_BORDER_RADIUS));
725 PaddingProperty buttonPadding;
726 buttonPadding.left = CalcLength(SHEET_LIST_PADDING);
727 buttonPadding.right = CalcLength(SHEET_LIST_PADDING);
728 buttonProp->UpdatePadding(buttonPadding);
729 if (!isVertical) {
730 // set flex grow to fill horizontal space
731 buttonProp->UpdateLayoutWeight(1);
732 buttonProp->UpdateFlexGrow(1.0);
733 buttonProp->UpdateFlexShrink(1.0);
734 if (isSuitableForElderly_ && index != 0) {
735 MarginProperty margin = {
736 .left = CalcLength(dialogTheme_->GetMarginLeft()),
737 };
738 buttonProp->UpdateMargin(margin);
739 }
740 } else if (isVertical && index != (length - 1)) {
741 // update button space in vertical
742 auto buttonSpace = dialogTheme_->GetMutiButtonPaddingVertical();
743 MarginProperty margin = {
744 .bottom = CalcLength(buttonSpace),
745 };
746 buttonProp->UpdateMargin(margin);
747 }
748 }
749
CreateDivider(const Dimension & dividerLength,const Dimension & dividerWidth,const Color & color,const Dimension & space)750 RefPtr<FrameNode> DialogPattern::CreateDivider(
751 const Dimension& dividerLength, const Dimension& dividerWidth, const Color& color, const Dimension& space)
752 {
753 auto dividerNode = FrameNode::CreateFrameNode(
754 V2::DIVIDER_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<DividerPattern>());
755 CHECK_NULL_RETURN(dividerNode, nullptr);
756 auto dividerProps = dividerNode->GetLayoutProperty<DividerLayoutProperty>();
757 CHECK_NULL_RETURN(dividerProps, nullptr);
758 dividerProps->UpdateVertical(true);
759 dividerProps->UpdateStrokeWidth(dividerWidth);
760 dividerProps->UpdateUserDefinedIdealSize(CalcSize(std::nullopt, CalcLength(dividerLength)));
761 auto dividerPaintProps = dividerNode->GetPaintProperty<DividerRenderProperty>();
762 CHECK_NULL_RETURN(dividerPaintProps, nullptr);
763 dividerPaintProps->UpdateDividerColor(color);
764 // add divider margin
765 MarginProperty margin = {
766 .left = CalcLength((space - dividerWidth) / 2),
767 .right = CalcLength((space - dividerWidth) / 2),
768 };
769 dividerProps->UpdateMargin(margin);
770 return dividerNode;
771 }
772
773 // alert dialog buttons
BuildButtons(const std::vector<ButtonInfo> & buttons,const DialogButtonDirection & direction)774 RefPtr<FrameNode> DialogPattern::BuildButtons(
775 const std::vector<ButtonInfo>& buttons, const DialogButtonDirection& direction)
776 {
777 auto Id = ElementRegister::GetInstance()->MakeUniqueId();
778 RefPtr<FrameNode> container;
779 bool isVertical;
780 if (direction == DialogButtonDirection::HORIZONTAL ||
781 (direction == DialogButtonDirection::AUTO && buttons.size() == TWO_BUTTON_MODE)) {
782 // use horizontal layout
783 isVertical = false;
784 container = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, Id, AceType::MakeRefPtr<LinearLayoutPattern>(false));
785 CHECK_NULL_RETURN(container, nullptr);
786 auto layoutProps = container->GetLayoutProperty<LinearLayoutProperty>();
787 layoutProps->UpdateMainAxisAlign(FlexAlign::SPACE_BETWEEN);
788 layoutProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
789 } else {
790 // use vertical layout
791 isVertical = true;
792 container = FrameNode::CreateFrameNode(V2::COLUMN_ETS_TAG, Id, AceType::MakeRefPtr<LinearLayoutPattern>(true));
793 auto layoutProps = container->GetLayoutProperty<LinearLayoutProperty>();
794 layoutProps->UpdateCrossAxisAlign(FlexAlign::STRETCH);
795 layoutProps->UpdateMeasureType(MeasureType::MATCH_PARENT_CROSS_AXIS);
796 }
797 CHECK_NULL_RETURN(container, nullptr);
798 // set action's padding
799 PaddingProperty actionPadding;
800 if (buttons.size() == ONE_BUTTON_MODE || isVertical) {
801 actionPadding.left = CalcLength(dialogTheme_->GetSingleButtonPaddingStart());
802 actionPadding.right = CalcLength(dialogTheme_->GetSingleButtonPaddingEnd());
803 } else {
804 actionPadding.left = CalcLength(dialogTheme_->GetMutiButtonPaddingStart());
805 actionPadding.right = CalcLength(dialogTheme_->GetMutiButtonPaddingEnd());
806 }
807 auto padding = dialogTheme_->GetActionsPadding();
808 actionPadding.top = CalcLength(dialogTheme_->GetButtonWithContentPadding());
809 actionPadding.bottom = CalcLength(dialogTheme_->GetButtonPaddingBottom());
810 container->GetLayoutProperty()->UpdatePadding(actionPadding);
811 AddButtonAndDivider(buttons, container, isVertical);
812 container->MarkModifyDone();
813 buttonContainer_ = container;
814 return container;
815 }
816
AddButtonAndDivider(const std::vector<ButtonInfo> & buttons,const RefPtr<NG::FrameNode> & container,bool isVertical)817 void DialogPattern::AddButtonAndDivider(
818 const std::vector<ButtonInfo>& buttons, const RefPtr<NG::FrameNode>& container, bool isVertical)
819 {
820 auto dividerLength = dialogTheme_->GetDividerLength();
821 auto dividerWidth = dialogTheme_->GetDividerBetweenButtonWidth_();
822 auto dividerColor = dialogTheme_->GetDividerColor();
823 auto buttonSpace = dialogTheme_->GetMutiButtonPaddingHorizontal();
824 auto length = buttons.size();
825 for (size_t i = 0; i < length; ++i) {
826 if (i != 0 && !isVertical && !isSuitableForElderly_) {
827 auto dividerNode = CreateDivider(dividerLength, dividerWidth, dividerColor, buttonSpace);
828 CHECK_NULL_VOID(dividerNode);
829 container->AddChild(dividerNode);
830 }
831 auto buttonNode = CreateButton(buttons[i], i, false, isVertical, length);
832 CHECK_NULL_VOID(buttonNode);
833 auto buttonPattern = buttonNode->GetPattern<ButtonPattern>();
834 CHECK_NULL_VOID(buttonPattern);
835 buttonPattern->SetSkipColorConfigurationUpdate();
836 buttonNode->MountToParent(container);
837 buttonNode->MarkModifyDone();
838 }
839 }
840
CreateButtonText(const std::string & text,const std::string & colorStr)841 RefPtr<FrameNode> DialogPattern::CreateButtonText(const std::string& text, const std::string& colorStr)
842 {
843 auto textNode = FrameNode::CreateFrameNode(
844 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
845 CHECK_NULL_RETURN(textNode, nullptr);
846 textNode->GetOrCreateFocusHub()->SetFocusable(true);
847 auto textProps = textNode->GetLayoutProperty<TextLayoutProperty>();
848 CHECK_NULL_RETURN(textProps, nullptr);
849 textProps->UpdateContent(text);
850 textProps->UpdateFontWeight(FontWeight::MEDIUM);
851 textProps->UpdateMaxLines(1);
852 textProps->UpdateTextOverflow(TextOverflow::ELLIPSIS);
853 Dimension buttonTextSize =
854 dialogTheme_->GetButtonTextSize().IsValid() ? dialogTheme_->GetButtonTextSize() : DIALOG_BUTTON_TEXT_SIZE;
855 textProps->UpdateFontSize(buttonTextSize);
856
857 // update text color
858 Color color;
859 if (Color::ParseColorString(colorStr, color)) {
860 textProps->UpdateTextColor(color);
861 } else {
862 textProps->UpdateTextColor(DEFAULT_BUTTON_COLOR);
863 }
864 return textNode;
865 }
866
BuildSheetItem(const ActionSheetInfo & item)867 RefPtr<FrameNode> DialogPattern::BuildSheetItem(const ActionSheetInfo& item)
868 {
869 // ListItem -> Row -> title + icon
870 auto Id = ElementRegister::GetInstance()->MakeUniqueId();
871 RefPtr<FrameNode> itemNode = FrameNode::CreateFrameNode(
872 V2::LIST_ITEM_ETS_TAG, Id, AceType::MakeRefPtr<ListItemPattern>(nullptr, V2::ListItemStyle::NONE));
873 CHECK_NULL_RETURN(itemNode, nullptr);
874
875 // update sheet row flex align
876 auto rowId = ElementRegister::GetInstance()->MakeUniqueId();
877 auto itemRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, rowId, AceType::MakeRefPtr<LinearLayoutPattern>(false));
878 CHECK_NULL_RETURN(itemRow, nullptr);
879 auto layoutProps = itemRow->GetLayoutProperty<LinearLayoutProperty>();
880 layoutProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
881 layoutProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
882
883 // mount icon
884 if (!item.icon.empty()) {
885 auto iconNode = BuildSheetInfoIcon(item.icon);
886 iconNode->MountToParent(itemRow);
887 iconNode->MarkModifyDone();
888 }
889
890 // mount title
891 if (!item.title.empty()) {
892 auto titleNode = BuildSheetInfoTitle(item.title);
893 titleNode->MountToParent(itemRow);
894 titleNode->MarkModifyDone();
895 }
896
897 // set sheetItem action
898 auto hub = itemRow->GetOrCreateGestureEventHub();
899 if (item.action) {
900 hub->AddClickEvent(item.action);
901 auto recordEvent = [weak = WeakClaim(this), title = item.title](GestureEvent& info) {
902 if (!Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
903 return;
904 }
905 auto pattern = weak.Upgrade();
906 CHECK_NULL_VOID(pattern);
907 Recorder::EventParamsBuilder builder;
908 builder.SetEventType(Recorder::EventType::DIALOG_SELECT)
909 .SetText(title)
910 .SetExtra(Recorder::KEY_TITLE, pattern->title_)
911 .SetExtra(Recorder::KEY_SUB_TITLE, pattern->subtitle_);
912 Recorder::EventRecorder::Get().OnEvent(std::move(builder));
913 };
914 auto recordEventPtr = MakeRefPtr<ClickEvent>(std::move(recordEvent));
915 hub->AddClickEvent(recordEventPtr);
916 }
917
918 // close dialog when clicked
919 BindCloseCallBack(hub, SHEET_INFO_IDX);
920 itemRow->MountToParent(itemNode);
921 return itemNode;
922 }
923
BuildSheetInfoTitle(const std::string & title)924 RefPtr<FrameNode> DialogPattern::BuildSheetInfoTitle(const std::string& title)
925 {
926 auto titleId = ElementRegister::GetInstance()->MakeUniqueId();
927 auto titleNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, titleId, AceType::MakeRefPtr<TextPattern>());
928 CHECK_NULL_RETURN(titleNode, nullptr);
929 // update text style
930 auto style = dialogTheme_->GetContentTextStyle();
931 auto props = titleNode->GetLayoutProperty<TextLayoutProperty>();
932 props->UpdateContent(title);
933 props->UpdateTextOverflow(TextOverflow::ELLIPSIS);
934 props->UpdateAdaptMaxFontSize(style.GetFontSize());
935 props->UpdateAdaptMinFontSize(dialogTheme_->GetTitleMinFontSize());
936 props->UpdateMaxLines(style.GetMaxLines());
937 props->UpdateFlexGrow(1.0f);
938 props->UpdateFlexShrink(1.0f);
939 return titleNode;
940 }
941
BuildSheetInfoIcon(const std::string & icon)942 RefPtr<FrameNode> DialogPattern::BuildSheetInfoIcon(const std::string& icon)
943 {
944 auto iconId = ElementRegister::GetInstance()->MakeUniqueId();
945 auto iconNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, iconId, AceType::MakeRefPtr<ImagePattern>());
946 CHECK_NULL_RETURN(iconNode, nullptr);
947 // add image margin
948 MarginProperty margin = {
949 .left = CalcLength(SHEET_IMAGE_MARGIN),
950 .right = CalcLength(SHEET_IMAGE_MARGIN),
951 .top = CalcLength(SHEET_IMAGE_MARGIN),
952 .bottom = CalcLength(SHEET_IMAGE_MARGIN),
953 };
954 auto iconProps = iconNode->GetLayoutProperty<ImageLayoutProperty>();
955 iconProps->UpdateMargin(margin);
956 auto imageSrc = ImageSourceInfo(icon);
957 iconProps->UpdateImageSourceInfo(imageSrc);
958 iconProps->UpdateUserDefinedIdealSize(CalcSize(SHEET_IMAGE_SIZE, SHEET_IMAGE_SIZE));
959 return iconNode;
960 }
961
BuildSheet(const std::vector<ActionSheetInfo> & sheets)962 RefPtr<FrameNode> DialogPattern::BuildSheet(const std::vector<ActionSheetInfo>& sheets)
963 {
964 auto listId = ElementRegister::GetInstance()->MakeUniqueId();
965 auto list = FrameNode::CreateFrameNode(V2::LIST_ETS_TAG, listId, AceType::MakeRefPtr<ListPattern>());
966 CHECK_NULL_RETURN(list, nullptr);
967
968 // set sheet padding
969 CalcLength padding(SHEET_LIST_PADDING.ConvertToPx());
970 PaddingProperty sheetPadding = {
971 .left = padding,
972 .right = padding,
973 .top = padding,
974 .bottom = padding,
975 };
976 list->GetLayoutProperty()->UpdatePadding(sheetPadding);
977 list->GetPaintProperty<ScrollablePaintProperty>()->UpdateScrollBarMode(DisplayMode::OFF);
978
979 for (auto&& item : sheets) {
980 auto itemNode = BuildSheetItem(item);
981 CHECK_NULL_RETURN(itemNode, nullptr);
982 list->AddChild(itemNode);
983 }
984
985 // set list divider
986 auto divider = V2::ItemDivider {
987 .strokeWidth = SHEET_DIVIDER_WIDTH,
988 .color = Color::GRAY,
989 };
990 auto props = list->GetLayoutProperty<ListLayoutProperty>();
991 props->UpdateDivider(divider);
992 props->UpdateListDirection(Axis::VERTICAL);
993 return list;
994 }
995
BuildMenu(const std::vector<ButtonInfo> & buttons,bool hasTitle)996 RefPtr<FrameNode> DialogPattern::BuildMenu(const std::vector<ButtonInfo>& buttons, bool hasTitle)
997 {
998 auto menu = FrameNode::CreateFrameNode(
999 V2::COLUMN_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), MakeRefPtr<LinearLayoutPattern>(true));
1000 menuNode_ = menu;
1001 // column -> button
1002 for (size_t i = 0; i < buttons.size(); ++i) {
1003 RefPtr<FrameNode> button;
1004 uint32_t val = buttons.size() > 0 ? buttons.size() - 1 : 0;
1005 if (i != val) {
1006 button = CreateButton(buttons[i], i);
1007 } else {
1008 button = CreateButton(buttons[i], i, true);
1009 }
1010 CHECK_NULL_RETURN(button, nullptr);
1011 auto props = DynamicCast<FrameNode>(button)->GetLayoutProperty();
1012 auto buttonRow = FrameNode::CreateFrameNode(V2::ROW_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(),
1013 AceType::MakeRefPtr<LinearLayoutPattern>(false));
1014 CHECK_NULL_RETURN(buttonRow, nullptr);
1015 auto buttonRowProps = buttonRow->GetLayoutProperty<LinearLayoutProperty>();
1016 CHECK_NULL_RETURN(buttonRowProps, nullptr);
1017 buttonRowProps->UpdateMainAxisAlign(FlexAlign::FLEX_START);
1018 buttonRowProps->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
1019
1020 button->MountToParent(buttonRow);
1021 button->MarkModifyDone();
1022 menu->AddChild(buttonRow);
1023 }
1024 auto menuProps = menu->GetLayoutProperty<LinearLayoutProperty>();
1025 CHECK_NULL_RETURN(menuProps, nullptr);
1026 PaddingProperty menuPadding;
1027 if (!hasTitle) {
1028 menuPadding.top = CalcLength(dialogTheme_->GetContentAdjustPadding().Top());
1029 }
1030 menuPadding.left = CalcLength(dialogTheme_->GetDefaultPadding().Left());
1031 menuPadding.right = CalcLength(dialogTheme_->GetDefaultPadding().Right());
1032 menuPadding.bottom = CalcLength(dialogTheme_->GetButtonPaddingBottom());
1033 menuProps->UpdatePadding(menuPadding);
1034 return menu;
1035 }
1036
RegisterOnKeyEvent(const RefPtr<FocusHub> & focusHub)1037 void DialogPattern::RegisterOnKeyEvent(const RefPtr<FocusHub>& focusHub)
1038 {
1039 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
1040 auto pattern = wp.Upgrade();
1041 CHECK_NULL_RETURN(pattern, false);
1042 return pattern->OnKeyEvent(event);
1043 };
1044 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
1045 }
1046
OnKeyEvent(const KeyEvent & event)1047 bool DialogPattern::OnKeyEvent(const KeyEvent& event)
1048 {
1049 if (event.action != KeyAction::DOWN) {
1050 return false;
1051 }
1052 return false;
1053 }
1054
InitFocusEvent(const RefPtr<FocusHub> & focusHub)1055 void DialogPattern::InitFocusEvent(const RefPtr<FocusHub>& focusHub)
1056 {
1057 auto onFocus = [wp = WeakClaim(this)]() {
1058 auto pattern = wp.Upgrade();
1059 CHECK_NULL_VOID(pattern);
1060 pattern->HandleFocusEvent();
1061 };
1062 focusHub->SetOnFocusInternal(std::move(onFocus));
1063
1064 auto onBlur = [wp = WeakClaim(this)]() {
1065 auto pattern = wp.Upgrade();
1066 CHECK_NULL_VOID(pattern);
1067 pattern->HandleBlurEvent();
1068 };
1069 focusHub->SetOnBlurInternal(std::move(onBlur));
1070 }
1071
HandleBlurEvent()1072 void DialogPattern::HandleBlurEvent()
1073 {
1074 CHECK_NULL_VOID(contentRenderContext_ && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE));
1075 auto defaultShadowOff = static_cast<ShadowStyle>(dialogTheme_->GetDefaultShadowOff());
1076 contentRenderContext_->UpdateBackShadow(dialogProperties_.shadow.value_or(Shadow::CreateShadow(defaultShadowOff)));
1077 }
1078
HandleFocusEvent()1079 void DialogPattern::HandleFocusEvent()
1080 {
1081 CHECK_NULL_VOID(contentRenderContext_ && Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TWELVE));
1082 auto defaultShadowOn = static_cast<ShadowStyle>(dialogTheme_->GetDefaultShadowOn());
1083 contentRenderContext_->UpdateBackShadow(dialogProperties_.shadow.value_or(Shadow::CreateShadow(defaultShadowOn)));
1084 }
1085
1086 // XTS inspector
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1087 void DialogPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1088 {
1089 /* no fixed attr below, just return */
1090 if (filter.IsFastFilter()) {
1091 return;
1092 }
1093 auto host = GetHost();
1094 CHECK_NULL_VOID(host);
1095 if (host->GetTag() == V2::ALERT_DIALOG_ETS_TAG || host->GetTag() == V2::ACTION_SHEET_DIALOG_ETS_TAG) {
1096 json->PutExtAttr("title", title_.c_str(), filter);
1097 json->PutExtAttr("subtitle", subtitle_.c_str(), filter);
1098 json->PutExtAttr("message", message_.c_str(), filter);
1099 }
1100 }
1101
OnColorConfigurationUpdate()1102 void DialogPattern::OnColorConfigurationUpdate()
1103 {
1104 auto host = GetHost();
1105 CHECK_NULL_VOID(host);
1106 auto context = host->GetContext();
1107 CHECK_NULL_VOID(context);
1108 auto dialogTheme = context->GetTheme<DialogTheme>();
1109 CHECK_NULL_VOID(dialogTheme);
1110 dialogTheme_ = dialogTheme;
1111 UpdateWrapperBackgroundStyle(host, dialogTheme);
1112 UpdateButtonsProperty();
1113 OnModifyDone();
1114 host->MarkDirtyNode();
1115 }
1116
UpdateAlignmentAndOffset()1117 void DialogPattern::UpdateAlignmentAndOffset()
1118 {
1119 auto host = GetHost();
1120 CHECK_NULL_VOID(host);
1121 auto props = host->GetLayoutProperty<DialogLayoutProperty>();
1122 CHECK_NULL_VOID(props);
1123 auto dialogProp = GetDialogProperties();
1124 props->UpdateDialogAlignment(dialogProp.alignment);
1125 props->UpdateDialogOffset(dialogProp.offset);
1126 }
1127
OnLanguageConfigurationUpdate()1128 void DialogPattern::OnLanguageConfigurationUpdate()
1129 {
1130 CHECK_NULL_VOID(dialogProperties_.onLanguageChange);
1131 dialogProperties_.onLanguageChange(dialogProperties_);
1132 UpdateAlignmentAndOffset();
1133 if (!dialogProperties_.title.empty() && contentNodeMap_.find(DialogContentNode::TITLE) != contentNodeMap_.end()) {
1134 UpdateNodeContent(contentNodeMap_[DialogContentNode::TITLE], dialogProperties_.title);
1135 title_ = dialogProperties_.title;
1136 }
1137
1138 if (!dialogProperties_.subtitle.empty() &&
1139 contentNodeMap_.find(DialogContentNode::SUBTITLE) != contentNodeMap_.end()) {
1140 UpdateNodeContent(contentNodeMap_[DialogContentNode::SUBTITLE], dialogProperties_.subtitle);
1141 subtitle_ = dialogProperties_.subtitle;
1142 }
1143
1144 if (!dialogProperties_.content.empty() &&
1145 contentNodeMap_.find(DialogContentNode::MESSAGE) != contentNodeMap_.end()) {
1146 UpdateNodeContent(contentNodeMap_[DialogContentNode::MESSAGE], dialogProperties_.content);
1147 message_ = dialogProperties_.content;
1148 }
1149
1150 if (!dialogProperties_.buttons.empty()) {
1151 UpdateButtonsProperty();
1152 }
1153
1154 if (dialogProperties_.type == DialogType::ACTION_SHEET) {
1155 UpdateSheetIconAndText();
1156 }
1157
1158 if (dialogProperties_.shadow.has_value()) {
1159 contentRenderContext_->UpdateBackShadow(dialogProperties_.shadow.value());
1160 }
1161
1162 if (dialogProperties_.borderWidth.has_value() &&
1163 contentNodeMap_.find(DialogContentNode::BORDERWIDTH) != contentNodeMap_.end()) {
1164 auto layoutProps = contentNodeMap_[DialogContentNode::BORDERWIDTH]->GetLayoutProperty<LinearLayoutProperty>();
1165 layoutProps->UpdateBorderWidth(dialogProperties_.borderWidth.value());
1166 contentRenderContext_->UpdateBorderWidth(dialogProperties_.borderWidth.value());
1167 }
1168
1169 if (dialogProperties_.borderColor.has_value()) {
1170 contentRenderContext_->UpdateBorderColor(dialogProperties_.borderColor.value());
1171 }
1172
1173 if (dialogProperties_.borderRadius.has_value()) {
1174 contentRenderContext_->UpdateBorderRadius(dialogProperties_.borderRadius.value());
1175 }
1176 }
1177
UpdateNodeContent(const RefPtr<FrameNode> & node,std::string & text)1178 void DialogPattern::UpdateNodeContent(const RefPtr<FrameNode>& node, std::string& text)
1179 {
1180 CHECK_NULL_VOID(node);
1181 auto layoutProps = AceType::DynamicCast<TextLayoutProperty>(node->GetLayoutProperty());
1182 CHECK_NULL_VOID(layoutProps);
1183 layoutProps->UpdateContent(text);
1184 node->MarkModifyDone();
1185 }
1186
UpdateSheetIconAndText()1187 void DialogPattern::UpdateSheetIconAndText()
1188 {
1189 if (dialogProperties_.sheetsInfo.empty()) {
1190 return;
1191 }
1192
1193 auto sheetContainer = contentNodeMap_[DialogContentNode::SHEET];
1194 CHECK_NULL_VOID(sheetContainer);
1195 int32_t sheetIndex = 0;
1196 for (const auto& sheet : sheetContainer->GetChildren()) {
1197 auto itemRow = DynamicCast<FrameNode>(sheet->GetFirstChild());
1198 CHECK_NULL_VOID(itemRow);
1199
1200 auto sheetInfo = dialogProperties_.sheetsInfo.at(sheetIndex);
1201 if (!sheetInfo.icon.empty()) {
1202 auto iconNode = DynamicCast<FrameNode>(itemRow->GetFirstChild());
1203 CHECK_NULL_VOID(iconNode);
1204 auto iconProps = iconNode->GetLayoutProperty<ImageLayoutProperty>();
1205 CHECK_NULL_VOID(iconProps);
1206 iconProps->UpdateImageSourceInfo(ImageSourceInfo(sheetInfo.icon));
1207 iconNode->MarkModifyDone();
1208 }
1209 if (!sheetInfo.title.empty()) {
1210 auto titleNode = DynamicCast<FrameNode>(itemRow->GetLastChild());
1211 CHECK_NULL_VOID(titleNode);
1212 auto titleProps = titleNode->GetLayoutProperty<TextLayoutProperty>();
1213 CHECK_NULL_VOID(titleProps);
1214 titleProps->UpdateContent(sheetInfo.title);
1215 titleNode->MarkModifyDone();
1216 }
1217 ++sheetIndex;
1218 }
1219 }
1220
UpdateButtonsProperty()1221 void DialogPattern::UpdateButtonsProperty()
1222 {
1223 CHECK_NULL_VOID(buttonContainer_);
1224 int32_t btnIndex = 0;
1225 isFirstDefaultFocus_ = true;
1226 for (const auto& buttonNode : buttonContainer_->GetChildren()) {
1227 if (buttonNode->GetTag() != V2::BUTTON_ETS_TAG) {
1228 continue;
1229 }
1230 auto buttonFrameNode = DynamicCast<FrameNode>(buttonNode);
1231 CHECK_NULL_VOID(buttonFrameNode);
1232 auto pattern = buttonFrameNode->GetPattern<ButtonPattern>();
1233 CHECK_NULL_VOID(pattern);
1234 pattern->SetSkipColorConfigurationUpdate();
1235 // parse button text color and background color
1236 std::string textColorStr;
1237 std::optional<Color> bgColor;
1238 ParseButtonFontColorAndBgColor(dialogProperties_.buttons[btnIndex], textColorStr, bgColor);
1239 // update background color
1240 auto renderContext = buttonFrameNode->GetRenderContext();
1241 CHECK_NULL_VOID(renderContext);
1242 renderContext->UpdateBackgroundColor(bgColor.value());
1243 auto buttonTextNode = DynamicCast<FrameNode>(buttonFrameNode->GetFirstChild());
1244 CHECK_NULL_VOID(buttonTextNode);
1245 auto buttonTextLayoutProperty = buttonTextNode->GetLayoutProperty<TextLayoutProperty>();
1246 CHECK_NULL_VOID(buttonTextLayoutProperty);
1247 Color textColor;
1248 Color::ParseColorString(textColorStr, textColor);
1249 buttonTextLayoutProperty->UpdateContent(dialogProperties_.buttons[btnIndex].text);
1250 buttonTextLayoutProperty->UpdateTextColor(textColor);
1251 buttonTextNode->MarkModifyDone();
1252 buttonTextNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1253 ++btnIndex;
1254 }
1255 }
1256
GetDialogContext()1257 PipelineContext* DialogPattern::GetDialogContext()
1258 {
1259 auto host = GetHost();
1260 CHECK_NULL_RETURN(host, nullptr);
1261 auto context = host->GetContext();
1262 CHECK_NULL_RETURN(context, nullptr);
1263 return context;
1264 }
1265
UpdatePropertyForElderly(const std::vector<ButtonInfo> & buttons)1266 void DialogPattern::UpdatePropertyForElderly(const std::vector<ButtonInfo>& buttons)
1267 {
1268 isSuitableForElderly_ = false;
1269 notAdapationAging_ = false;
1270 auto pipeline = PipelineContext::GetCurrentContext();
1271 CHECK_NULL_VOID(pipeline);
1272 auto windowManager = pipeline->GetWindowManager();
1273 CHECK_NULL_VOID(windowManager);
1274 auto dialogContext = GetDialogContext();
1275 CHECK_NULL_VOID(dialogContext);
1276 TAG_LOGI(AceLogTag::ACE_DIALOG, "dialog GetContext fontScale : %{public}f", dialogContext->GetFontScale());
1277 if (GreatOrEqual(dialogContext->GetFontScale(), dialogTheme_->GetMinFontScaleForElderly())) {
1278 if (pipeline->GetRootHeight() < dialogTheme_->GetDialogLandscapeHeightBoundary().ConvertToPx() &&
1279 windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_SPLIT_PRIMARY) {
1280 notAdapationAging_ = true;
1281 return;
1282 }
1283 deviceOrientation_ = SystemProperties::GetDeviceOrientation();
1284 if (buttons.size() >= THREE_BUTTON_MODE && deviceOrientation_ == DeviceOrientation::LANDSCAPE) {
1285 notAdapationAging_ = true;
1286 return;
1287 }
1288 fontScaleForElderly_ = dialogContext->GetFontScale();
1289 isSuitableForElderly_ = true;
1290 notAdapationAging_ = false;
1291 }
1292 }
1293
NeedsButtonDirectionChange(const std::vector<ButtonInfo> & buttons)1294 bool DialogPattern::NeedsButtonDirectionChange(const std::vector<ButtonInfo>& buttons)
1295 {
1296 CHECK_NULL_RETURN(buttonContainer_, false);
1297 if (buttons.size() == ONE_BUTTON_MODE || buttonContainer_->GetTag() != V2::ROW_ETS_TAG) {
1298 return false;
1299 }
1300 auto host = GetHost();
1301 CHECK_NULL_RETURN(host, false);
1302 auto props = host->GetLayoutProperty<DialogLayoutProperty>();
1303 CHECK_NULL_RETURN(props, false);
1304 auto buttonLayoutConstraint = props->GetLayoutConstraint();
1305 isSuitOldMeasure_ = true;
1306 host->Measure(buttonLayoutConstraint);
1307 isSuitOldMeasure_ = false;
1308 const auto& children = buttonContainer_->GetChildren();
1309 for (const auto& child : children) {
1310 if (child->GetTag() == V2::BUTTON_ETS_TAG) {
1311 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
1312 CHECK_NULL_RETURN(buttonNode, false);
1313 auto buttonTextNode = DynamicCast<FrameNode>(buttonNode->GetFirstChild());
1314 CHECK_NULL_RETURN(buttonTextNode, false);
1315 auto textGeometryNode = buttonTextNode->GetGeometryNode();
1316 CHECK_NULL_RETURN(textGeometryNode, false);
1317 auto textFarmeSize = textGeometryNode->GetFrameSize();
1318 auto textPattern = buttonTextNode->GetPattern<TextPattern>();
1319 CHECK_NULL_RETURN(textPattern, false);
1320 auto textDisplay = textPattern->GetTextForDisplay();
1321 auto textProps = buttonTextNode->GetLayoutProperty<TextLayoutProperty>();
1322 CHECK_NULL_RETURN(textProps, false);
1323 Dimension buttonTextSize = textProps->GetFontSize().value_or(dialogTheme_->GetButtonTextSize());
1324 MeasureContext measureContext;
1325 measureContext.textContent = textDisplay;
1326 measureContext.fontSize = buttonTextSize;
1327 auto dialogContext = GetDialogContext();
1328 CHECK_NULL_RETURN(dialogContext, false);
1329 if (isSuitableForElderly_ && dialogContext->GetFontScale() >= dialogTheme_->GetTitleMaxFontScale() &&
1330 SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE) {
1331 measureContext.fontSize =
1332 Dimension(buttonTextSize.Value() * dialogTheme_->GetTitleMaxFontScale(), DimensionUnit::VP);
1333 }
1334 auto fontweight = StringUtils::FontWeightToString(FontWeight::MEDIUM);
1335 measureContext.fontWeight = fontweight;
1336 Size measureSize = MeasureUtil::MeasureTextSize(measureContext);
1337 if (measureSize.Width() != textFarmeSize.Width()) {
1338 return true;
1339 }
1340 }
1341 }
1342 return false;
1343 }
1344
CheckScrollHeightIsNegative(const RefPtr<UINode> & contentColumn,const DialogProperties & Dialogprops)1345 void DialogPattern::CheckScrollHeightIsNegative(
1346 const RefPtr<UINode>& contentColumn, const DialogProperties& Dialogprops)
1347 {
1348 CHECK_NULL_VOID(buttonContainer_);
1349 if (Dialogprops.buttons.size() == ONE_BUTTON_MODE || buttonContainer_->GetTag() == V2::ROW_ETS_TAG) {
1350 return;
1351 }
1352 auto host = GetHost();
1353 CHECK_NULL_VOID(host);
1354 auto props = host->GetLayoutProperty<DialogLayoutProperty>();
1355 CHECK_NULL_VOID(props);
1356 auto buttonLayoutConstraint = props->GetLayoutConstraint();
1357 isSuitOldMeasure_ = true;
1358 host->Measure(buttonLayoutConstraint);
1359 isSuitOldMeasure_ = false;
1360 if (isScrollHeightNegative_) {
1361 isSuitableForElderly_ = false;
1362 notAdapationAging_ = true;
1363 contentColumn->RemoveChild(buttonContainer_);
1364 auto buttonContainerNew = BuildButtons(Dialogprops.buttons, Dialogprops.buttonDirection);
1365 buttonContainerNew->MountToParent(contentColumn);
1366 buttonContainer_ = buttonContainerNew;
1367 }
1368 }
1369
UpdateDeviceOrientation(const DeviceOrientation & deviceOrientation)1370 void DialogPattern::UpdateDeviceOrientation(const DeviceOrientation& deviceOrientation)
1371 {
1372 if (deviceOrientation_ != deviceOrientation) {
1373 CHECK_NULL_VOID(buttonContainer_);
1374 OnFontConfigurationUpdate();
1375 auto host = GetHost();
1376 CHECK_NULL_VOID(host);
1377 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1378 deviceOrientation_ = deviceOrientation;
1379 }
1380 }
1381
UpdateTitleTextFontScale()1382 void DialogPattern::UpdateTitleTextFontScale()
1383 {
1384 CHECK_NULL_VOID(titleContainer_);
1385 auto scale = dialogTheme_->GetMinFontScaleForElderly();
1386 if (isSuitableForElderly_) {
1387 scale = dialogTheme_->GetTitleMaxFontScale();
1388 }
1389 if (titleContainer_->GetTag() == V2::COLUMN_ETS_TAG) {
1390 auto children = titleContainer_->GetChildren();
1391 for (const auto& child : children) {
1392 auto textNode = AceType::DynamicCast<FrameNode>(child->GetChildAtIndex(START_CHILD_INDEX));
1393 CHECK_NULL_VOID(textNode);
1394 auto titleProp = AceType::DynamicCast<TextLayoutProperty>(textNode->GetLayoutProperty());
1395 CHECK_NULL_VOID(titleProp);
1396 if (notAdapationAging_) {
1397 titleProp->UpdateMaxFontScale(dialogTheme_->GetDialogDefaultScale());
1398 } else {
1399 titleProp->UpdateMaxFontScale(scale);
1400 titleProp->UpdateMaxLines(ADAPT_TITLE_MAX_LINES);
1401 }
1402 }
1403 } else {
1404 auto textNode = AceType::DynamicCast<FrameNode>(titleContainer_->GetChildAtIndex(START_CHILD_INDEX));
1405 CHECK_NULL_VOID(textNode);
1406 auto titleProp = AceType::DynamicCast<TextLayoutProperty>(textNode->GetLayoutProperty());
1407 CHECK_NULL_VOID(titleProp);
1408 if (notAdapationAging_) {
1409 titleProp->UpdateMaxFontScale(dialogTheme_->GetDialogDefaultScale());
1410 } else {
1411 titleProp->UpdateMaxFontScale(scale);
1412 titleProp->UpdateMaxLines(ADAPT_TITLE_MAX_LINES);
1413 }
1414 }
1415 }
1416
UpdateTextFontScale()1417 void DialogPattern::UpdateTextFontScale()
1418 {
1419 UpdateTitleTextFontScale();
1420 CHECK_NULL_VOID(contentNodeMap_[DialogContentNode::MESSAGE]);
1421 auto scale = dialogTheme_->GetMinFontScaleForElderly();
1422 auto contentProp =
1423 AceType::DynamicCast<TextLayoutProperty>(contentNodeMap_[DialogContentNode::MESSAGE]->GetLayoutProperty());
1424 CHECK_NULL_VOID(contentProp);
1425 if (isSuitableForElderly_) {
1426 scale = SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE
1427 ? dialogTheme_->GetContentLandscapeMaxFontScale()
1428 : dialogTheme_->GetContentMaxFontScale();
1429 }
1430 if (notAdapationAging_) {
1431 contentProp->UpdateMaxFontScale(dialogTheme_->GetDialogDefaultScale());
1432 } else {
1433 contentProp->UpdateMaxFontScale(scale);
1434 }
1435 CHECK_NULL_VOID(buttonContainer_);
1436 MarginProperty margin;
1437 if (isSuitableForElderly_) {
1438 scale = SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE
1439 ? dialogTheme_->GetButtonLandscapeMaxFontScale()
1440 : dialogTheme_->GetButtonMaxFontScale();
1441 margin.top = CalcLength(8.0_vp);
1442 margin.bottom = CalcLength(8.0_vp);
1443 }
1444 const auto& children = buttonContainer_->GetChildren();
1445 for (const auto& child : children) {
1446 if (child->GetTag() == V2::BUTTON_ETS_TAG) {
1447 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
1448 CHECK_NULL_VOID(buttonNode);
1449 auto buttonTextNode = DynamicCast<FrameNode>(buttonNode->GetFirstChild());
1450 CHECK_NULL_VOID(buttonTextNode);
1451 auto textProp = AceType::DynamicCast<TextLayoutProperty>(buttonTextNode->GetLayoutProperty());
1452 CHECK_NULL_VOID(textProp);
1453 if (notAdapationAging_) {
1454 textProp->UpdateMaxFontScale(dialogTheme_->GetDialogDefaultScale());
1455 } else {
1456 textProp->UpdateMaxFontScale(scale);
1457 }
1458 if (isSuitableForElderly_) {
1459 textProp->UpdateMargin(margin);
1460 }
1461 }
1462 }
1463 }
1464
UpdateFontScale()1465 void DialogPattern::UpdateFontScale()
1466 {
1467 auto dialogContext = GetDialogContext();
1468 CHECK_NULL_VOID(dialogContext);
1469 if (dialogContext->GetFontScale() != fontScaleForElderly_) {
1470 OnFontConfigurationUpdate();
1471 auto host = GetHost();
1472 CHECK_NULL_VOID(host);
1473 host->MarkModifyDone();
1474 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1475 fontScaleForElderly_ = dialogContext->GetFontScale();
1476 }
1477 }
1478
SetButtonEnabled(const RefPtr<FrameNode> & buttonNode,bool enabled)1479 void DialogPattern::SetButtonEnabled(const RefPtr<FrameNode>& buttonNode, bool enabled)
1480 {
1481 // set Enabled and Focusable
1482 auto buttonButtonEvent = buttonNode->GetEventHub<ButtonEventHub>();
1483 CHECK_NULL_VOID(buttonButtonEvent);
1484 buttonButtonEvent->SetEnabled(enabled);
1485 buttonNode->GetOrCreateFocusHub()->SetFocusable(enabled);
1486 }
1487
UpdateWrapperBackgroundStyle(const RefPtr<FrameNode> & host,const RefPtr<DialogTheme> & dialogTheme)1488 void DialogPattern::UpdateWrapperBackgroundStyle(const RefPtr<FrameNode>& host, const RefPtr<DialogTheme>& dialogTheme)
1489 {
1490 auto col = DynamicCast<FrameNode>(host->GetChildAtIndex(START_CHILD_INDEX));
1491 CHECK_NULL_VOID(col);
1492 auto colRenderContext = col->GetRenderContext();
1493 CHECK_NULL_VOID(colRenderContext);
1494 if (!dialogProperties_.customStyle && !dialogProperties_.backgroundColor.has_value() &&
1495 (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) || !colRenderContext->IsUniRenderEnabled() ||
1496 !dialogProperties_.isSysBlurStyle)) {
1497 colRenderContext->UpdateBackgroundColor(dialogTheme->GetBackgroundColor());
1498 }
1499 if (colRenderContext->GetBackBlurStyle().has_value()) {
1500 colRenderContext->UpdateBackBlurStyle(colRenderContext->GetBackBlurStyle());
1501 }
1502 }
1503
DumpInfo()1504 void DialogPattern::DumpInfo()
1505 {
1506 DumpLog::GetInstance().AddDesc("Type: " + DialogTypeUtils::ConvertDialogTypeToString(dialogProperties_.type));
1507 if (!dialogProperties_.title.empty()) {
1508 DumpLog::GetInstance().AddDesc("Title: " + dialogProperties_.title);
1509 }
1510 if (!dialogProperties_.subtitle.empty()) {
1511 DumpLog::GetInstance().AddDesc("Subtitle: " + dialogProperties_.subtitle);
1512 }
1513 if (!dialogProperties_.content.empty()) {
1514 DumpLog::GetInstance().AddDesc("Content: " + dialogProperties_.content);
1515 }
1516 DumpLog::GetInstance().AddDesc(
1517 "DialogButtonDirection: " +
1518 DialogButtonDirectionUtils::ConvertDialogButtonDirectionToString(dialogProperties_.buttonDirection));
1519 if (dialogProperties_.width.has_value()) {
1520 DumpLog::GetInstance().AddDesc("Width: " + dialogProperties_.width.value().ToString());
1521 }
1522 if (dialogProperties_.height.has_value()) {
1523 DumpLog::GetInstance().AddDesc("Height: " + dialogProperties_.height.value().ToString());
1524 }
1525 if (dialogProperties_.backgroundBlurStyle.has_value()) {
1526 DumpLog::GetInstance().AddDesc(
1527 "BackgroundBlurStyle: " + std::to_string(dialogProperties_.backgroundBlurStyle.value()));
1528 }
1529 if (dialogProperties_.borderWidth.has_value()) {
1530 DumpLog::GetInstance().AddDesc("BorderWidth: " + dialogProperties_.borderWidth.value().ToString());
1531 }
1532 if (dialogProperties_.borderColor.has_value()) {
1533 DumpLog::GetInstance().AddDesc("BorderColor: " + dialogProperties_.borderColor.value().ToString());
1534 }
1535 if (dialogProperties_.backgroundColor.has_value()) {
1536 DumpLog::GetInstance().AddDesc("BackgroundColor: " + dialogProperties_.backgroundColor.value().ToString());
1537 }
1538 if (dialogProperties_.borderRadius.has_value()) {
1539 DumpLog::GetInstance().AddDesc("BorderRadius: " + dialogProperties_.borderRadius.value().ToString());
1540 }
1541 DumpBoolProperty();
1542 DumpObjectProperty();
1543 }
1544
DumpBoolProperty()1545 void DialogPattern::DumpBoolProperty()
1546 {
1547 DumpLog::GetInstance().AddDesc("AutoCancel: " + GetBoolStr(dialogProperties_.autoCancel));
1548 DumpLog::GetInstance().AddDesc("CustomStyle: " + GetBoolStr(dialogProperties_.customStyle));
1549 DumpLog::GetInstance().AddDesc("IsMenu: " + GetBoolStr(dialogProperties_.isMenu));
1550 DumpLog::GetInstance().AddDesc("IsMask: " + GetBoolStr(dialogProperties_.isMask));
1551 DumpLog::GetInstance().AddDesc("IsModal: " + GetBoolStr(dialogProperties_.isModal));
1552 DumpLog::GetInstance().AddDesc("IsScenceBoardDialog: " + GetBoolStr(dialogProperties_.isScenceBoardDialog));
1553 DumpLog::GetInstance().AddDesc("IsSysBlurStyle: " + GetBoolStr(dialogProperties_.isSysBlurStyle));
1554 DumpLog::GetInstance().AddDesc("IsShowInSubWindow: " + GetBoolStr(dialogProperties_.isShowInSubWindow));
1555 }
1556
DumpObjectProperty()1557 void DialogPattern::DumpObjectProperty()
1558 {
1559 DumpLog::GetInstance().AddDesc(
1560 "Alignment: " + DialogAlignmentUtils::ConvertDialogAlignmentToString(dialogProperties_.alignment));
1561 DumpLog::GetInstance().AddDesc("Offset: { dx: " + dialogProperties_.offset.GetX().ToString() +
1562 " dy: " + dialogProperties_.offset.GetY().ToString() + " }");
1563 if (dialogProperties_.buttons.size() > 0) {
1564 std::stringstream butonInfoSteam;
1565 butonInfoSteam << "Buttons: [";
1566 for (auto buttonInfo : dialogProperties_.buttons) {
1567 butonInfoSteam << "{ text: " << buttonInfo.text << " , color: " << buttonInfo.textColor << " }, ";
1568 }
1569 butonInfoSteam << "]";
1570 DumpLog::GetInstance().AddDesc(butonInfoSteam.str());
1571 }
1572 if (dialogProperties_.shadow.has_value()) {
1573 auto shadow = dialogProperties_.shadow.value();
1574 std::stringstream butonInfoSteam;
1575 static const int32_t precision = 2;
1576 butonInfoSteam << "Shadow: {";
1577 butonInfoSteam << " radius:" << std::fixed << std::setprecision(precision) << shadow.GetBlurRadius();
1578 butonInfoSteam << " style:" << std::to_string(static_cast<int32_t>(shadow.GetStyle()));
1579 butonInfoSteam << " type:" << std::to_string(static_cast<int32_t>(shadow.GetShadowType()));
1580 butonInfoSteam << " fill:" << GetBoolStr(shadow.GetIsFilled());
1581 butonInfoSteam << " offset:" << shadow.GetOffset().ToString();
1582 butonInfoSteam << " }";
1583 DumpLog::GetInstance().AddDesc(butonInfoSteam.str());
1584 }
1585 if (dialogProperties_.maskColor.has_value()) {
1586 DumpLog::GetInstance().AddDesc("MaskColor: " + dialogProperties_.maskColor.value().ToString());
1587 }
1588 if (dialogProperties_.maskRect.has_value()) {
1589 DumpLog::GetInstance().AddDesc("MaskRect: " + dialogProperties_.maskRect.value().ToString());
1590 }
1591 }
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)1592 void DialogPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
1593 {
1594 if (isFoldStatusChanged_ || type == WindowSizeChangeReason::ROTATION || type == WindowSizeChangeReason::RESIZE) {
1595 auto host = GetHost();
1596 CHECK_NULL_VOID(host);
1597 InitHostWindowRect();
1598 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1599 isFoldStatusChanged_ = false;
1600 }
1601 }
1602
InitHostWindowRect()1603 void DialogPattern::InitHostWindowRect()
1604 {
1605 if (!dialogProperties_.isShowInSubWindow) {
1606 isUIExtensionSubWindow_ = false;
1607 hostWindowRect_.Reset();
1608 return;
1609 }
1610
1611 auto currentId = Container::CurrentId();
1612 auto container = Container::Current();
1613 CHECK_NULL_VOID(container);
1614 if (container->IsSubContainer()) {
1615 currentId = SubwindowManager::GetInstance()->GetParentContainerId(currentId);
1616 container = AceEngine::Get().GetContainer(currentId);
1617 CHECK_NULL_VOID(container);
1618 }
1619
1620 if (container->IsUIExtensionWindow()) {
1621 isUIExtensionSubWindow_ = true;
1622 auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(currentId);
1623 CHECK_NULL_VOID(subwindow);
1624 auto rect = subwindow->GetUIExtensionHostWindowRect();
1625 hostWindowRect_ = RectF(rect.Left(), rect.Top(), rect.Width(), rect.Height());
1626 }
1627 }
1628
DumpSimplifyInfo(std::unique_ptr<JsonValue> & json)1629 void DialogPattern::DumpSimplifyInfo(std::unique_ptr<JsonValue>& json)
1630 {
1631 json->Put("Type", DialogTypeUtils::ConvertDialogTypeToString(dialogProperties_.type).c_str());
1632 if (!dialogProperties_.title.empty()) {
1633 json->Put("Title", dialogProperties_.title.c_str());
1634 }
1635 if (!dialogProperties_.subtitle.empty()) {
1636 json->Put("Subtitle", dialogProperties_.subtitle.c_str());
1637 }
1638 if (!dialogProperties_.content.empty()) {
1639 json->Put("Content", dialogProperties_.content.c_str());
1640 }
1641 if (dialogProperties_.buttonDirection != DialogButtonDirection::AUTO) {
1642 json->Put("ButtonDirection",
1643 DialogButtonDirectionUtils::ConvertDialogButtonDirectionToString(
1644 dialogProperties_.buttonDirection).c_str());
1645 }
1646 if (dialogProperties_.backgroundBlurStyle.has_value() && dialogProperties_.backgroundBlurStyle.value() != 0) {
1647 json->Put("BackgroundBlurStyle", std::to_string(dialogProperties_.backgroundBlurStyle.value()).c_str());
1648 }
1649 if (dialogProperties_.backgroundColor.value_or(Color::TRANSPARENT) != Color::TRANSPARENT) {
1650 json->Put("BackgroundColor", dialogProperties_.backgroundColor.value_or(Color::TRANSPARENT).ToString().c_str());
1651 }
1652 DumpSimplifySizeProperty(json);
1653 DumpSimplifyBorderProperty(json);
1654 DumpSimplifyBoolProperty(json);
1655 DumpSimplifyObjectProperty(json);
1656 }
1657
DumpSimplifyBorderProperty(std::unique_ptr<JsonValue> & json)1658 void DialogPattern::DumpSimplifyBorderProperty(std::unique_ptr<JsonValue>& json)
1659 {
1660 if (dialogProperties_.borderWidth.has_value()) {
1661 auto border = dialogProperties_.borderWidth.value();
1662 DimensionUnit unit = border.leftDimen.value_or(
1663 border.topDimen.value_or(border.rightDimen.value_or(border.bottomDimen.value_or(Dimension())))).Unit();
1664 Dimension defaultValue(0, unit);
1665 BorderWidthProperty defaultBorder = { defaultValue, defaultValue, defaultValue, defaultValue };
1666 if (!(border == defaultBorder)) {
1667 json->Put("BorderWidth", border.ToString().c_str());
1668 }
1669 }
1670 if (dialogProperties_.borderColor.has_value()) {
1671 auto color = dialogProperties_.borderColor.value();
1672 BorderColorProperty defaultValue = { Color::BLACK, Color::BLACK, Color::BLACK, Color::BLACK };
1673 if (!(color == defaultValue)) {
1674 json->Put("BorderColor", color.ToString().c_str());
1675 }
1676 }
1677 if (dialogProperties_.borderRadius.has_value()) {
1678 auto radius = dialogProperties_.borderRadius.value();
1679 DimensionUnit unit = radius.radiusTopLeft.value_or(radius.radiusTopRight.value_or(
1680 radius.radiusTopLeft.value_or(radius.radiusBottomLeft.value_or(
1681 radius.radiusBottomRight.value_or(radius.radiusTopStart.value_or(radius.radiusTopEnd.value_or(
1682 radius.radiusBottomStart.value_or(radius.radiusBottomEnd.value_or(Dimension()))))))))).Unit();
1683 Dimension defaultValue(0, unit);
1684 BorderRadiusProperty defaultRadius(defaultValue);
1685 if (!(radius == defaultRadius)) {
1686 json->Put("BorderRadius", dialogProperties_.borderRadius.value().ToString().c_str());
1687 }
1688 }
1689 }
1690
DumpSimplifySizeProperty(std::unique_ptr<JsonValue> & json)1691 void DialogPattern::DumpSimplifySizeProperty(std::unique_ptr<JsonValue>& json)
1692 {
1693 if (dialogProperties_.width.has_value() || dialogProperties_.height.has_value()) {
1694 DimensionUnit unit = dialogProperties_.width.has_value() ?
1695 dialogProperties_.width.value().Unit() : dialogProperties_.height.value().Unit();
1696 CalcDimension defaultCalcDimen(0, unit);
1697 if (dialogProperties_.width.value_or(defaultCalcDimen) != defaultCalcDimen &&
1698 dialogProperties_.height.value_or(defaultCalcDimen) != defaultCalcDimen) {
1699 json->Put("Width", dialogProperties_.width.value_or(defaultCalcDimen).ToString().c_str());
1700 json->Put("Height", dialogProperties_.height.value_or(defaultCalcDimen).ToString().c_str());
1701 }
1702 }
1703 }
1704
DumpSimplifyBoolProperty(std::unique_ptr<JsonValue> & json)1705 void DialogPattern::DumpSimplifyBoolProperty(std::unique_ptr<JsonValue>& json)
1706 {
1707 if (dialogProperties_.autoCancel) {
1708 json->Put("AutoCancel", GetBoolStr(dialogProperties_.autoCancel).c_str());
1709 }
1710 if (dialogProperties_.customStyle) {
1711 json->Put("CustomStyle", GetBoolStr(dialogProperties_.customStyle).c_str());
1712 }
1713 if (dialogProperties_.isMenu) {
1714 json->Put("IsMenu", GetBoolStr(dialogProperties_.isMenu).c_str());
1715 }
1716 if (dialogProperties_.isMask) {
1717 json->Put("IsMask", GetBoolStr(dialogProperties_.isMask).c_str());
1718 }
1719 if (dialogProperties_.isModal) {
1720 json->Put("IsModal", GetBoolStr(dialogProperties_.isModal).c_str());
1721 }
1722 if (dialogProperties_.isScenceBoardDialog) {
1723 json->Put("IsScenceBoardDialog", GetBoolStr(dialogProperties_.isScenceBoardDialog).c_str());
1724 }
1725 if (dialogProperties_.isSysBlurStyle) {
1726 json->Put("IsSysBlurStyle", GetBoolStr(dialogProperties_.isSysBlurStyle).c_str());
1727 }
1728 if (dialogProperties_.isShowInSubWindow) {
1729 json->Put("IsShowInSubWindow", GetBoolStr(dialogProperties_.isShowInSubWindow).c_str());
1730 }
1731 }
1732
DumpSimplifyObjectProperty(std::unique_ptr<JsonValue> & json)1733 void DialogPattern::DumpSimplifyObjectProperty(std::unique_ptr<JsonValue>& json)
1734 {
1735 json->Put("Alignment", DialogAlignmentUtils::ConvertDialogAlignmentToString(dialogProperties_.alignment).c_str());
1736 std::stringstream stream;
1737 stream << dialogProperties_.offset.GetX().ToString() << "," << dialogProperties_.offset.GetY().ToString();
1738 json->Put("Offset", stream.str().c_str());
1739 if (!dialogProperties_.buttons.empty()) {
1740 std::unique_ptr<JsonValue> buttons = JsonUtil::Create(true);
1741 int32_t index = -1;
1742 for (const auto& buttonInfo : dialogProperties_.buttons) {
1743 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
1744 child->Put("Text", buttonInfo.text.c_str());
1745 child->Put("Color", buttonInfo.textColor.c_str());
1746 index++;
1747 std::string key = "Button" + std::to_string(index);
1748 buttons->PutRef(key.c_str(), std::move(child));
1749 }
1750 json->PutRef("Buttons", std::move(buttons));
1751 }
1752 if (dialogProperties_.shadow.has_value()) {
1753 auto shadow = dialogProperties_.shadow.value();
1754 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
1755
1756 child->Put("Radius", shadow.GetBlurRadius());
1757 child->Put("Style", static_cast<int32_t>(shadow.GetStyle()));
1758 child->Put("Type", static_cast<int32_t>(shadow.GetShadowType()));
1759 child->Put("Fill", GetBoolStr(shadow.GetIsFilled()).c_str());
1760 child->Put("Offset", shadow.GetOffset().ToString().c_str());
1761 json->PutRef("Shadow", std::move(child));
1762 }
1763 if (dialogProperties_.maskColor.has_value()) {
1764 json->Put("MaskColor", dialogProperties_.maskColor.value().ToString().c_str());
1765 }
1766 if (dialogProperties_.maskRect.has_value()) {
1767 json->Put("MaskRect", dialogProperties_.maskRect.value().ToString().c_str());
1768 }
1769 }
1770 } // namespace OHOS::Ace::NG
1771