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