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         BuildSymbolMoreItemNode(barItemNode, isButtonEnabled);
466     } else {
467         BuildImageMoreItemNode(barItemNode, isButtonEnabled);
468     }
469 }
470 
CreateBarItemNode(bool isButtonEnabled)471 RefPtr<BarItemNode> NavigationTitleUtil::CreateBarItemNode(bool isButtonEnabled)
472 {
473     int32_t barItemNodeId = ElementRegister::GetInstance()->MakeUniqueId();
474     auto barItemNode = BarItemNode::GetOrCreateBarItemNode(
475         V2::BAR_ITEM_ETS_TAG, barItemNodeId, []() { return AceType::MakeRefPtr<BarItemPattern>(); });
476     auto barItemLayoutProperty = barItemNode->GetLayoutProperty();
477     CHECK_NULL_RETURN(barItemLayoutProperty, nullptr);
478     barItemLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT);
479     BuildMoreIemNode(barItemNode, isButtonEnabled);
480     return barItemNode;
481 }
482 
HandleLongPress(const GestureEvent & info,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)483 void NavigationTitleUtil::HandleLongPress(
484     const GestureEvent& info, const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
485 {
486     CHECK_NULL_VOID(menuNode);
487     auto context = PipelineBase::GetCurrentContext();
488     CHECK_NULL_VOID(context);
489     auto dialogTheme = context->GetTheme<AgingAdapationDialogTheme>();
490     CHECK_NULL_VOID(dialogTheme);
491     float scale = context->GetFontScale();
492     if (LessNotEqual(scale, dialogTheme->GetBigFontSizeScale())) {
493         TAG_LOGI(AceLogTag::ACE_NAVIGATION,
494             "The current system font scale is %{public}f; dialogTheme font scale is %{public}f", scale,
495             dialogTheme->GetBigFontSizeScale());
496         return;
497     }
498     auto menuItemNode = menuNode->FindChildByPosition(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
499     CHECK_NULL_VOID(menuItemNode);
500     auto index = menuNode->GetChildIndex(menuItemNode);
501     auto dialogNode = CreatePopupDialogNode(menuItemNode, menuItems, index);
502     CHECK_NULL_VOID(dialogNode);
503     auto titleBarNode = menuNode->GetParentFrameNode();
504     CHECK_NULL_VOID(titleBarNode);
505     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
506     CHECK_NULL_VOID(titleBarPattern);
507     if (titleBarPattern->GetLargeFontPopUpDialogNode() != nullptr) {
508         HandleLongPressActionEnd(menuNode);
509     }
510     titleBarPattern->SetLargeFontPopUpDialogNode(dialogNode);
511 }
512 
HandleLongPressActionEnd(const RefPtr<FrameNode> & targetNode)513 void NavigationTitleUtil::HandleLongPressActionEnd(const RefPtr<FrameNode>& targetNode)
514 {
515     CHECK_NULL_VOID(targetNode);
516     auto titleBarNode = targetNode->GetParentFrameNode();
517     CHECK_NULL_VOID(titleBarNode);
518     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
519     CHECK_NULL_VOID(titleBarPattern);
520     auto dialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
521     CHECK_NULL_VOID(dialogNode);
522     auto pipeline = PipelineContext::GetCurrentContext();
523     CHECK_NULL_VOID(pipeline);
524     auto overlayManager = pipeline->GetOverlayManager();
525     CHECK_NULL_VOID(overlayManager);
526     overlayManager->CloseDialog(dialogNode);
527     titleBarPattern->SetLargeFontPopUpDialogNode(nullptr);
528 }
529 
InitDragAndLongPressEvent(const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)530 void NavigationTitleUtil::InitDragAndLongPressEvent(
531     const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
532 {
533     CHECK_NULL_VOID(menuNode);
534     auto pipeline = menuNode->GetContext();
535     CHECK_NULL_VOID(pipeline);
536     if (LessNotEqual(pipeline->GetFontScale(), AgingAdapationDialogUtil::GetDialogBigFontSizeScale())) {
537         return;
538     }
539 
540     auto gestureHub = menuNode->GetOrCreateGestureEventHub();
541     CHECK_NULL_VOID(gestureHub);
542     InitDragEvent(gestureHub, menuNode, menuItems);
543     InitLongPressEvent(gestureHub, menuNode, menuItems);
544     auto accessibilityProperty = menuNode->GetAccessibilityProperty<NG::AccessibilityProperty>();
545     CHECK_NULL_VOID(accessibilityProperty);
546     accessibilityProperty->SetAccessibilityLevel(AccessibilityProperty::Level::NO_STR);
547 }
548 
CreatePopupDialogNode(const RefPtr<FrameNode> targetNode,const std::vector<NG::BarItem> & menuItems,int32_t index)549 RefPtr<FrameNode> NavigationTitleUtil::CreatePopupDialogNode(
550     const RefPtr<FrameNode> targetNode, const std::vector<NG::BarItem>& menuItems, int32_t index)
551 {
552     CHECK_NULL_RETURN(targetNode, nullptr);
553     RefPtr<BarItemNode> barItemNode = AceType::DynamicCast<BarItemNode>(targetNode->GetFirstChild());
554     CHECK_NULL_RETURN(barItemNode, nullptr);
555     auto accessibilityProperty = targetNode->GetAccessibilityProperty<AccessibilityProperty>();
556     CHECK_NULL_RETURN(accessibilityProperty, nullptr);
557     ImageSourceInfo imageSourceInfo;
558     std::string message;
559     RefPtr<FrameNode> dialogNode;
560     if (barItemNode->IsMoreItemNode()) {
561         auto theme = NavigationGetTheme();
562         CHECK_NULL_RETURN(theme, nullptr);
563         message = Localization::GetInstance()->GetEntryLetters("common.more");
564         if (message.empty()) {
565             message = accessibilityProperty->GetAccessibilityText();
566         }
567         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
568             auto symbolNode = AceType::DynamicCast<FrameNode>(barItemNode->GetFirstChild());
569             CHECK_NULL_RETURN(symbolNode, nullptr);
570             dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, symbolNode);
571             return dialogNode;
572         }
573         imageSourceInfo.SetResourceId(theme->GetMoreResourceId());
574         dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, imageSourceInfo);
575         return dialogNode;
576     }
577     if (index < 0 || index >= static_cast<int32_t>(menuItems.size())) {
578         return nullptr;
579     }
580     auto menuItem = menuItems.at(index);
581     if (menuItem.text.has_value() && !menuItem.text.value().empty()) {
582         message = menuItem.text.value();
583     } else {
584         message = accessibilityProperty->GetAccessibilityText();
585     }
586     if (menuItem.iconSymbol.has_value() && menuItem.iconSymbol.value() != nullptr) {
587         return CreateSymbolDialog(message, barItemNode);
588     }
589     if (menuItem.icon.has_value() && !menuItem.icon.value().empty()) {
590         imageSourceInfo = ImageSourceInfo(menuItem.icon.value());
591     }
592     dialogNode = AgingAdapationDialogUtil::ShowLongPressDialog(message, imageSourceInfo);
593     return dialogNode;
594 }
595 
CreateSymbolDialog(const std::string & message,const RefPtr<FrameNode> & targetNode)596 RefPtr<FrameNode> NavigationTitleUtil::CreateSymbolDialog(
597     const std::string& message, const RefPtr<FrameNode>& targetNode)
598 {
599     auto barItemNode = AceType::DynamicCast<BarItemNode>(targetNode);
600     CHECK_NULL_RETURN(barItemNode, nullptr);
601     auto iconNode = AceType::DynamicCast<FrameNode>(barItemNode->GetIconNode());
602     CHECK_NULL_RETURN(iconNode, nullptr);
603     return AgingAdapationDialogUtil::ShowLongPressDialog(message, iconNode);
604 }
605 
SetAccessibility(const RefPtr<FrameNode> & node,const std::string & message)606 void NavigationTitleUtil::SetAccessibility(const RefPtr<FrameNode>& node, const std::string& message)
607 {
608     CHECK_NULL_VOID(node);
609     auto accessibilityProperty = node->GetAccessibilityProperty<NG::AccessibilityProperty>();
610     CHECK_NULL_VOID(accessibilityProperty);
611     accessibilityProperty->SetAccessibilityText(message);
612     accessibilityProperty->SetAccessibilityGroup(true);
613 }
614 
GetTitleString(const RefPtr<TitleBarNode> & titleBarNode,bool isCustom)615 std::string NavigationTitleUtil::GetTitleString(const RefPtr<TitleBarNode>& titleBarNode, bool isCustom)
616 {
617     if (isCustom) {
618         return "";
619     }
620     CHECK_NULL_RETURN(titleBarNode, "");
621     auto title = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
622     CHECK_NULL_RETURN(title, "");
623     if (title->GetTag() != V2::TEXT_ETS_TAG) {
624         return "";
625     }
626     auto textLayoutProperty = title->GetLayoutProperty<TextLayoutProperty>();
627     CHECK_NULL_RETURN(textLayoutProperty, "");
628     return textLayoutProperty->GetContentValue("");
629 }
630 
GetSubtitleString(const RefPtr<TitleBarNode> & titleBarNode)631 std::string NavigationTitleUtil::GetSubtitleString(const RefPtr<TitleBarNode>& titleBarNode)
632 {
633     CHECK_NULL_RETURN(titleBarNode, "");
634     auto subtitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
635     CHECK_NULL_RETURN(subtitle, "");
636     if (subtitle->GetTag() != V2::TEXT_ETS_TAG) {
637         return "";
638     }
639     auto textLayoutProperty = subtitle->GetLayoutProperty<TextLayoutProperty>();
640     CHECK_NULL_RETURN(textLayoutProperty, "");
641     return textLayoutProperty->GetContentValue("");
642 }
643 
InitDragEvent(const RefPtr<GestureEventHub> & gestureHub,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)644 void NavigationTitleUtil::InitDragEvent(const RefPtr<GestureEventHub>& gestureHub, const RefPtr<FrameNode>& menuNode,
645     const std::vector<NG::BarItem>& menuItems)
646 {
647     auto actionUpdateTask = [weakMenuNode = WeakPtr<FrameNode>(menuNode), menuItems](const GestureEvent& info) {
648         auto menuNode = weakMenuNode.Upgrade();
649         CHECK_NULL_VOID(menuNode);
650         auto menuItemNode =
651             menuNode->FindChildByPosition(info.GetGlobalLocation().GetX(), info.GetGlobalLocation().GetY());
652         CHECK_NULL_VOID(menuItemNode);
653         auto index = menuNode->GetChildIndex(menuItemNode);
654         auto totalCount = menuNode->TotalChildCount();
655         auto titleBarNode = menuNode->GetParentFrameNode();
656         CHECK_NULL_VOID(titleBarNode);
657         auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
658         CHECK_NULL_VOID(titleBarPattern);
659         auto dialogNode = titleBarPattern->GetLargeFontPopUpDialogNode();
660         if (dialogNode && index >= 0 && index < totalCount) {
661             if (!titleBarPattern->GetMoveIndex().has_value()) {
662                 titleBarPattern->SetMoveIndex(index);
663             }
664 
665             if (titleBarPattern->GetMoveIndex().value() != index) {
666                 HandleLongPressActionEnd(menuNode);
667                 titleBarPattern->SetMoveIndex(index);
668                 titleBarPattern->SetLargeFontPopUpDialogNode(CreatePopupDialogNode(menuItemNode, menuItems, index));
669             }
670         }
671     };
672 
673     auto dragEvent = AceType::MakeRefPtr<DragEvent>(nullptr, std::move(actionUpdateTask), nullptr, nullptr);
674     PanDirection panDirection = { .type = PanDirection::ALL };
675     gestureHub->SetDragEvent(dragEvent, panDirection, DEFAULT_PAN_FINGER, DEFAULT_PAN_DISTANCE);
676 }
677 
InitLongPressEvent(const RefPtr<GestureEventHub> & gestureHub,const RefPtr<FrameNode> & menuNode,const std::vector<NG::BarItem> & menuItems)678 void NavigationTitleUtil::InitLongPressEvent(const RefPtr<GestureEventHub>& gestureHub,
679     const RefPtr<FrameNode>& menuNode, const std::vector<NG::BarItem>& menuItems)
680 {
681     auto longPressCallback = [weakTargetNode = WeakPtr<FrameNode>(menuNode), menuItems](GestureEvent& info) {
682         auto menuNode = weakTargetNode.Upgrade();
683         NavigationTitleUtil::HandleLongPress(info, menuNode, menuItems);
684     };
685     auto longPressEvent = AceType::MakeRefPtr<LongPressEvent>(std::move(longPressCallback));
686     gestureHub->SetLongPressEvent(longPressEvent);
687 
688     auto longPressRecognizer = gestureHub->GetLongPressRecognizer();
689     CHECK_NULL_VOID(longPressRecognizer);
690 
691     auto longPressEndCallback = [weakTargetNode = WeakPtr<FrameNode>(menuNode)](GestureEvent& info) {
692         auto menuNode = weakTargetNode.Upgrade();
693         NavigationTitleUtil::HandleLongPressActionEnd(menuNode);
694     };
695     longPressRecognizer->SetOnActionEnd(longPressEndCallback);
696 }
697 
CreateOrUpdateMainTitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo,bool ignoreMainTitle)698 void NavigationTitleUtil::CreateOrUpdateMainTitle(const RefPtr<TitleBarNode>& titleBarNode,
699     const NG::NavigationTitleInfo& titleInfo, bool ignoreMainTitle)
700 {
701     CHECK_NULL_VOID(titleBarNode);
702     if (ignoreMainTitle) {
703         return;
704     }
705     auto mainTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
706     if (!titleInfo.hasMainTitle) {
707         // remove main title if any.
708         titleBarNode->RemoveChild(mainTitle);
709         titleBarNode->SetTitle(nullptr);
710         return;
711     }
712 
713     if (mainTitle) {
714         // update main title
715         auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
716         CHECK_NULL_VOID(textLayoutProperty);
717         textLayoutProperty->UpdateMaxLines(titleInfo.hasSubTitle ? 1 : TITLEBAR_MAX_LINES);
718         textLayoutProperty->UpdateContent(titleInfo.title);
719         return;
720     }
721     // create and init main title
722     mainTitle = FrameNode::CreateFrameNode(
723         V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
724     auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
725     CHECK_NULL_VOID(textLayoutProperty);
726     textLayoutProperty->UpdateContent(titleInfo.title);
727     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
728     CHECK_NULL_VOID(titleBarPattern);
729     titleBarPattern->SetNeedResetMainTitleProperty(true);
730     titleBarNode->SetTitle(mainTitle);
731     titleBarNode->AddChild(mainTitle);
732 }
733 
CreateOrUpdateSubtitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)734 void NavigationTitleUtil::CreateOrUpdateSubtitle(const RefPtr<TitleBarNode>& titleBarNode,
735     const NG::NavigationTitleInfo& titleInfo)
736 {
737     CHECK_NULL_VOID(titleBarNode);
738     auto subTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
739     if (!titleInfo.hasSubTitle) {
740         // remove subtitle if any.
741         titleBarNode->RemoveChild(subTitle);
742         titleBarNode->SetSubtitle(nullptr);
743         return;
744     }
745     if (subTitle) {
746         // update subtitle
747         auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
748         CHECK_NULL_VOID(textLayoutProperty);
749         textLayoutProperty->UpdateContent(titleInfo.subtitle);
750         auto renderContext = subTitle->GetRenderContext();
751         CHECK_NULL_VOID(renderContext);
752         renderContext->UpdateOpacity(1.0);
753         return;
754     }
755     // create and init subtitle
756     subTitle = FrameNode::CreateFrameNode(
757         V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
758     auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
759     CHECK_NULL_VOID(textLayoutProperty);
760     textLayoutProperty->UpdateContent(titleInfo.subtitle);
761     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
762     CHECK_NULL_VOID(titleBarPattern);
763     titleBarPattern->SetNeedResetSubTitleProperty(true);
764     titleBarNode->SetSubtitle(subTitle);
765     titleBarNode->AddChild(subTitle);
766 }
767 
CreateOrUpdateDestinationMainTitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)768 void NavigationTitleUtil::CreateOrUpdateDestinationMainTitle(const RefPtr<TitleBarNode>& titleBarNode,
769     const NG::NavigationTitleInfo& titleInfo)
770 {
771     CHECK_NULL_VOID(titleBarNode);
772     auto mainTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetTitle());
773     if (!titleInfo.hasMainTitle) {
774         // remove main title if any.
775         titleBarNode->RemoveChild(mainTitle);
776         titleBarNode->SetTitle(nullptr);
777         return;
778     }
779     if (mainTitle) {
780         // update main title
781         auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
782         CHECK_NULL_VOID(textLayoutProperty);
783         textLayoutProperty->UpdateMaxLines(titleInfo.hasSubTitle ? 1 : TITLEBAR_MAX_LINES);
784         if (AceApplicationInfo::GetInstance().GreatOrEqualTargetAPIVersion(PlatformVersion::VERSION_TWELVE)) {
785             textLayoutProperty->UpdateHeightAdaptivePolicy(titleInfo.hasSubTitle ?
786             TextHeightAdaptivePolicy::MAX_LINES_FIRST : TextHeightAdaptivePolicy::MIN_FONT_SIZE_FIRST);
787         }
788         textLayoutProperty->UpdateContent(titleInfo.title);
789         textLayoutProperty->UpdateMaxFontScale(STANDARD_FONT_SCALE);
790         return;
791     }
792     // create and init main title
793     mainTitle = FrameNode::CreateFrameNode(
794         V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
795     auto textLayoutProperty = mainTitle->GetLayoutProperty<TextLayoutProperty>();
796     CHECK_NULL_VOID(textLayoutProperty);
797     textLayoutProperty->UpdateContent(titleInfo.title);
798     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
799     CHECK_NULL_VOID(titleBarPattern);
800     titleBarPattern->SetNeedResetMainTitleProperty(true);
801     titleBarNode->SetTitle(mainTitle);
802     titleBarNode->AddChild(mainTitle);
803 }
804 
CreateOrUpdateDestinationSubtitle(const RefPtr<TitleBarNode> & titleBarNode,const NG::NavigationTitleInfo & titleInfo)805 void NavigationTitleUtil::CreateOrUpdateDestinationSubtitle(const RefPtr<TitleBarNode>& titleBarNode,
806     const NG::NavigationTitleInfo& titleInfo)
807 {
808     CHECK_NULL_VOID(titleBarNode);
809     auto subTitle = AceType::DynamicCast<FrameNode>(titleBarNode->GetSubtitle());
810     if (!titleInfo.hasSubTitle) {
811         // remove subtitle if any.
812         titleBarNode->RemoveChild(subTitle);
813         titleBarNode->SetSubtitle(nullptr);
814         return;
815     }
816     if (subTitle) {
817         // update subtitle
818         auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
819         CHECK_NULL_VOID(textLayoutProperty);
820         textLayoutProperty->UpdateContent(titleInfo.subtitle);
821         textLayoutProperty->UpdateMaxFontScale(STANDARD_FONT_SCALE);
822         return;
823     }
824     // create and init subtitle
825     subTitle = FrameNode::CreateFrameNode(
826         V2::TEXT_ETS_TAG, ElementRegister::GetInstance()->MakeUniqueId(), AceType::MakeRefPtr<TextPattern>());
827     auto textLayoutProperty = subTitle->GetLayoutProperty<TextLayoutProperty>();
828     CHECK_NULL_VOID(textLayoutProperty);
829     textLayoutProperty->UpdateContent(titleInfo.subtitle);
830     auto titleBarPattern = titleBarNode->GetPattern<TitleBarPattern>();
831     CHECK_NULL_VOID(titleBarPattern);
832     titleBarPattern->SetNeedResetSubTitleProperty(true);
833     titleBarNode->SetSubtitle(subTitle);
834     titleBarNode->AddChild(subTitle);
835 }
836 
FoldStatusChangedAnimation(const RefPtr<FrameNode> & host)837 void NavigationTitleUtil::FoldStatusChangedAnimation(const RefPtr<FrameNode>& host)
838 {
839     CHECK_NULL_VOID(host);
840     auto pipelineContext = host->GetContext();
841     CHECK_NULL_VOID(pipelineContext);
842     auto titleBar = AceType::DynamicCast<TitleBarNode>(host);
843     CHECK_NULL_VOID(titleBar);
844     auto pattern = titleBar->GetPattern<TitleBarPattern>();
845     CHECK_NULL_VOID(pattern);
846 
847     if (!pipelineContext->IsHoverModeChange() || !IsNeedHoverModeAction(titleBar)) {
848         // Since only expanded to hover or hover to expanded need this animation.
849         return;
850     }
851 
852     AnimationOption option;
853     option.SetCurve(TITLEBAR_OPACITY_ANIMATION_CURVE);
854     auto renderNodeContext = host->GetRenderContext();
855     CHECK_NULL_VOID(renderNodeContext);
856     option.SetDuration(TITLEBAR_OPACITY_ANIMATION_DURATION);
857     renderNodeContext->UpdateOpacity(1.0f);
858     option.SetOnFinishEvent([weakRenderNodeContext = WeakPtr<RenderContext>(renderNodeContext),
859                                 weakHost = WeakPtr<FrameNode>(host)]() {
860         auto host = weakHost.Upgrade();
861         CHECK_NULL_VOID(host);
862         auto renderContext = weakRenderNodeContext.Upgrade();
863         CHECK_NULL_VOID(renderContext);
864         AnimationOption finishOption;
865         finishOption.SetDuration(TITLEBAR_OPACITY_ANIMATION_DURATION);
866         finishOption.SetCurve(TITLEBAR_OPACITY_ANIMATION_CURVE);
867         auto parent = AceType::DynamicCast<FrameNode>(host->GetParent());
868         CHECK_NULL_VOID(parent);
869         parent->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
870         AnimationUtils::Animate(
871             finishOption, [weakRenderNodeContext = WeakPtr<RenderContext>(renderContext)]() {
872                 auto renderNodeContext = weakRenderNodeContext.Upgrade();
873                 CHECK_NULL_VOID(renderNodeContext);
874                 renderNodeContext->UpdateOpacity(1.0f);
875             });
876     });
877     AnimationUtils::Animate(
878         option,
879         [weakRenderNodeContext = WeakPtr<RenderContext>(renderNodeContext)]() {
880             auto renderContext = weakRenderNodeContext.Upgrade();
881             CHECK_NULL_VOID(renderContext);
882             renderContext->UpdateOpacity(0.0f);
883         },
884         option.GetOnFinishEvent());
885 }
886 
IsNeedHoverModeAction(const RefPtr<TitleBarNode> & titleBarNode)887 bool NavigationTitleUtil::IsNeedHoverModeAction(const RefPtr<TitleBarNode>& titleBarNode)
888 {
889     CHECK_NULL_RETURN(titleBarNode, false);
890     auto pattern = titleBarNode->GetPattern<TitleBarPattern>();
891     CHECK_NULL_RETURN(pattern, false);
892     auto options = pattern->GetTitleBarOptions();
893     auto titleBarLayoutProperty = titleBarNode->GetLayoutProperty<TitleBarLayoutProperty>();
894     CHECK_NULL_RETURN(titleBarLayoutProperty, false);
895     auto parentType = titleBarLayoutProperty->GetTitleBarParentTypeValue(TitleBarParentType::NAVBAR);
896     if (parentType == TitleBarParentType::NAVBAR &&
897         titleBarLayoutProperty->GetTitleModeValue(NavigationTitleMode::MINI) == NavigationTitleMode::FREE) {
898         return false;
899     }
900     if (!options.enableHoverMode || options.brOptions.barStyle == NG::BarStyle::STANDARD) {
901         return false;
902     }
903     RefPtr<NavigationGroupNode> navigationGroupNode;
904     if (parentType == TitleBarParentType::NAVBAR) {
905         auto navBarNode = AceType::DynamicCast<NavBarNode>(titleBarNode->GetParent());
906         CHECK_NULL_RETURN(navBarNode, false);
907         navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(navBarNode->GetParent());
908     } else {
909         auto navDestination = AceType::DynamicCast<NavDestinationGroupNode>(titleBarNode->GetParent());
910         CHECK_NULL_RETURN(navDestination, false);
911         auto navDestinationPattern = navDestination->GetPattern<NavDestinationPattern>();
912         CHECK_NULL_RETURN(navDestinationPattern, false);
913         navigationGroupNode = AceType::DynamicCast<NavigationGroupNode>(navDestinationPattern->GetNavigationNode());
914     }
915     CHECK_NULL_RETURN(navigationGroupNode, false);
916     auto navigationPattern = AceType::DynamicCast<NavigationPattern>(navigationGroupNode->GetPattern());
917     CHECK_NULL_RETURN(navigationPattern, false);
918     auto pageNode = navigationPattern->GetNavBasePageNode();
919     CHECK_NULL_RETURN(pageNode, false);
920     auto foldCreaseRects = pattern->GetFoldCreaseRects();
921     auto parentNode = AceType::DynamicCast<FrameNode>(titleBarNode->GetParent());
922     CHECK_NULL_RETURN(parentNode, false);
923     bool isParentFullPage = pageNode->GetGeometryNode()->GetFrameSize().Height()
924         == parentNode->GetGeometryNode()->GetFrameSize().Height();
925     return !foldCreaseRects.empty() && isParentFullPage;
926 }
927 
CalculateTitlebarOffset(const RefPtr<UINode> & titleBarNode)928 float NavigationTitleUtil::CalculateTitlebarOffset(const RefPtr<UINode>& titleBarNode)
929 {
930     CHECK_NULL_RETURN(titleBarNode, 0.0f);
931     auto titleBar = AceType::DynamicCast<TitleBarNode>(titleBarNode);
932     CHECK_NULL_RETURN(titleBar, 0.0f);
933     if (!IsNeedHoverModeAction(titleBar)) {
934         return 0.0f;
935     }
936     auto pattern = titleBar->GetPattern<TitleBarPattern>();
937     CHECK_NULL_RETURN(pattern, false);
938     auto foldCreaseRects = pattern->GetFoldCreaseRects();
939     auto pipelineContext = titleBar->GetContext();
940     CHECK_NULL_RETURN(pipelineContext, 0.0f);
941     if (!pipelineContext->IsHalfFoldHoverStatus()) {
942         return 0.0f;
943     }
944     auto safeArea = pipelineContext->GetSafeAreaWithoutProcess();
945     auto length = safeArea.top_.Length();
946     auto foldCrease = foldCreaseRects.front();
947 
948     // offsetY = The Y of the foldCrease + Adapt vertical displacement of hover state - the height of the status bar.
949     return foldCrease.GetOffset().GetY() + TITLEBAR_VERTICAL_PADDING.ConvertToPx() - length;
950 }
951 
IsTitleBarHasOffsetY(const RefPtr<FrameNode> & titleBarNode)952 bool NavigationTitleUtil::IsTitleBarHasOffsetY(const RefPtr<FrameNode>& titleBarNode)
953 {
954     return titleBarNode && titleBarNode->IsVisible() && !NearZero(CalculateTitlebarOffset(titleBarNode));
955 }
956 
UpdateTitleOrToolBarTranslateYAndOpacity(const RefPtr<NavDestinationNodeBase> & nodeBase,const RefPtr<FrameNode> & barNode,float translate,bool isTitle)957 void NavigationTitleUtil::UpdateTitleOrToolBarTranslateYAndOpacity(const RefPtr<NavDestinationNodeBase>& nodeBase,
958     const RefPtr<FrameNode>& barNode, float translate, bool isTitle)
959 {
960     CHECK_NULL_VOID(nodeBase);
961     CHECK_NULL_VOID(barNode);
962     auto renderContext = barNode->GetRenderContext();
963     CHECK_NULL_VOID(renderContext);
964     auto option = renderContext->GetTransformTranslateValue(TranslateOptions(0.0f, 0.0f, 0.0f));
965     option.y = CalcDimension(translate, DimensionUnit::PX);
966     renderContext->UpdateTransformTranslate(option);
967     auto barHeight = renderContext->GetPaintRectWithoutTransform().Height();
968     float opacity = 1.0f;
969     if (!NearZero(barHeight)) {
970         opacity = 1.0f - std::clamp(std::abs(translate) / barHeight, 0.0f, 1.0f);
971     }
972     renderContext->UpdateOpacity(opacity);
973     if (isTitle) {
974         return;
975     }
976     auto divider = AceType::DynamicCast<FrameNode>(nodeBase->GetToolBarDividerNode());
977     CHECK_NULL_VOID(divider);
978     auto dividerRenderContext = divider->GetRenderContext();
979     CHECK_NULL_VOID(dividerRenderContext);
980     dividerRenderContext->UpdateTransformTranslate(option);
981     dividerRenderContext->UpdateOpacity(opacity);
982 }
983 } // namespace OHOS::Ace::NG
984