1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "core/components_ng/pattern/app_bar/atomic_service_pattern.h"
16 #include <string>
17
18 #include "core/components_ng/pattern/button/button_pattern.h"
19 #include "core/components_ng/pattern/divider/divider_render_property.h"
20 #include "core/components_ng/pattern/image/image_layout_property.h"
21 #include "core/components_ng/pattern/image/image_render_property.h"
22 #include "core/components_ng/base/inspector.h"
23
24 namespace OHOS::Ace::NG {
25 constexpr int32_t ATOMIC_SERVICE_MIN_SIZE = 2;
26 constexpr int32_t FIRST_OVERLAY_INDEX = 1;
27
BeforeCreateLayoutWrapper()28 void AtomicServicePattern::BeforeCreateLayoutWrapper()
29 {
30 MenuBarSafeAreaCallBack();
31 ContentSafeAreaCallBack();
32 ColorConfigurationCallBack();
33 }
34
MenuBarSafeAreaCallBack()35 void AtomicServicePattern::MenuBarSafeAreaCallBack()
36 {
37 auto pipeline = PipelineContext::GetCurrentContext();
38 CHECK_NULL_VOID(pipeline);
39 auto theme = pipeline->GetTheme<AppBarTheme>();
40 CHECK_NULL_VOID(theme);
41 auto host = GetHost();
42 CHECK_NULL_VOID(host);
43 auto manager = pipeline->GetSafeAreaManager();
44 CHECK_NULL_VOID(manager);
45 manager->SetIsAtomicService(true);
46 manager->AddGeoRestoreNode(host);
47 auto systemSafeArea = manager->GetSystemSafeArea();
48 auto menuSafeTopValue = systemSafeArea.top_.Length();
49 auto menuSafeTopVp = Dimension(menuSafeTopValue, DimensionUnit::PX).ConvertToVp();
50 auto customAppBar = GetJSAppBarContainer();
51 CHECK_NULL_VOID(customAppBar);
52 customAppBar->FireCustomCallback(ARKUI_APP_BAR_MENU_SAFE_AREA, std::to_string(menuSafeTopVp));
53 }
54
ContentSafeAreaCallBack()55 void AtomicServicePattern::ContentSafeAreaCallBack()
56 {
57 auto pipeline = PipelineContext::GetCurrentContext();
58 CHECK_NULL_VOID(pipeline);
59 auto safeArea = pipeline->GetSafeArea();
60 auto manager = pipeline->GetSafeAreaManager();
61 CHECK_NULL_VOID(manager);
62 if (manager->KeyboardSafeAreaEnabled()) {
63 safeArea.bottom_ = safeArea.bottom_.Combine(manager->GetKeyboardInset());
64 }
65 auto left = Dimension(safeArea.left_.Length(), DimensionUnit::PX).ConvertToVp();
66 auto right = Dimension(safeArea.right_.Length(), DimensionUnit::PX).ConvertToVp();
67 auto top = Dimension(safeArea.top_.Length(), DimensionUnit::PX).ConvertToVp();
68 auto bottom = Dimension(safeArea.bottom_.Length(), DimensionUnit::PX).ConvertToVp();
69 auto customAppBar = GetJSAppBarContainer();
70 CHECK_NULL_VOID(customAppBar);
71 std::vector<float> values = { top, left, right, bottom };
72 std::string result;
73 for (size_t i = 0; i < values.size(); ++i) {
74 result += std::to_string(values[i]);
75 if (i < values.size() - 1) {
76 result += "|";
77 }
78 }
79 customAppBar->FireCustomCallback(ARKUI_APP_BAR_CONTENT_SAFE_AREA, result);
80 }
81
ColorConfigurationCallBack()82 void AtomicServicePattern::ColorConfigurationCallBack()
83 {
84 auto customAppBar = GetJSAppBarContainer();
85 CHECK_NULL_VOID(customAppBar);
86 auto context = GetContext();
87 CHECK_NULL_VOID(context);
88 customAppBar->FireCustomCallback(ARKUI_APP_BAR_COLOR_CONFIGURATION,
89 settedColorMode.has_value() ? !settedColorMode.value() : context->GetColorMode() == ColorMode::DARK);
90 }
91
AppInfoCallBack()92 void AtomicServicePattern::AppInfoCallBack()
93 {
94 auto atom = GetHost();
95 CHECK_NULL_VOID(atom);
96 auto pipeline = atom->GetContextRefPtr();
97 CHECK_NULL_VOID(pipeline);
98 auto themeManager = pipeline->GetThemeManager();
99 CHECK_NULL_VOID(themeManager);
100 auto themeConstants = themeManager->GetThemeConstants();
101 CHECK_NULL_VOID(themeConstants);
102 auto windowManager = pipeline->GetWindowManager();
103 CHECK_NULL_VOID(windowManager);
104 auto customAppBar = GetJSAppBarContainer();
105 CHECK_NULL_VOID(customAppBar);
106 auto id = windowManager->GetAppIconId();
107 auto pixelMap = themeConstants->GetPixelMap(id);
108 if (pixelMap) {
109 const RefPtr<PixelMap> icon = PixelMap::CreatePixelMap(&pixelMap);
110 customAppBar->FireAppIconCallback(icon);
111 } else {
112 TAG_LOGW(AceLogTag::ACE_APPBAR, "App bar Cannot get pixelmap, try media path.");
113 }
114 auto result = AceApplicationInfo::GetInstance().GetProcessName() + "|" +
115 themeConstants->GetString(windowManager->GetAppLabelId());
116 customAppBar->FireCustomCallback(ARKUI_APP_BAR_BAR_INFO, result);
117 }
118
AppScreenCallBack()119 void AtomicServicePattern::AppScreenCallBack()
120 {
121 auto customAppBar = GetJSAppBarContainer();
122 CHECK_NULL_VOID(customAppBar);
123 auto container = Container::Current();
124 CHECK_NULL_VOID(container);
125 customAppBar->FireCustomCallback(ARKUI_APP_BAR_SCREEN, container->UIExtensionIsHalfScreen());
126 }
127
AppBgColorCallBack()128 void AtomicServicePattern::AppBgColorCallBack()
129 {
130 auto host = GetHost();
131 CHECK_NULL_VOID(host);
132 auto pipeline = host->GetContextRefPtr();
133 CHECK_NULL_VOID(pipeline);
134 auto customAppBar = GetJSAppBarContainer();
135 CHECK_NULL_VOID(customAppBar);
136 customAppBar->FireCustomCallback(ARKUI_APP_BG_COLOR, pipeline->GetAppBgColor().ColorToString());
137 }
138
UpdateLayoutMargin()139 void AtomicServicePattern::UpdateLayoutMargin()
140 {
141 auto pipeline = PipelineContext::GetCurrentContext();
142 CHECK_NULL_VOID(pipeline);
143 auto safeArea = pipeline->GetSafeArea();
144 auto atom = GetHost();
145 CHECK_NULL_VOID(atom);
146 MarginProperty margin;
147 margin.left = CalcLength(safeArea.left_.Length());
148 margin.right = CalcLength(safeArea.right_.Length());
149 margin.top = CalcLength(safeArea.top_.Length());
150 margin.bottom = CalcLength(safeArea.bottom_.Length());
151 // update stage margin
152 auto stage = GetContent();
153 CHECK_NULL_VOID(stage);
154 auto layoutProperty = stage->GetLayoutProperty();
155 CHECK_NULL_VOID(layoutProperty);
156 layoutProperty->UpdateMargin(margin);
157 stage->MarkModifyDone();
158 stage->MarkDirtyNode();
159 }
160
UpdateOverlayLayout()161 void AtomicServicePattern::UpdateOverlayLayout()
162 {
163 auto atom = GetHost();
164 CHECK_NULL_VOID(atom);
165 if (atom->GetChildren().size() <= ATOMIC_SERVICE_MIN_SIZE) {
166 return;
167 }
168 for (int index = FIRST_OVERLAY_INDEX;
169 index <= static_cast<int32_t>(atom->GetChildren().size()) - ATOMIC_SERVICE_MIN_SIZE; index++) {
170 auto overlay = AceType::DynamicCast<FrameNode>(atom->GetChildAtIndex(index));
171 CHECK_NULL_VOID(overlay);
172 auto overlayRender = overlay->GetRenderContext();
173 overlayRender->UpdatePosition(OffsetT<Dimension>());
174 overlay->MarkModifyDone();
175 overlay->MarkDirtyNode();
176 }
177 }
178
OnAttachToFrameNode()179 void AtomicServicePattern::OnAttachToFrameNode()
180 {
181 auto host = GetHost();
182 CHECK_NULL_VOID(host);
183 host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
184 AppBgColorCallBack();
185 }
186
OnColorConfigurationUpdate()187 void AtomicServicePattern::OnColorConfigurationUpdate()
188 {
189 AppBgColorCallBack();
190 ColorConfigurationCallBack();
191 }
GetJSAppBarContainer()192 RefPtr<CustomAppBarNode> AtomicServicePattern::GetJSAppBarContainer()
193 {
194 auto customAppBarNode = NG::ViewStackProcessor::GetInstance()->GetCustomAppBarNode();
195 return AceType::DynamicCast<CustomAppBarNode>(customAppBarNode);
196 }
197
GetStageNodeWrapper()198 RefPtr<FrameNode> AtomicServicePattern::GetStageNodeWrapper()
199 {
200 return NG::Inspector::GetFrameNodeByKey("AtomicServiceStageId");
201 }
202
GetContent()203 RefPtr<FrameNode> AtomicServicePattern::GetContent()
204 {
205 auto stageNodeWrapper = GetStageNodeWrapper();
206 CHECK_NULL_RETURN(stageNodeWrapper, nullptr);
207 return AceType::DynamicCast<FrameNode>(stageNodeWrapper->GetChildAtIndex(0));
208 }
209
GetMenuBarRow()210 RefPtr<FrameNode> AtomicServicePattern::GetMenuBarRow()
211 {
212 return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenubarRowId");
213 }
214
GetMenuBar()215 RefPtr<FrameNode> AtomicServicePattern::GetMenuBar()
216 {
217 return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenubarId");
218 }
219
GetMenuButton()220 RefPtr<FrameNode> AtomicServicePattern::GetMenuButton()
221 {
222 return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenuId");
223 }
224
GetDivider()225 RefPtr<FrameNode> AtomicServicePattern::GetDivider()
226 {
227 return NG::Inspector::GetFrameNodeByKey("AtomicServiceDividerId");
228 }
229
GetCloseButton()230 RefPtr<FrameNode> AtomicServicePattern::GetCloseButton()
231 {
232 return NG::Inspector::GetFrameNodeByKey("AtomicServiceCloseId");
233 }
234
GetMenuIcon()235 RefPtr<FrameNode> AtomicServicePattern::GetMenuIcon()
236 {
237 return NG::Inspector::GetFrameNodeByKey("AtomicServiceMenuIconId");
238 }
239
GetCloseIcon()240 RefPtr<FrameNode> AtomicServicePattern::GetCloseIcon()
241 {
242 return NG::Inspector::GetFrameNodeByKey("AtomicServiceCloseIconId");
243 }
244
UpdateColor(std::optional<bool> isLight)245 void AtomicServicePattern::UpdateColor(std::optional<bool> isLight)
246 {
247 auto pipeline = PipelineContext::GetCurrentContext();
248 CHECK_NULL_VOID(pipeline);
249 auto theme = pipeline->GetTheme<AppBarTheme>();
250 if (!(isLight.has_value())) {
251 isLight = pipeline->GetColorMode() != ColorMode::DARK;
252 }
253 auto menuButton = GetMenuButton();
254 UpdateButtonColor(theme, menuButton, isLight.value());
255 auto divider = GetDivider();
256 UpdateDividerColor(theme, divider, isLight.value());
257 auto closeButton = GetCloseButton();
258 UpdateButtonColor(theme, closeButton, isLight.value());
259
260 auto menuIcon = GetMenuIcon();
261 UpdateIconColor(theme, menuIcon, isLight.value());
262 auto closeIcon = GetCloseIcon();
263 UpdateIconColor(theme, closeIcon, isLight.value());
264 }
265
UpdateMenuBarColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isLight)266 void AtomicServicePattern::UpdateMenuBarColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isLight)
267 {
268 CHECK_NULL_VOID(theme);
269 CHECK_NULL_VOID(menuBar);
270 auto renderContext = menuBar->GetRenderContext();
271 // background effect、border color
272 EffectOption option;
273 BorderColorProperty borderColor;
274 option.radius = theme->GetBlurRadius();
275 if (isLight) {
276 option.color = theme->GetBlurColorLight();
277 borderColor.SetColor(theme->GetBorderColorLight());
278 } else {
279 option.color = theme->GetBlurColorDark();
280 borderColor.SetColor(theme->GetBorderColorDark());
281 }
282 renderContext->UpdateBackgroundEffect(option);
283 renderContext->UpdateBorderColor(borderColor);
284
285 menuBar->MarkModifyDone();
286 menuBar->MarkDirtyNode(PROPERTY_UPDATE_LAYOUT);
287 }
288
UpdateButtonColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLight)289 void AtomicServicePattern::UpdateButtonColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLight)
290 {
291 CHECK_NULL_VOID(theme);
292 CHECK_NULL_VOID(button);
293 // pressed color
294 auto buttonPattern = button->GetPattern<ButtonPattern>();
295 CHECK_NULL_VOID(buttonPattern);
296 if (isLight) {
297 buttonPattern->SetClickedColor(theme->GetClickEffectColorLight());
298 } else {
299 buttonPattern->SetClickedColor(theme->GetClickEffectColorDark());
300 }
301 // focus border color
302 if (isLight) {
303 buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorLight());
304 } else {
305 buttonPattern->SetFocusBorderColor(theme->GetFocusedOutlineColorDark());
306 }
307
308 button->MarkModifyDone();
309 button->MarkDirtyNode();
310 }
311
UpdateDividerColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & divider,bool isLight)312 void AtomicServicePattern::UpdateDividerColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& divider, bool isLight)
313 {
314 CHECK_NULL_VOID(theme);
315 CHECK_NULL_VOID(divider);
316
317 auto renderProperty = divider->GetPaintProperty<DividerRenderProperty>();
318 if (isLight) {
319 renderProperty->UpdateDividerColor(theme->GetDividerColorLight());
320 } else {
321 renderProperty->UpdateDividerColor(theme->GetDividerColorDark());
322 }
323
324 divider->MarkModifyDone();
325 divider->MarkDirtyNode();
326 }
327
UpdateIconColor(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLight)328 void AtomicServicePattern::UpdateIconColor(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLight)
329 {
330 CHECK_NULL_VOID(theme);
331 CHECK_NULL_VOID(icon);
332 // fill color
333 auto color = isLight ? theme->GetIconColorLight() : theme->GetIconColorDark();
334 ACE_UPDATE_NODE_PAINT_PROPERTY(ImageRenderProperty, SvgFillColor, color, icon);
335 ACE_UPDATE_NODE_RENDER_CONTEXT(ForegroundColor, color, icon);
336 icon->MarkModifyDone();
337 icon->MarkDirtyNode();
338 }
339
UpdateLayout()340 void AtomicServicePattern::UpdateLayout()
341 {
342 auto pipeline = PipelineContext::GetCurrentContext();
343 CHECK_NULL_VOID(pipeline);
344 auto theme = pipeline->GetTheme<AppBarTheme>();
345 CHECK_NULL_VOID(theme);
346 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
347
348 auto menuBar = GetMenuBar();
349 UpdateMenuBarLayout(theme, menuBar, isRtl);
350
351 auto menuButton = GetMenuButton();
352 UpdateButtonLayout(theme, menuButton, !isRtl);
353 auto closeButton = GetCloseButton();
354 UpdateButtonLayout(theme, closeButton, isRtl);
355
356 auto menuIcon = GetMenuIcon();
357 UpdateIconLayout(theme, menuIcon, !isRtl);
358 auto closeIcon = GetCloseIcon();
359 UpdateIconLayout(theme, closeIcon, isRtl);
360 }
361
UpdateMenuBarLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & menuBar,bool isRtl)362 void AtomicServicePattern::UpdateMenuBarLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& menuBar, bool isRtl)
363 {
364 CHECK_NULL_VOID(theme);
365 CHECK_NULL_VOID(menuBar);
366
367 MarginProperty margin;
368 auto pipeline = PipelineContext::GetCurrentContext();
369 CHECK_NULL_VOID(pipeline);
370 auto safeArea = pipeline->GetSafeArea();
371
372 Dimension safeAreaLeft(pipeline->Px2VpWithCurrentDensity(safeArea.left_.Length()), DimensionUnit::VP);
373 Dimension safeAreaRight(pipeline->Px2VpWithCurrentDensity(safeArea.right_.Length()), DimensionUnit::VP);
374
375 if (isRtl) {
376 margin.left = CalcLength(theme->GetMenuBarRightMargin() + safeAreaLeft);
377 margin.right = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaRight);
378 } else {
379 margin.left = CalcLength(theme->GetMenuBarLeftMargin() + safeAreaLeft);
380 margin.right = CalcLength(theme->GetMenuBarRightMargin() + safeAreaRight);
381 }
382 menuBar->GetLayoutProperty<LinearLayoutProperty>()->UpdateMargin(margin);
383
384 menuBar->MarkModifyDone();
385 menuBar->MarkDirtyNode();
386 }
387
UpdateButtonLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & button,bool isLeft)388 void AtomicServicePattern::UpdateButtonLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& button, bool isLeft)
389 {
390 CHECK_NULL_VOID(theme);
391 CHECK_NULL_VOID(button);
392
393 auto bent = theme->GetBentRadius();
394 auto rightAngle = theme->GetRightAngle();
395 auto leftBorderRadius = BorderRadiusProperty(bent, rightAngle, rightAngle, bent);
396 auto rightBorderRadius = BorderRadiusProperty(rightAngle, bent, bent, rightAngle);
397
398 auto layoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
399 layoutProperty->UpdateBorderRadius(isLeft ? leftBorderRadius : rightBorderRadius);
400
401 button->MarkModifyDone();
402 button->MarkDirtyNode();
403 }
404
UpdateIconLayout(RefPtr<AppBarTheme> & theme,RefPtr<FrameNode> & icon,bool isLeft)405 void AtomicServicePattern::UpdateIconLayout(RefPtr<AppBarTheme>& theme, RefPtr<FrameNode>& icon, bool isLeft)
406 {
407 CHECK_NULL_VOID(theme);
408 CHECK_NULL_VOID(icon);
409
410 MarginProperty margin;
411 margin.top = CalcLength(theme->GetIconVerticalMargin());
412 margin.bottom = CalcLength(theme->GetIconVerticalMargin());
413 if (isLeft) {
414 margin.left = CalcLength(theme->GetIconOutsideMargin());
415 margin.right = CalcLength(theme->GetIconInsideMargin());
416 } else {
417 margin.left = CalcLength(theme->GetIconInsideMargin());
418 margin.right = CalcLength(theme->GetIconOutsideMargin());
419 }
420 auto layoutProperty = icon->GetLayoutProperty<ImageLayoutProperty>();
421 CHECK_NULL_VOID(layoutProperty);
422 layoutProperty->UpdateMargin(margin);
423
424 icon->MarkModifyDone();
425 icon->MarkDirtyNode();
426 }
427 } // namespace OHOS::Ace::NG
428