1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/navigation_bar/navigation_bar_component_v2.h"
17
18 #include "core/components/display/display_component.h"
19 #include "core/components/flex/flex_item_component.h"
20 #include "core/components/navigation_bar/navigation_bar_element.h"
21 #include "core/components/padding/padding_component.h"
22 #include "core/components/transform/transform_component.h"
23
24 namespace OHOS::Ace {
25 namespace {
26
27 constexpr double MIDDLE_ZONE_FLEX_GROW = 1.0;
28 constexpr double MIDDLE_ZONE_FLEX_SHRINK = 1.0;
29 constexpr double MENU_DEFAULT_HEIGHT = 56.0;
30
31 } // namespace
32
BuildMiniLayer()33 RefPtr<Component> NavigationBarBuilder::BuildMiniLayer()
34 {
35 Edge padding;
36 RefPtr<RowComponent> container =
37 AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_START, FlexAlign::CENTER, std::list<RefPtr<Component>>());
38 container->SetTextDirection(direction_);
39
40 if (!declaration_->hideBarBackButton) {
41 IconImage backIcon(theme_->GetBackResourceId(), menuIconSize_, menuIconSize_);
42 backIcon.image->SetTextDirection(direction_);
43 backIcon.image->SetMatchTextDirection(true);
44 backIcon.image->SetColor(theme_->GetMenuIconColor());
45 auto backButton = BuildIconButton(theme_, menuZoneSize_, menuZoneSize_, backIcon, backClickMarker_);
46 EventMarker clickEventId([weakContext = context_](const BaseEventInfo* info) {
47 auto context = weakContext.Upgrade();
48 if (!context) {
49 LOGW("context is empty");
50 return;
51 }
52 if (!context->CallRouterBackToPopPage()) {
53 context->Finish(false);
54 }
55 });
56 backButton->SetClickedEventId(clickEventId);
57 container->AppendChild(GenerateAccessibilityComposed(StringUtils::StringToInt(id_), "backButton", backButton));
58 container->AppendChild(BuildPadding(theme_->GetTitleMinPadding().Value()));
59 padding.SetLeft(theme_->GetDefaultPaddingStart());
60 } else {
61 container->AppendChild(BuildPadding(theme_->GetMaxPaddingStart().Value()));
62 }
63
64 container->AppendChild(BuildTitle());
65 container->SetUpdateType(UpdateType::REBUILD);
66
67 if (AddMenu(container)) {
68 padding.SetRight(theme_->GetDefaultPaddingEnd());
69 } else {
70 padding.SetRight(theme_->GetMaxPaddingStart() - theme_->GetTitleMinPadding());
71 }
72
73 return BuildAnimationContainer(container, theme_->GetHeight(), padding);
74 }
75
BuildFullLayer()76 RefPtr<Component> NavigationBarBuilder::BuildFullLayer()
77 {
78 RefPtr<ColumnComponent> columnContainer =
79 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::STRETCH, std::list<RefPtr<Component>>());
80 columnContainer->SetTextDirection(direction_);
81 columnContainer->SetCrossAxisSize(CrossAxisSize::MAX);
82 columnContainer->AppendChild(BuildTitle());
83
84 RefPtr<RowComponent> menuContainer =
85 AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_END, FlexAlign::CENTER, std::list<RefPtr<Component>>());
86 menuContainer->SetTextDirection(direction_);
87 AddMenu(menuContainer);
88 auto menusBox = AceType::MakeRefPtr<BoxComponent>();
89 menusBox->SetHeight(theme_->GetHeight().Value(), theme_->GetHeight().Unit());
90 menusBox->SetChild(menuContainer);
91
92 RefPtr<ColumnComponent> container =
93 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::STRETCH, std::list<RefPtr<Component>>());
94 container->SetTextDirection(direction_);
95 container->SetCrossAxisSize(CrossAxisSize::MAX);
96 container->AppendChild(menusBox);
97 container->AppendChild(columnContainer);
98
99 Edge padding;
100 padding.SetLeft(theme_->GetMaxPaddingStart());
101 padding.SetRight(theme_->GetDefaultPaddingEnd());
102 return BuildAnimationContainer(container, theme_->GetHeightEmphasize(), padding);
103 }
104
BuildFreeModeBar()105 RefPtr<Component> NavigationBarBuilder::BuildFreeModeBar()
106 {
107 Edge padding;
108 padding.SetLeft(theme_->GetMaxPaddingStart());
109 padding.SetRight(theme_->GetMaxPaddingStart());
110 RefPtr<ColumnComponent> columnContainer =
111 AceType::MakeRefPtr<ColumnComponent>(FlexAlign::FLEX_START, FlexAlign::STRETCH, std::list<RefPtr<Component>>());
112 columnContainer->SetTextDirection(direction_);
113 columnContainer->SetCrossAxisSize(CrossAxisSize::MAX);
114 columnContainer->AppendChild(BuildTitle());
115 auto columnBox = AceType::MakeRefPtr<BoxComponent>();
116 columnBox->SetChild(columnContainer);
117 columnBox->SetPadding(padding);
118
119 padding.SetLeft(theme_->GetDefaultPaddingEnd());
120 padding.SetRight(theme_->GetDefaultPaddingEnd());
121 RefPtr<RowComponent> menuContainer =
122 AceType::MakeRefPtr<RowComponent>(FlexAlign::FLEX_END, FlexAlign::CENTER, std::list<RefPtr<Component>>());
123 menuContainer->SetTextDirection(direction_);
124 AddMenu(menuContainer);
125 auto menusBox = AceType::MakeRefPtr<BoxComponent>();
126 menusBox->SetHeight(theme_->GetHeight().Value(), theme_->GetHeight().Unit());
127 menusBox->SetChild(menuContainer);
128 menusBox->SetPadding(padding);
129
130 auto height = !declaration_->subTitle.empty() ? Dimension(134, DimensionUnit::VP) : theme_->GetHeightEmphasize();
131 RefPtr<CollapsingNavigationBarComponent> collapsingNavigationBar =
132 AceType::MakeRefPtr<CollapsingNavigationBarComponent>(
133 titleComposed_, subTitleComposed_, declaration_->titleModeChangedEvent);
134 collapsingNavigationBar->AppendChild(menusBox);
135 collapsingNavigationBar->AppendChild(columnBox);
136 collapsingNavigationBar->SetMinHeight(theme_->GetHeight());
137
138 return BuildAnimationContainer(collapsingNavigationBar, height, Edge());
139 }
140
BuildAnimationContainer(const RefPtr<Component> & content,const Dimension & height,const Edge & padding)141 RefPtr<Component> NavigationBarBuilder::BuildAnimationContainer(
142 const RefPtr<Component>& content, const Dimension& height, const Edge& padding)
143 {
144 auto boxContainer = AceType::MakeRefPtr<BoxComponent>();
145 boxContainer->SetChild(content);
146 boxContainer->SetPadding(padding);
147 auto display = AceType::MakeRefPtr<DisplayComponent>();
148 display->SetChild(boxContainer);
149 if (!declaration_->hideBar) {
150 boxContainer->SetHeight(height, declaration_->animationOption);
151 display->SetOpacity(1.0, declaration_->animationOption);
152 } else {
153 boxContainer->SetHeight(Dimension(0.0, height.Unit()), declaration_->animationOption);
154 display->SetOpacity(0.0, declaration_->animationOption);
155 }
156 return display;
157 }
158
BuildTitle()159 RefPtr<Component> NavigationBarBuilder::BuildTitle()
160 {
161 RefPtr<ColumnComponent> titleContainer = AceType::MakeRefPtr<ColumnComponent>(
162 FlexAlign::FLEX_START, FlexAlign::FLEX_START, std::list<RefPtr<Component>>());
163 titleContainer->SetTextDirection(direction_);
164 titleContainer->SetMainAxisSize(MainAxisSize::MIN);
165
166 if (declaration_->customTitle || !declaration_->title.empty()) {
167 RefPtr<Component> title;
168 if (declaration_->customTitle) {
169 title = declaration_->customTitle;
170 } else {
171 title = BuildTitleText(
172 declaration_->title, theme_->GetTitleColor(), theme_->GetTitleFontSize(), FontWeight::W500);
173 }
174 auto transform = AceType::MakeRefPtr<TransformComponent>();
175 transform->SetChild(title);
176 transform->SetOriginDimension(DimensionOffset(Offset(0.0, 0.0)));
177 titleComposed_ = GenerateAccessibilityComposed(StringUtils::StringToInt(id_), "titleText", transform);
178 titleContainer->AppendChild(titleComposed_);
179 }
180 if (!declaration_->subTitle.empty()) {
181 titleContainer->AppendChild(BuildPadding(2, true));
182 auto subTitleText = BuildTitleText(
183 declaration_->subTitle, theme_->GetSubTitleColor(), theme_->GetSubTitleFontSize(), FontWeight::W400);
184 auto display = AceType::MakeRefPtr<DisplayComponent>(subTitleText);
185 subTitleComposed_ = GenerateAccessibilityComposed(StringUtils::StringToInt(id_), "subTitleText", display);
186 titleContainer->AppendChild(subTitleComposed_);
187 }
188
189 return AceType::MakeRefPtr<FlexItemComponent>(MIDDLE_ZONE_FLEX_GROW, MIDDLE_ZONE_FLEX_SHRINK, 0.0, titleContainer);
190 }
191
AddMenu(const RefPtr<ComponentGroup> & container)192 bool NavigationBarBuilder::AddMenu(const RefPtr<ComponentGroup>& container)
193 {
194 if (declaration_->customMenus) {
195 LOGE("arg is customMenus.");
196 container->AppendChild(declaration_->customMenus);
197 return true;
198 }
199 uint32_t showInBarSize = 0;
200 bool hasRoom = true;
201 uint32_t mostShowInBarSize =
202 menuCount_ > 0 ? static_cast<uint32_t>(menuCount_) : theme_->GetMostMenuItemCountInBar();
203 bool needAddPadding = false;
204 menu_ = AceType::MakeRefPtr<MenuComponent>("", "navigationMenu");
205 auto ctx = context_.Upgrade();
206 if (ctx) {
207 auto themeManager = ctx->GetThemeManager();
208 if (themeManager) {
209 menu_->SetTheme(themeManager->GetTheme<SelectTheme>());
210 }
211 }
212 auto menusSize = declaration_->menuItems.size();
213 for (const auto& menuItem : declaration_->menuItems) {
214 hasRoom = hasRoom && ((showInBarSize < mostShowInBarSize - 1) ||
215 (showInBarSize == mostShowInBarSize - 1 && menusSize == mostShowInBarSize) ||
216 (showInBarSize < mostShowInBarSize && SystemProperties::GetDeviceType() == DeviceType::TV));
217 if (hasRoom) {
218 showInBarSize++;
219 IconImage menuIcon(menuItem->icon, menuIconSize_, menuIconSize_);
220 auto optionButton = BuildIconButton(theme_, menuZoneSize_, menuZoneSize_, menuIcon);
221 if (theme_->GetMenuItemPadding().Value() > 0.0 && needAddPadding) {
222 container->AppendChild(BuildPadding(theme_->GetMenuItemPadding().Value()));
223 }
224 optionButton->SetClickedEventId(menuItem->actionWithParam);
225 container->AppendChild(
226 GenerateAccessibilityComposed(StringUtils::StringToInt(id_), "optionButton", optionButton));
227 needAddPadding = true;
228 } else {
229 AddOption(menuItem);
230 }
231 }
232 if (menu_->GetOptionCount() > 0) {
233 // add collapse menu
234 IconImage moreIcon(theme_->GetMoreResourceId(), menuIconSize_, menuIconSize_);
235 moreIcon.image->SetColor(theme_->GetMenuIconColor());
236 moreButton_ = BuildIconButton(theme_, menuZoneSize_, menuZoneSize_, moreIcon);
237 container->AppendChild(GenerateAccessibilityComposed(StringUtils::StringToInt(id_), "moreButton", moreButton_));
238 container->AppendChild(menu_);
239 }
240 BindMoreButtonClickEvent();
241 return showInBarSize > 0 || menu_->GetOptionCount() > 0;
242 }
243
AddOption(const RefPtr<ToolBarItem> & menuItem)244 void NavigationBarBuilder::AddOption(const RefPtr<ToolBarItem>& menuItem)
245 {
246 auto optionComponent = AceType::MakeRefPtr<OptionComponent>();
247 auto ctx = context_.Upgrade();
248 if (ctx) {
249 auto themeManager = ctx->GetThemeManager();
250 if (themeManager) {
251 optionComponent->InitTheme(themeManager);
252 }
253 }
254 optionComponent->SetText(AceType::MakeRefPtr<TextComponent>(menuItem->value));
255 optionComponent->SetValue(menuItem->value);
256 optionComponent->SetIcon(AceType::MakeRefPtr<ImageComponent>(menuItem->icon));
257 optionComponent->SetClickEvent(menuItem->action);
258 menu_->AppendOption(optionComponent);
259 }
260
BindMoreButtonClickEvent()261 void NavigationBarBuilder::BindMoreButtonClickEvent()
262 {
263 if (!moreButton_) {
264 return;
265 }
266 EventMarker clickEventId([menu = menu_, context = context_](const BaseEventInfo* info) {
267 if (!menu) {
268 return;
269 }
270 auto showMenuFunc = menu->GetTargetCallback();
271 if (!showMenuFunc) {
272 return;
273 }
274 auto ctx = context.Upgrade();
275 if (!ctx) {
276 return;
277 }
278 double morePopupOffsetX = 0.0;
279 morePopupOffsetX = ctx->GetStageRect().Width();
280 showMenuFunc("", Offset(morePopupOffsetX, MENU_DEFAULT_HEIGHT));
281 });
282 moreButton_->SetClickedEventId(clickEventId);
283 }
284
285 } // namespace OHOS::Ace
286