1 /*
2 * Copyright (c) 2024 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_ng/pattern/navigation/navigation_title_util.h"
17
18 #include <algorithm>
19
20 #include "base/i18n/localization.h"
21 #include "core/common/ace_application_info.h"
22 #include "core/common/agingadapation/aging_adapation_dialog_theme.h"
23 #include "core/common/agingadapation/aging_adapation_dialog_util.h"
24 #include "core/common/container.h"
25 #include "core/components_ng/base/view_abstract.h"
26 #include "core/components_ng/pattern/bubble/bubble_pattern.h"
27 #include "core/components_ng/pattern/button/button_layout_property.h"
28 #include "core/components_ng/pattern/button/button_pattern.h"
29 #include "core/components_ng/pattern/grid/grid_pattern.h"
30 #include "core/components_ng/pattern/image/image_layout_property.h"
31 #include "core/components_ng/pattern/image/image_pattern.h"
32 #include "core/components_ng/pattern/menu/menu_view.h"
33 #include "core/components_ng/pattern/menu/wrapper/menu_wrapper_pattern.h"
34 #include "core/components_ng/pattern/navigation/bar_item_event_hub.h"
35 #include "core/components_ng/pattern/navigation/bar_item_pattern.h"
36 #include "core/components_ng/pattern/navigation/nav_bar_pattern.h"
37 #include "core/components_ng/pattern/navigation/navdestination_node_base.h"
38 #include "core/components_ng/pattern/navigation/navdestination_pattern_base.h"
39 #include "core/components_ng/pattern/navigation/navigation_pattern.h"
40 #include "core/components_ng/pattern/navigation/title_bar_node.h"
41 #include "core/components_ng/pattern/navigation/title_bar_pattern.h"
42 #include "core/components_ng/pattern/navigation/tool_bar_node.h"
43 #include "core/components_ng/pattern/text/text_pattern.h"
44
45 namespace OHOS::Ace::NG {
46 namespace {
47 constexpr Dimension TITLEBAR_VERTICAL_PADDING = 56.0_vp;
48 constexpr int32_t TITLEBAR_OPACITY_ANIMATION_DURATION = 120;
49 const RefPtr<CubicCurve> TITLEBAR_OPACITY_ANIMATION_CURVE = AceType::MakeRefPtr<CubicCurve>(0.4, 0.0, 0.4, 1.0);
50 }
BuildMoreButton(bool isButtonEnabled,const RefPtr<NavigationBarTheme> & theme,const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & menuNode,std::vector<OptionParam> && params,const std::string & field,const std::string & parentId,bool isCreateLandscapeMenu)51 bool NavigationTitleUtil::BuildMoreButton(bool isButtonEnabled, const RefPtr<NavigationBarTheme>& theme,
52 const RefPtr<NavDestinationNodeBase>& nodeBase, const RefPtr<FrameNode>& menuNode,
53 std::vector<OptionParam>&& params, const std::string& field, const std::string& parentId,
54 bool isCreateLandscapeMenu)
55 {
56 auto barItemNode = CreateBarItemNode(isButtonEnabled);
57 CHECK_NULL_RETURN(barItemNode, false);
58 auto menuItemNode = CreateMenuItemButton(theme);
59 CHECK_NULL_RETURN(menuItemNode, false);
60 MenuParam menuParam;
61 menuParam.isShowInSubWindow = false;
62 menuParam.placement = Placement::BOTTOM_RIGHT;
63 auto barMenuNode = MenuView::Create(
64 std::move(params), menuItemNode->GetId(), menuItemNode->GetTag(), MenuType::NAVIGATION_MENU, menuParam);
65 BuildMoreItemNodeAction(menuItemNode, barItemNode, barMenuNode);
66 auto iconNode = AceType::DynamicCast<FrameNode>(barItemNode->GetChildren().front());
67 InitTitleBarButtonEvent(menuItemNode, iconNode, true);
68
69 // read navdestination "more" button
70 std::string message = Localization::GetInstance()->GetEntryLetters("navigation.more");
71 SetAccessibility(menuItemNode, message);
72
73 // set navdestination titleBar "more" button inspectorId
74 SetInnerChildId(menuItemNode, field, menuNode->GetTag(), "More", parentId);
75
76 barItemNode->MountToParent(menuItemNode);
77 barItemNode->MarkModifyDone();
78 menuItemNode->MarkModifyDone();
79 CHECK_NULL_RETURN(menuNode, false);
80 menuNode->AddChild(menuItemNode);
81 CHECK_NULL_RETURN(nodeBase, false);
82 if (isCreateLandscapeMenu) {
83 nodeBase->SetLandscapeMenuNode(barMenuNode);
84 } else {
85 nodeBase->SetMenuNode(barMenuNode);
86 }
87 return true;
88 }
89
CreateMenuItems(const int32_t menuNodeId,const std::vector<NG::BarItem> & menuItems,const RefPtr<NavDestinationNodeBase> & navDestinationNodeBase,bool isButtonEnabled,const std::string & field,const std::string & parentId,bool isCreateLandscapeMenu)90 RefPtr<FrameNode> NavigationTitleUtil::CreateMenuItems(const int32_t menuNodeId,
91 const std::vector<NG::BarItem>& menuItems, const RefPtr<NavDestinationNodeBase>& navDestinationNodeBase,
92 bool isButtonEnabled, const std::string& field, const std::string& parentId, bool isCreateLandscapeMenu)
93 {
94 auto menuNode = FrameNode::GetOrCreateFrameNode(
95 V2::NAVIGATION_MENU_ETS_TAG, menuNodeId, []() { return AceType::MakeRefPtr<LinearLayoutPattern>(false); });
96 CHECK_NULL_RETURN(menuNode, nullptr);
97 menuNode->Clean();
98 menuNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
99 auto rowProperty = menuNode->GetLayoutProperty<LinearLayoutProperty>();
100 CHECK_NULL_RETURN(rowProperty, nullptr);
101 rowProperty->UpdateMainAxisAlign(FlexAlign::SPACE_BETWEEN);
102 auto theme = NavigationGetTheme();
103 CHECK_NULL_RETURN(theme, nullptr);
104 auto mostMenuItemCount = GetOrInitMaxMenuNums(theme, navDestinationNodeBase);
105 bool needMoreButton = menuItems.size() > mostMenuItemCount ? true : false;
106
107 int32_t count = 0;
108 std::vector<OptionParam> params;
109 OptionParam param;
110 for (const auto& menuItem : menuItems) {
111 ++count;
112 if (needMoreButton && (count > static_cast<int32_t>(mostMenuItemCount) - 1)) {
113 param = { menuItem.text.value_or(""), menuItem.icon.value_or(""), menuItem.isEnabled.value_or(true),
114 menuItem.action, menuItem.iconSymbol.value_or(nullptr) };
115 param.SetSymbolUserDefinedIdealFontSize(theme->GetMenuIconSize());
116 params.push_back(param);
117 } else {
118 auto menuItemNode = CreateMenuItemNode(theme, menuItem, isButtonEnabled);
119 CHECK_NULL_RETURN(menuItemNode, nullptr);
120
121 // set titleBar menuitem inspectorId
122 std::string menuItemId = menuItemNode->GetTag() + std::to_string(count);
123 NavigationTitleUtil::SetInnerChildId(menuItemNode, field, menuNode->GetTag(), menuItemId, parentId);
124
125 // read menu button
126 SetAccessibility(menuItemNode, menuItem.text.value_or(""));
127 menuNode->AddChild(menuItemNode);
128 }
129 }
130
131 // build more button
132 if (needMoreButton) {
133 bool buildMoreButtonResult = BuildMoreButton(isButtonEnabled, theme, navDestinationNodeBase,
134 menuNode, std::move(params), field, parentId, isCreateLandscapeMenu);
135 if (!buildMoreButtonResult) {
136 TAG_LOGI(AceLogTag::ACE_NAVIGATION, "build more button node failed");
137 return nullptr;
138 }
139 }
140 InitDragAndLongPressEvent(menuNode, menuItems);
141 return menuNode;
142 }
143
GetOrInitMaxMenuNums(const RefPtr<NavigationBarTheme> & theme,const RefPtr<NavDestinationNodeBase> & navDestinationNodeBase)144 uint32_t NavigationTitleUtil::GetOrInitMaxMenuNums(
145 const RefPtr<NavigationBarTheme>& theme, const RefPtr<NavDestinationNodeBase>& navDestinationNodeBase)
146 {
147 auto patternBase = navDestinationNodeBase->GetPattern<NavDestinationPatternBase>();
148 CHECK_NULL_RETURN(patternBase, 0);
149 auto navDesMaxNum = patternBase->GetMaxMenuNum();
150 auto mostMenuItemCount =
151 navDesMaxNum < 0 ? theme->GetMostMenuItemCountInBar() : static_cast<uint32_t>(navDesMaxNum);
152 mostMenuItemCount = SystemProperties::GetDeviceOrientation() == DeviceOrientation::LANDSCAPE ? MAX_MENU_NUM_LARGE
153 : mostMenuItemCount;
154 patternBase->SetMaxMenuNum(mostMenuItemCount);
155 return mostMenuItemCount;
156 }
157
BuildMoreItemNodeAction(const RefPtr<FrameNode> & buttonNode,const RefPtr<BarItemNode> & barItemNode,const RefPtr<FrameNode> & barMenuNode)158 void NavigationTitleUtil::BuildMoreItemNodeAction(const RefPtr<FrameNode>& buttonNode,
159 const RefPtr<BarItemNode>& barItemNode, const RefPtr<FrameNode>& barMenuNode)
160 {
161 auto eventHub = barItemNode->GetEventHub<BarItemEventHub>();
162 CHECK_NULL_VOID(eventHub);
163
164 auto context = PipelineContext::GetCurrentContext();
165 auto clickCallback = [weakContext = WeakPtr<PipelineContext>(context), id = barItemNode->GetId(),
166 weakMenu = WeakPtr<FrameNode>(barMenuNode)]() {
167 auto context = weakContext.Upgrade();
168 CHECK_NULL_VOID(context);
169
170 auto overlayManager = context->GetOverlayManager();
171 CHECK_NULL_VOID(overlayManager);
172
173 auto menu = weakMenu.Upgrade();
174 CHECK_NULL_VOID(menu);
175 overlayManager->ShowMenu(id, OffsetF(0.0f, 0.0f), menu);
176 };
177 eventHub->SetItemAction(clickCallback);
178
179 auto gestureEventHub = buttonNode->GetOrCreateGestureEventHub();
180 CHECK_NULL_VOID(gestureEventHub);
181 auto callback = [action = clickCallback](GestureEvent& info) {
182 if (info.GetSourceDevice() == SourceType::KEYBOARD) {
183 return;
184 }
185 action();
186 };
187 gestureEventHub->AddClickEvent(AceType::MakeRefPtr<ClickEvent>(callback));
188 }
189
CreateMenuItemNode(const RefPtr<NavigationBarTheme> & theme,const BarItem & menuItem,bool isButtonEnabled)190 RefPtr<FrameNode> NavigationTitleUtil::CreateMenuItemNode(
191 const RefPtr<NavigationBarTheme>& theme, const BarItem& menuItem, bool isButtonEnabled)
192 {
193 auto menuItemNode = CreateMenuItemButton(theme);
194 CHECK_NULL_RETURN(menuItemNode, nullptr);
195
196 int32_t barItemNodeId = ElementRegister::GetInstance()->MakeUniqueId();
197 auto barItemNode = BarItemNode::GetOrCreateBarItemNode(
198 V2::BAR_ITEM_ETS_TAG, barItemNodeId, []() { return AceType::MakeRefPtr<BarItemPattern>(); });
199 UpdateBarItemNodeWithItem(barItemNode, menuItem, isButtonEnabled);
200 auto iconNode = AceType::DynamicCast<FrameNode>(barItemNode->GetChildren().front());
201 InitTitleBarButtonEvent(menuItemNode, iconNode, false, menuItem, menuItem.isEnabled.value_or(true));
202 auto barItemLayoutProperty = barItemNode->GetLayoutProperty();
203 CHECK_NULL_RETURN(barItemLayoutProperty, nullptr);
204 barItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
205
206 barItemNode->MountToParent(menuItemNode);
207 barItemNode->MarkModifyDone();
208 menuItemNode->MarkModifyDone();
209 return menuItemNode;
210 }
211
CreateMenuItemButton(const RefPtr<NavigationBarTheme> & theme)212 RefPtr<FrameNode> NavigationTitleUtil::CreateMenuItemButton(const RefPtr<NavigationBarTheme>& theme)
213 {
214 auto buttonPattern = AceType::MakeRefPtr<NG::ButtonPattern>();
215 CHECK_NULL_RETURN(buttonPattern, nullptr);
216 buttonPattern->setComponentButtonType(ComponentButtonType::NAVIGATION);
217 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
218 buttonPattern->SetBlendColor(theme->GetBackgroundPressedColor(), theme->GetBackgroundHoverColor());
219 buttonPattern->SetFocusBorderColor(theme->GetBackgroundFocusOutlineColor());
220 buttonPattern->SetFocusBorderWidth(theme->GetBackgroundFocusOutlineWeight());
221 } else {
222 buttonPattern->SetFocusBorderColor(theme->GetToolBarItemFocusColor());
223 buttonPattern->SetFocusBorderWidth(theme->GetToolBarItemFocusBorderWidth());
224 }
225 auto menuItemNode = FrameNode::CreateFrameNode(
226 V2::MENU_ITEM_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), buttonPattern);
227 CHECK_NULL_RETURN(menuItemNode, nullptr);
228 auto focusHub = menuItemNode->GetOrCreateFocusHub();
229 CHECK_NULL_RETURN(focusHub, nullptr);
230 focusHub->SetFocusDependence(FocusDependence::SELF);
231 auto menuItemLayoutProperty = menuItemNode->GetLayoutProperty<ButtonLayoutProperty>();
232 CHECK_NULL_RETURN(menuItemLayoutProperty, nullptr);
233 menuItemLayoutProperty->UpdateType(ButtonType::NORMAL);
234 auto renderContext = menuItemNode->GetRenderContext();
235 CHECK_NULL_RETURN(renderContext, nullptr);
236 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
237 auto iconBackgroundWidth = theme->GetIconBackgroundWidth();
238 auto iconBackgroundHeight = theme->GetIconBackgroundHeight();
239 menuItemLayoutProperty->UpdateUserDefinedIdealSize(
240 CalcSize(CalcLength(iconBackgroundWidth), CalcLength(iconBackgroundHeight)));
241 menuItemLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(theme->GetCornerRadius()));
242 renderContext->UpdateBackgroundColor(theme->GetCompBackgroundColor());
243 PaddingProperty padding;
244 padding.SetEdges(CalcLength(MENU_BUTTON_PADDING));
245 menuItemLayoutProperty->UpdatePadding(padding);
246 MarginProperty margin;
247 margin.right = CalcLength(theme->GetCompPadding());
248 margin.end = CalcLength(theme->GetCompPadding());
249 menuItemLayoutProperty->UpdateMargin(margin);
250 } else {
251 menuItemLayoutProperty->UpdateUserDefinedIdealSize(
252 CalcSize(CalcLength(BACK_BUTTON_SIZE), CalcLength(BACK_BUTTON_SIZE)));
253 menuItemLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(BUTTON_RADIUS_SIZE));
254 renderContext->UpdateBackgroundColor(Color::TRANSPARENT);
255 PaddingProperty padding;
256 padding.SetEdges(CalcLength(BUTTON_PADDING));
257 menuItemLayoutProperty->UpdatePadding(padding);
258 }
259 return menuItemNode;
260 }
261
CreateBarItemTextNode(const std::string & text)262 RefPtr<FrameNode> NavigationTitleUtil::CreateBarItemTextNode(const std::string& text)
263 {
264 int32_t nodeId = ElementRegister::GetInstance()->MakeUniqueId();
265 auto textNode = FrameNode::CreateFrameNode(V2::TEXT_ETS_TAG, nodeId, AceType::MakeRefPtr<TextPattern>());
266 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
267 CHECK_NULL_RETURN(textLayoutProperty, nullptr);
268 textLayoutProperty->UpdateContent(text);
269 textLayoutProperty->UpdateFontSize(TEXT_FONT_SIZE);
270 textLayoutProperty->UpdateTextColor(TEXT_COLOR);
271 textLayoutProperty->UpdateTextAlign(TextAlign::CENTER);
272 return textNode;
273 }
274
UpdateSymbolEffect(RefPtr<TextLayoutProperty> symbolProperty,bool isActive)275 void UpdateSymbolEffect(RefPtr<TextLayoutProperty> symbolProperty, bool isActive)
276 {
277 CHECK_NULL_VOID(symbolProperty);
278 auto symbolEffectOptions = SymbolEffectOptions(SymbolEffectType::BOUNCE);
279 symbolEffectOptions.SetIsTxtActive(isActive);
280 symbolEffectOptions.SetIsTxtActiveSource(0);
281 symbolProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
282 }
283
CreateBarItemIconNode(const BarItem & barItem,const bool isButtonEnabled)284 RefPtr<FrameNode> NavigationTitleUtil::CreateBarItemIconNode(const BarItem& barItem, const bool isButtonEnabled)
285 {
286 auto theme = NavigationGetTheme();
287 CHECK_NULL_RETURN(theme, nullptr);
288
289 Color iconColor = theme->GetMenuIconColor();
290 double iconOpacity = theme->GetAlphaDisabled();
291 auto iconWidth = theme->GetMenuIconSize();
292 auto iconHeight = theme->GetMenuIconSize();
293 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
294 iconColor = theme->GetIconColor();
295 iconOpacity = theme->GetIconDisableAlpha();
296 iconWidth = theme->GetIconWidth();
297 iconHeight = theme->GetIconHeight();
298 }
299
300 if (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr) {
301 auto iconNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
302 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
303 CHECK_NULL_RETURN(iconNode, nullptr);
304 auto symbolProperty = iconNode->GetLayoutProperty<TextLayoutProperty>();
305 CHECK_NULL_RETURN(symbolProperty, nullptr);
306 if (isButtonEnabled) {
307 symbolProperty->UpdateSymbolColorList({ iconColor });
308 } else {
309 symbolProperty->UpdateSymbolColorList({ iconColor.BlendOpacity(iconOpacity) });
310 }
311 barItem.iconSymbol.value()(AccessibilityManager::WeakClaim(AccessibilityManager::RawPtr(iconNode)));
312 UpdateSymbolEffect(symbolProperty, false);
313 symbolProperty->UpdateFontSize(iconWidth);
314 iconNode->MarkModifyDone();
315 return iconNode;
316 }
317 int32_t nodeId = ElementRegister::GetInstance()->MakeUniqueId();
318 ImageSourceInfo info(barItem.icon.value());
319 auto iconNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, nodeId, AceType::MakeRefPtr<ImagePattern>());
320 auto imageLayoutProperty = iconNode->GetLayoutProperty<ImageLayoutProperty>();
321 CHECK_NULL_RETURN(imageLayoutProperty, nullptr);
322 if (isButtonEnabled) {
323 info.SetFillColor(iconColor);
324 } else {
325 info.SetFillColor(iconColor.BlendOpacity(iconOpacity));
326 }
327 imageLayoutProperty->UpdateImageSourceInfo(info);
328 imageLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(iconWidth), CalcLength(iconHeight)));
329 iconNode->MarkModifyDone();
330 return iconNode;
331 }
332
InitTitleBarButtonEvent(const RefPtr<FrameNode> & buttonNode,const RefPtr<FrameNode> & iconNode,bool isMoreButton,const BarItem & menuItem,bool isButtonEnabled)333 void NavigationTitleUtil::InitTitleBarButtonEvent(const RefPtr<FrameNode>& buttonNode,
334 const RefPtr<FrameNode>& iconNode, bool isMoreButton, const BarItem& menuItem, bool isButtonEnabled)
335 {
336 auto eventHub = buttonNode->GetOrCreateInputEventHub();
337 CHECK_NULL_VOID(eventHub);
338
339 if (isMoreButton) {
340 auto hoverTask = [weakTargetNode = WeakPtr<FrameNode>(buttonNode)](bool isHover) {
341 auto targetNode = weakTargetNode.Upgrade();
342 CHECK_NULL_VOID(targetNode);
343 auto popupParam = AceType::MakeRefPtr<PopupParam>();
344 popupParam->SetMessage(Localization::GetInstance()->GetEntryLetters("common.more"));
345 popupParam->SetIsShow(isHover);
346 popupParam->SetBlockEvent(false);
347 ViewAbstract::BindPopup(popupParam, targetNode, nullptr);
348 };
349 eventHub->AddOnHoverEvent(AceType::MakeRefPtr<InputEvent>(std::move(hoverTask)));
350 return;
351 }
352
353 if (menuItem.action) {
354 auto gestureEventHub = buttonNode->GetOrCreateGestureEventHub();
355 CHECK_NULL_VOID(gestureEventHub);
356 auto clickCallback = [action = menuItem.action, weakNode = WeakPtr<FrameNode>(iconNode)](GestureEvent& info) {
357 if (info.GetSourceDevice() == SourceType::KEYBOARD) {
358 return;
359 }
360 if (action) {
361 action();
362 }
363 auto symbol = weakNode.Upgrade();
364 CHECK_NULL_VOID(symbol);
365 if (symbol->GetTag() == V2::SYMBOL_ETS_TAG) {
366 auto symbolProperty = symbol->GetLayoutProperty<TextLayoutProperty>();
367 CHECK_NULL_VOID(symbolProperty);
368 auto symbolEffectOptions = symbolProperty->GetSymbolEffectOptionsValue(SymbolEffectOptions());
369 symbolEffectOptions.SetEffectType(SymbolEffectType::BOUNCE);
370 symbolEffectOptions.SetIsTxtActive(true);
371 symbolEffectOptions.SetIsTxtActiveSource(0);
372 symbolProperty->UpdateSymbolEffectOptions(symbolEffectOptions);
373 symbol->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
374 }
375 };
376 gestureEventHub->AddClickEvent(AceType::MakeRefPtr<ClickEvent>(clickCallback));
377 }
378
379 auto buttonEvent = buttonNode->GetEventHub<ButtonEventHub>();
380 CHECK_NULL_VOID(buttonEvent);
381 buttonEvent->SetEnabled(isButtonEnabled);
382 auto focusHub = buttonNode->GetFocusHub();
383 CHECK_NULL_VOID(focusHub);
384 focusHub->SetEnabled(isButtonEnabled);
385 }
386
UpdateBarItemNodeWithItem(const RefPtr<BarItemNode> & barItemNode,const BarItem & barItem,const bool isButtonEnabled)387 void NavigationTitleUtil::UpdateBarItemNodeWithItem(
388 const RefPtr<BarItemNode>& barItemNode, const BarItem& barItem, const bool isButtonEnabled)
389 {
390 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN) && barItem.text.has_value() &&
391 !barItem.text.value().empty()) {
392 auto textNode = CreateBarItemTextNode(barItem.text.value());
393 barItemNode->SetTextNode(textNode);
394 barItemNode->AddChild(textNode);
395 }
396 if ((barItem.icon.has_value()) || (barItem.iconSymbol.has_value() && barItem.iconSymbol.value() != nullptr)) {
397 auto iconNode = CreateBarItemIconNode(barItem, isButtonEnabled);
398 barItemNode->SetIconNode(iconNode);
399 barItemNode->AddChild(iconNode);
400 }
401 if (barItem.action) {
402 auto eventHub = barItemNode->GetEventHub<BarItemEventHub>();
403 CHECK_NULL_VOID(eventHub);
404 eventHub->SetItemAction(barItem.action);
405 }
406 auto barItemPattern = barItemNode->GetPattern<BarItemPattern>();
407 barItemNode->MarkModifyDone();
408 }
409
BuildImageMoreItemNode(const RefPtr<BarItemNode> & barItemNode,bool isButtonEnabled)410 void BuildImageMoreItemNode(const RefPtr<BarItemNode>& barItemNode, bool isButtonEnabled)
411 {
412 int32_t imageNodeId = ElementRegister::GetInstance()->MakeUniqueId();
413 auto imageNode = FrameNode::CreateFrameNode(V2::IMAGE_ETS_TAG, imageNodeId, AceType::MakeRefPtr<ImagePattern>());
414 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
415 CHECK_NULL_VOID(imageLayoutProperty);
416 auto theme = NavigationGetTheme();
417 CHECK_NULL_VOID(theme);
418
419 auto info = ImageSourceInfo("");
420 info.SetResourceId(theme->GetMoreResourceId());
421 if (isButtonEnabled) {
422 info.SetFillColor(theme->GetMenuIconColor());
423 } else {
424 info.SetFillColor(theme->GetMenuIconColor().BlendOpacity(theme->GetAlphaDisabled()));
425 }
426
427 imageLayoutProperty->UpdateImageSourceInfo(info);
428 auto iconSize = theme->GetMenuIconSize();
429 imageLayoutProperty->UpdateUserDefinedIdealSize(CalcSize(CalcLength(iconSize), CalcLength(iconSize)));
430 imageNode->MarkModifyDone();
431
432 barItemNode->SetIsMoreItemNode(true);
433 barItemNode->SetIconNode(imageNode);
434 barItemNode->AddChild(imageNode);
435 barItemNode->MarkModifyDone();
436 }
437
BuildSymbolMoreItemNode(const RefPtr<BarItemNode> & barItemNode,bool isButtonEnabled)438 void BuildSymbolMoreItemNode(const RefPtr<BarItemNode>& barItemNode, bool isButtonEnabled)
439 {
440 auto theme = NavigationGetTheme();
441 CHECK_NULL_VOID(theme);
442 auto iconSize = theme->GetMenuIconSize();
443 auto symbolNode = FrameNode::GetOrCreateFrameNode(V2::SYMBOL_ETS_TAG,
444 ElementRegister::GetInstance()->MakeUniqueId(), []() { return AceType::MakeRefPtr<TextPattern>(); });
445 CHECK_NULL_VOID(symbolNode);
446 auto symbolProperty = symbolNode->GetLayoutProperty<TextLayoutProperty>();
447 CHECK_NULL_VOID(symbolProperty);
448 symbolProperty->UpdateSymbolSourceInfo(SymbolSourceInfo(theme->GetMoreSymbolId()));
449 symbolProperty->UpdateFontSize(iconSize);
450 if (isButtonEnabled) {
451 symbolProperty->UpdateSymbolColorList({ theme->GetMenuIconColor() });
452 } else {
453 symbolProperty->UpdateSymbolColorList({ theme->GetMenuIconColor().BlendOpacity(theme->GetAlphaDisabled()) });
454 }
455 symbolNode->MarkModifyDone();
456 barItemNode->SetIsMoreItemNode(true);
457 barItemNode->SetIconNode(symbolNode);
458 barItemNode->AddChild(symbolNode);
459 barItemNode->MarkModifyDone();
460 }
461
BuildMoreIemNode(const RefPtr<BarItemNode> & barItemNode,bool isButtonEnabled)462 void NavigationTitleUtil::BuildMoreIemNode(const RefPtr<BarItemNode>& barItemNode, bool isButtonEnabled)
463 {
464 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE) &&
465 SystemProperties::IsNeedSymbol()) {
466 BuildSymbolMoreItemNode(barItemNode, isButtonEnabled);
467 } else {
468 BuildImageMoreItemNode(barItemNode, isButtonEnabled);
469 }
470 }
471
CreateBarItemNode(bool isButtonEnabled)472 RefPtr<BarItemNode> NavigationTitleUtil::CreateBarItemNode(bool isButtonEnabled)
473 {
474 int32_t barItemNodeId = ElementRegister::GetInstance()->MakeUniqueId();
475 auto barItemNode = BarItemNode::GetOrCreateBarItemNode(
476 V2::BAR_ITEM_ETS_TAG, barItemNodeId, []() { return AceType::MakeRefPtr<BarItemPattern>(); });
477 auto barItemLayoutProperty = barItemNode->GetLayoutProperty();
478 CHECK_NULL_RETURN(barItemLayoutProperty, nullptr);
479 barItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
480 BuildMoreIemNode(barItemNode, isButtonEnabled);
481 return barItemNode;
482 }
483
HandleLongPress(const GestureEvent & info,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)484 void NavigationTitleUtil::HandleLongPress(
485 const GestureEvent& info, const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
486 {
487 CHECK_NULL_VOID(menuNode);
488 auto context = PipelineBase::GetCurrentContext();
489 CHECK_NULL_VOID(context);
490 auto dialogTheme = context->GetTheme<AgingAdapationDialogTheme>();
491 CHECK_NULL_VOID(dialogTheme);
492 float scale = context->GetFontScale();
493 if (LessNotEqual(scale, dialogTheme->GetBigFontSizeScale())) {
494 TAG_LOGI(AceLogTag::ACE_NAVIGATION,
495 "The current system font scale is %{public}f; dialogTheme font scale is %{public}f", scale,
496 dialogTheme->GetBigFontSizeScale());
497 return;
498 }
499 auto menuItemNode = menuNode->FindChildByPosition(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
500 CHECK_NULL_VOID(menuItemNode);
501 auto index = menuNode->GetChildIndex(menuItemNode);
502 auto dialogNode = CreatePopupDialogNode(menuItemNode, menuItems, index);
503 CHECK_NULL_VOID(dialogNode);
504 auto titleBarNode = menuNode->GetParentFrameNode();
505 CHECK_NULL_VOID(titleBarNode);
506 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
507 CHECK_NULL_VOID(titleBarPattern);
508 if (titleBarPattern->GetLargeFontPopUpDialogNode() != nullptr) {
509 HandleLongPressActionEnd(menuNode);
510 }
511 titleBarPattern->SetLargeFontPopUpDialogNode(dialogNode);
512 }
513
HandleLongPressActionEnd(const RefPtr<FrameNode> & targetNode)514 void NavigationTitleUtil::HandleLongPressActionEnd(const RefPtr<FrameNode>& targetNode)
515 {
516 CHECK_NULL_VOID(targetNode);
517 auto titleBarNode = targetNode->GetParentFrameNode();
518 CHECK_NULL_VOID(titleBarNode);
519 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
520 CHECK_NULL_VOID(titleBarPattern);
521 auto dialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
522 CHECK_NULL_VOID(dialogNode);
523 auto pipeline = PipelineContext::GetCurrentContext();
524 CHECK_NULL_VOID(pipeline);
525 auto overlayManager = pipeline->GetOverlayManager();
526 CHECK_NULL_VOID(overlayManager);
527 overlayManager->CloseDialog(dialogNode);
528 titleBarPattern->SetLargeFontPopUpDialogNode(nullptr);
529 }
530
InitDragAndLongPressEvent(const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)531 void NavigationTitleUtil::InitDragAndLongPressEvent(
532 const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
533 {
534 CHECK_NULL_VOID(menuNode);
535 auto pipeline = menuNode->GetContext();
536 CHECK_NULL_VOID(pipeline);
537 if (LessNotEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
538 return;
539 }
540
541 auto gestureHub = menuNode->GetOrCreateGestureEventHub();
542 CHECK_NULL_VOID(gestureHub);
543 InitDragEvent(gestureHub, menuNode, menuItems);
544 InitLongPressEvent(gestureHub, menuNode, menuItems);
545 auto accessibilityProperty = menuNode->GetAccessibilityProperty<NG::AccessibilityProperty>();
546 CHECK_NULL_VOID(accessibilityProperty);
547 accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
548 }
549
CreatePopupDialogNode(const RefPtr<FrameNode> targetNode,const std::vector<NG::BarItem> & menuItems,int32_t index)550 RefPtr<FrameNode> NavigationTitleUtil::CreatePopupDialogNode(
551 const RefPtr<FrameNode> targetNode, const std::vector<NG::BarItem>& menuItems, int32_t index)
552 {
553 CHECK_NULL_RETURN(targetNode, nullptr);
554 RefPtr<BarItemNode> barItemNode = AceType::DynamicCast<BarItemNode>(targetNode->GetFirstChild());
555 CHECK_NULL_RETURN(barItemNode, nullptr);
556 auto accessibilityProperty = targetNode->GetAccessibilityProperty<AccessibilityProperty>();
557 CHECK_NULL_RETURN(accessibilityProperty, nullptr);
558 ImageSourceInfo imageSourceInfo;
559 std::string message;
560 RefPtr<FrameNode> dialogNode;
561 if (barItemNode->IsMoreItemNode()) {
562 auto theme = NavigationGetTheme();
563 CHECK_NULL_RETURN(theme, nullptr);
564 message = Localization::GetInstance()->GetEntryLetters("common.more");
565 if (message.empty()) {
566 message = accessibilityProperty->GetAccessibilityText();
567 }
568 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
569 auto symbolNode = AceType::DynamicCast<FrameNode>(barItemNode->GetFirstChild());
570 CHECK_NULL_RETURN(symbolNode, nullptr);
571 dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, symbolNode);
572 return dialogNode;
573 }
574 imageSourceInfo.SetResourceId(theme->GetMoreResourceId());
575 dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, imageSourceInfo);
576 return dialogNode;
577 }
578 if (index < 0 || index >= static_cast<int32_t>(menuItems.size())) {
579 return nullptr;
580 }
581 auto menuItem = menuItems.at(index);
582 if (menuItem.text.has_value() && !menuItem.text.value().empty()) {
583 message = menuItem.text.value();
584 } else {
585 message = accessibilityProperty->GetAccessibilityText();
586 }
587 if (menuItem.iconSymbol.has_value() && menuItem.iconSymbol.value() != nullptr) {
588 return CreateSymbolDialog(message, barItemNode);
589 }
590 if (menuItem.icon.has_value() && !menuItem.icon.value().empty()) {
591 imageSourceInfo = ImageSourceInfo(menuItem.icon.value());
592 }
593 dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, imageSourceInfo);
594 return dialogNode;
595 }
596
CreateSymbolDialog(const std::string & message,const RefPtr<FrameNode> & targetNode)597 RefPtr<FrameNode> NavigationTitleUtil::CreateSymbolDialog(
598 const std::string& message, const RefPtr<FrameNode>& targetNode)
599 {
600 auto barItemNode = AceType::DynamicCast<BarItemNode>(targetNode);
601 CHECK_NULL_RETURN(barItemNode, nullptr);
602 auto iconNode = AceType::DynamicCast<FrameNode>(barItemNode->GetIconNode());
603 CHECK_NULL_RETURN(iconNode, nullptr);
604 return AgingAdapationDialogUtil::ShowLongPressDialog(message, iconNode);
605 }
606
SetAccessibility(const RefPtr<FrameNode> & node,const std::string & message)607 void NavigationTitleUtil::SetAccessibility(const RefPtr<FrameNode>& node, const std::string& message)
608 {
609 CHECK_NULL_VOID(node);
610 auto accessibilityProperty = node->GetAccessibilityProperty<NG::AccessibilityProperty>();
611 CHECK_NULL_VOID(accessibilityProperty);
612 accessibilityProperty->SetAccessibilityText(message);
613 accessibilityProperty->SetAccessibilityGroup(true);
614 }
615
GetTitleString(const RefPtr<TitleBarNode> & titleBarNode,bool isCustom)616 std::string NavigationTitleUtil::GetTitleString(const RefPtr<TitleBarNode>& titleBarNode, bool isCustom)
617 {
618 if (isCustom) {
619 return "";
620 }
621 CHECK_NULL_RETURN(titleBarNode, "");
622 auto title = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
623 CHECK_NULL_RETURN(title, "");
624 if (title->GetTag() != V2::TEXT_ETS_TAG) {
625 return "";
626 }
627 auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
628 CHECK_NULL_RETURN(textLayoutProperty, "");
629 return textLayoutProperty->GetContentValue("");
630 }
631
GetSubtitleString(const RefPtr<TitleBarNode> & titleBarNode)632 std::string NavigationTitleUtil::GetSubtitleString(const RefPtr<TitleBarNode>& titleBarNode)
633 {
634 CHECK_NULL_RETURN(titleBarNode, "");
635 auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
636 CHECK_NULL_RETURN(subtitle, "");
637 if (subtitle->GetTag() != V2::TEXT_ETS_TAG) {
638 return "";
639 }
640 auto textLayoutProperty = subtitle->GetLayoutProperty<TextLayoutProperty>();
641 CHECK_NULL_RETURN(textLayoutProperty, "");
642 return textLayoutProperty->GetContentValue("");
643 }
644
InitDragEvent(const RefPtr<GestureEventHub> & gestureHub,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)645 void NavigationTitleUtil::InitDragEvent(const RefPtr<GestureEventHub>& gestureHub, const RefPtr<FrameNode>& menuNode,
646 const std::vector<NG::BarItem>& menuItems)
647 {
648 auto actionUpdateTask = [weakMenuNode = WeakPtr<FrameNode>(menuNode), menuItems](const GestureEvent& info) {
649 auto menuNode = weakMenuNode.Upgrade();
650 CHECK_NULL_VOID(menuNode);
651 auto menuItemNode =
652 menuNode->FindChildByPosition(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
653 CHECK_NULL_VOID(menuItemNode);
654 auto index = menuNode->GetChildIndex(menuItemNode);
655 auto totalCount = menuNode->TotalChildCount();
656 auto titleBarNode = menuNode->GetParentFrameNode();
657 CHECK_NULL_VOID(titleBarNode);
658 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
659 CHECK_NULL_VOID(titleBarPattern);
660 auto dialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
661 if (dialogNode && index >= 0 && index < totalCount) {
662 if (!titleBarPattern->GetMoveIndex().has_value()) {
663 titleBarPattern->SetMoveIndex(index);
664 }
665
666 if (titleBarPattern->GetMoveIndex().value() != index) {
667 HandleLongPressActionEnd(menuNode);
668 titleBarPattern->SetMoveIndex(index);
669 titleBarPattern->SetLargeFontPopUpDialogNode(CreatePopupDialogNode(menuItemNode, menuItems, index));
670 }
671 }
672 };
673
674 auto dragEvent = AceType::MakeRefPtr<DragEvent>(nullptr, std::move(actionUpdateTask), nullptr, nullptr);
675 PanDirection panDirection = { .type = PanDirection::ALL };
676 gestureHub->SetDragEvent(dragEvent, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
677 }
678
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)679 void NavigationTitleUtil::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub,
680 const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
681 {
682 auto longPressCallback = [weakTargetNode = WeakPtr<FrameNode>(menuNode), menuItems](GestureEvent& info) {
683 auto menuNode = weakTargetNode.Upgrade();
684 NavigationTitleUtil::HandleLongPress(info, menuNode, menuItems);
685 };
686 auto longPressEvent = AceType::MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
687 gestureHub->SetLongPressEvent(longPressEvent);
688
689 auto longPressRecognizer = gestureHub->GetLongPressRecognizer();
690 CHECK_NULL_VOID(longPressRecognizer);
691
692 auto longPressEndCallback = [weakTargetNode = WeakPtr<FrameNode>(menuNode)](GestureEvent& info) {
693 auto menuNode = weakTargetNode.Upgrade();
694 NavigationTitleUtil::HandleLongPressActionEnd(menuNode);
695 };
696 longPressRecognizer->SetOnActionEnd(longPressEndCallback);
697 }
698
CreateOrUpdateMainTitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo,bool ignoreMainTitle)699 void NavigationTitleUtil::CreateOrUpdateMainTitle(const RefPtr<TitleBarNode>& titleBarNode,
700 const NG::NavigationTitleInfo& titleInfo, bool ignoreMainTitle)
701 {
702 CHECK_NULL_VOID(titleBarNode);
703 if (ignoreMainTitle) {
704 return;
705 }
706 auto mainTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
707 if (!titleInfo.hasMainTitle) {
708 // remove main title if any.
709 titleBarNode->RemoveChild(mainTitle);
710 titleBarNode->SetTitle(nullptr);
711 return;
712 }
713
714 if (mainTitle) {
715 // update main title
716 auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
717 CHECK_NULL_VOID(textLayoutProperty);
718 textLayoutProperty->UpdateMaxLines(titleInfo.hasSubTitle ? 1 : TITLEBAR_MAX_LINES);
719 textLayoutProperty->UpdateContent(titleInfo.title);
720 return;
721 }
722 // create and init main title
723 mainTitle = FrameNode::CreateFrameNode(
724 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
725 auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
726 CHECK_NULL_VOID(textLayoutProperty);
727 textLayoutProperty->UpdateContent(titleInfo.title);
728 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
729 CHECK_NULL_VOID(titleBarPattern);
730 titleBarPattern->SetNeedResetMainTitleProperty(true);
731 titleBarNode->SetTitle(mainTitle);
732 titleBarNode->AddChild(mainTitle);
733 }
734
CreateOrUpdateSubtitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)735 void NavigationTitleUtil::CreateOrUpdateSubtitle(const RefPtr<TitleBarNode>& titleBarNode,
736 const NG::NavigationTitleInfo& titleInfo)
737 {
738 CHECK_NULL_VOID(titleBarNode);
739 auto subTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
740 if (!titleInfo.hasSubTitle) {
741 // remove subtitle if any.
742 titleBarNode->RemoveChild(subTitle);
743 titleBarNode->SetSubtitle(nullptr);
744 return;
745 }
746 if (subTitle) {
747 // update subtitle
748 auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
749 CHECK_NULL_VOID(textLayoutProperty);
750 textLayoutProperty->UpdateContent(titleInfo.subtitle);
751 auto renderContext = subTitle->GetRenderContext();
752 CHECK_NULL_VOID(renderContext);
753 renderContext->UpdateOpacity(1.0);
754 return;
755 }
756 // create and init subtitle
757 subTitle = FrameNode::CreateFrameNode(
758 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
759 auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
760 CHECK_NULL_VOID(textLayoutProperty);
761 textLayoutProperty->UpdateContent(titleInfo.subtitle);
762 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
763 CHECK_NULL_VOID(titleBarPattern);
764 titleBarPattern->SetNeedResetSubTitleProperty(true);
765 titleBarNode->SetSubtitle(subTitle);
766 titleBarNode->AddChild(subTitle);
767 }
768
CreateOrUpdateDestinationMainTitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)769 void NavigationTitleUtil::CreateOrUpdateDestinationMainTitle(const RefPtr<TitleBarNode>& titleBarNode,
770 const NG::NavigationTitleInfo& titleInfo)
771 {
772 CHECK_NULL_VOID(titleBarNode);
773 auto mainTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
774 if (!titleInfo.hasMainTitle) {
775 // remove main title if any.
776 titleBarNode->RemoveChild(mainTitle);
777 titleBarNode->SetTitle(nullptr);
778 return;
779 }
780 if (mainTitle) {
781 // update main title
782 auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
783 CHECK_NULL_VOID(textLayoutProperty);
784 textLayoutProperty->UpdateMaxLines(titleInfo.hasSubTitle ? 1 : TITLEBAR_MAX_LINES);
785 if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
786 textLayoutProperty->UpdateHeightAdaptivePolicy(titleInfo.hasSubTitle ?
787 TextHeightAdaptivePolicy::MAX_LINES_FIRST : TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
788 }
789 textLayoutProperty->UpdateContent(titleInfo.title);
790 textLayoutProperty->UpdateMaxFontScale(STANDARD_FONT_SCALE);
791 return;
792 }
793 // create and init main title
794 mainTitle = FrameNode::CreateFrameNode(
795 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
796 auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
797 CHECK_NULL_VOID(textLayoutProperty);
798 textLayoutProperty->UpdateContent(titleInfo.title);
799 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
800 CHECK_NULL_VOID(titleBarPattern);
801 titleBarPattern->SetNeedResetMainTitleProperty(true);
802 titleBarNode->SetTitle(mainTitle);
803 titleBarNode->AddChild(mainTitle);
804 }
805
CreateOrUpdateDestinationSubtitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)806 void NavigationTitleUtil::CreateOrUpdateDestinationSubtitle(const RefPtr<TitleBarNode>& titleBarNode,
807 const NG::NavigationTitleInfo& titleInfo)
808 {
809 CHECK_NULL_VOID(titleBarNode);
810 auto subTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
811 if (!titleInfo.hasSubTitle) {
812 // remove subtitle if any.
813 titleBarNode->RemoveChild(subTitle);
814 titleBarNode->SetSubtitle(nullptr);
815 return;
816 }
817 if (subTitle) {
818 // update subtitle
819 auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
820 CHECK_NULL_VOID(textLayoutProperty);
821 textLayoutProperty->UpdateContent(titleInfo.subtitle);
822 textLayoutProperty->UpdateMaxFontScale(STANDARD_FONT_SCALE);
823 return;
824 }
825 // create and init subtitle
826 subTitle = FrameNode::CreateFrameNode(
827 V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
828 auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
829 CHECK_NULL_VOID(textLayoutProperty);
830 textLayoutProperty->UpdateContent(titleInfo.subtitle);
831 auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
832 CHECK_NULL_VOID(titleBarPattern);
833 titleBarPattern->SetNeedResetSubTitleProperty(true);
834 titleBarNode->SetSubtitle(subTitle);
835 titleBarNode->AddChild(subTitle);
836 }
837
FoldStatusChangedAnimation(const RefPtr<FrameNode> & host)838 void NavigationTitleUtil::FoldStatusChangedAnimation(const RefPtr<FrameNode>& host)
839 {
840 CHECK_NULL_VOID(host);
841 auto pipelineContext = host->GetContext();
842 CHECK_NULL_VOID(pipelineContext);
843 auto titleBar = AceType::DynamicCast<TitleBarNode>(host);
844 CHECK_NULL_VOID(titleBar);
845 auto pattern = titleBar->GetPattern<TitleBarPattern>();
846 CHECK_NULL_VOID(pattern);
847
848 if (!pipelineContext->IsHoverModeChange() || !IsNeedHoverModeAction(titleBar)) {
849 // Since only expanded to hover or hover to expanded need this animation.
850 return;
851 }
852
853 AnimationOption option;
854 option.SetCurve(TITLEBAR_OPACITY_ANIMATION_CURVE);
855 auto renderNodeContext = host->GetRenderContext();
856 CHECK_NULL_VOID(renderNodeContext);
857 option.SetDuration(TITLEBAR_OPACITY_ANIMATION_DURATION);
858 renderNodeContext->UpdateOpacity(1.0f);
859 option.SetOnFinishEvent([weakRenderNodeContext = WeakPtr<RenderContext>(renderNodeContext),
860 weakHost = WeakPtr<FrameNode>(host)]() {
861 auto host = weakHost.Upgrade();
862 CHECK_NULL_VOID(host);
863 auto renderContext = weakRenderNodeContext.Upgrade();
864 CHECK_NULL_VOID(renderContext);
865 AnimationOption finishOption;
866 finishOption.SetDuration(TITLEBAR_OPACITY_ANIMATION_DURATION);
867 finishOption.SetCurve(TITLEBAR_OPACITY_ANIMATION_CURVE);
868 auto parent = AceType::DynamicCast<FrameNode>(host->GetParent());
869 CHECK_NULL_VOID(parent);
870 parent->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
871 AnimationUtils::Animate(
872 finishOption, [weakRenderNodeContext = WeakPtr<RenderContext>(renderContext)]() {
873 auto renderNodeContext = weakRenderNodeContext.Upgrade();
874 CHECK_NULL_VOID(renderNodeContext);
875 renderNodeContext->UpdateOpacity(1.0f);
876 });
877 });
878 AnimationUtils::Animate(
879 option,
880 [weakRenderNodeContext = WeakPtr<RenderContext>(renderNodeContext)]() {
881 auto renderContext = weakRenderNodeContext.Upgrade();
882 CHECK_NULL_VOID(renderContext);
883 renderContext->UpdateOpacity(0.0f);
884 },
885 option.GetOnFinishEvent());
886 }
887
IsNeedHoverModeAction(const RefPtr<TitleBarNode> & titleBarNode)888 bool NavigationTitleUtil::IsNeedHoverModeAction(const RefPtr<TitleBarNode>& titleBarNode)
889 {
890 CHECK_NULL_RETURN(titleBarNode, false);
891 auto pattern = titleBarNode->GetPattern<TitleBarPattern>();
892 CHECK_NULL_RETURN(pattern, false);
893 auto options = pattern->GetTitleBarOptions();
894 auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
895 CHECK_NULL_RETURN(titleBarLayoutProperty, false);
896 auto parentType = titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR);
897 if (parentType == TitleBarParentType::NAVBAR &&
898 titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::MINI) == NavigationTitleMode::FREE) {
899 return false;
900 }
901 if (!options.enableHoverMode || options.brOptions.barStyle == NG::BarStyle::STANDARD) {
902 return false;
903 }
904 RefPtr<NavigationGroupNode> navigationGroupNode;
905 if (parentType == TitleBarParentType::NAVBAR) {
906 auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
907 CHECK_NULL_RETURN(navBarNode, false);
908 navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(navBarNode->GetParent());
909 } else {
910 auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
911 CHECK_NULL_RETURN(navDestination, false);
912 auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
913 CHECK_NULL_RETURN(navDestinationPattern, false);
914 navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
915 }
916 CHECK_NULL_RETURN(navigationGroupNode, false);
917 auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigationGroupNode->GetPattern());
918 CHECK_NULL_RETURN(navigationPattern, false);
919 auto pageNode = navigationPattern->GetNavBasePageNode();
920 CHECK_NULL_RETURN(pageNode, false);
921 auto foldCreaseRects = pattern->GetFoldCreaseRects();
922 auto parentNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetParent());
923 CHECK_NULL_RETURN(parentNode, false);
924 bool isParentFullPage = pageNode->GetGeometryNode()->GetFrameSize().Height()
925 == parentNode->GetGeometryNode()->GetFrameSize().Height();
926 return !foldCreaseRects.empty() && isParentFullPage;
927 }
928
CalculateTitlebarOffset(const RefPtr<UINode> & titleBarNode)929 float NavigationTitleUtil::CalculateTitlebarOffset(const RefPtr<UINode>& titleBarNode)
930 {
931 CHECK_NULL_RETURN(titleBarNode, 0.0f);
932 auto titleBar = AceType::DynamicCast<TitleBarNode>(titleBarNode);
933 CHECK_NULL_RETURN(titleBar, 0.0f);
934 if (!IsNeedHoverModeAction(titleBar)) {
935 return 0.0f;
936 }
937 auto pattern = titleBar->GetPattern<TitleBarPattern>();
938 CHECK_NULL_RETURN(pattern, false);
939 auto foldCreaseRects = pattern->GetFoldCreaseRects();
940 auto pipelineContext = titleBar->GetContext();
941 CHECK_NULL_RETURN(pipelineContext, 0.0f);
942 if (!pipelineContext->IsHalfFoldHoverStatus()) {
943 return 0.0f;
944 }
945 auto safeArea = pipelineContext->GetSafeAreaWithoutProcess();
946 auto length = safeArea.top_.Length();
947 auto foldCrease = foldCreaseRects.front();
948
949 // offsetY = The Y of the foldCrease + Adapt vertical displacement of hover state - the height of the status bar.
950 return foldCrease.GetOffset().GetY() + TITLEBAR_VERTICAL_PADDING.ConvertToPx() - length;
951 }
952
IsTitleBarHasOffsetY(const RefPtr<FrameNode> & titleBarNode)953 bool NavigationTitleUtil::IsTitleBarHasOffsetY(const RefPtr<FrameNode>& titleBarNode)
954 {
955 return titleBarNode && titleBarNode->IsVisible() && !NearZero(CalculateTitlebarOffset(titleBarNode));
956 }
957
UpdateTitleOrToolBarTranslateYAndOpacity(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,float translate,bool isTitle)958 void NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(const RefPtr<NavDestinationNodeBase>& nodeBase,
959 const RefPtr<FrameNode>& barNode, float translate, bool isTitle)
960 {
961 CHECK_NULL_VOID(nodeBase);
962 CHECK_NULL_VOID(barNode);
963 auto renderContext = barNode->GetRenderContext();
964 CHECK_NULL_VOID(renderContext);
965 auto option = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
966 option.y = CalcDimension(translate, DimensionUnit::PX);
967 renderContext->UpdateTransformTranslate(option);
968 auto barHeight = renderContext->GetPaintRectWithoutTransform().Height();
969 float opacity = 1.0f;
970 if (!NearZero(barHeight)) {
971 opacity = 1.0f - std::clamp(std::abs(translate) / barHeight, 0.0f, 1.0f);
972 }
973 renderContext->UpdateOpacity(opacity);
974 if (isTitle) {
975 return;
976 }
977 auto divider = AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarDividerNode());
978 CHECK_NULL_VOID(divider);
979 auto dividerRenderContext = divider->GetRenderContext();
980 CHECK_NULL_VOID(dividerRenderContext);
981 dividerRenderContext->UpdateTransformTranslate(option);
982 dividerRenderContext->UpdateOpacity(opacity);
983 }
984 } // namespace OHOS::Ace::NG
985