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/badge/render_badge.h"
17
18 #include "base/log/event_report.h"
19 #include "core/common/container.h"
20 #include "core/common/font_manager.h"
21
22 namespace OHOS::Ace {
23
RenderBadge()24 RenderBadge::RenderBadge()
25 {
26 clickRecognizer_ = AceType::MakeRefPtr<ClickRecognizer>();
27 clickRecognizer_->SetOnClick([wp = AceType::WeakClaim(this)](const ClickInfo&) {
28 auto badge = wp.Upgrade();
29 if (badge) {
30 badge->HandleClickEvent();
31 }
32 });
33 }
34
~RenderBadge()35 RenderBadge::~RenderBadge()
36 {
37 auto context = context_.Upgrade();
38 if (context) {
39 context->RemoveFontNode(WeakClaim(this));
40 auto fontManager = context->GetFontManager();
41 if (fontManager) {
42 fontManager->RemoveVariationNode(WeakClaim(this));
43 }
44 }
45 }
46
HandleClickEvent()47 void RenderBadge::HandleClickEvent()
48 {
49 if (onClick_) {
50 onClick_();
51 }
52 }
53
OnTouchTestHit(const Offset & coordinateOffset,const TouchRestrict & touchRestrict,TouchTestResult & result)54 void RenderBadge::OnTouchTestHit(
55 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result)
56 {
57 if (!clickRecognizer_) {
58 return;
59 }
60 clickRecognizer_->SetCoordinateOffset(coordinateOffset);
61 result.emplace_back(clickRecognizer_);
62 }
63
Update(const RefPtr<Component> & component)64 void RenderBadge::Update(const RefPtr<Component>& component)
65 {
66 badge_ = AceType::DynamicCast<BadgeComponent>(component);
67 if (!badge_) {
68 LOGE("Update error, badge component is null");
69 EventReport::SendRenderException(RenderExcepType::RENDER_COMPONENT_ERR);
70 return;
71 }
72 showMessage_ = badge_->IsShowMessage();
73 auto padding = badge_->GetPadding();
74 auto badgeLabel = badge_->GetBadgeLabel();
75 auto messageCount = badge_->GetMessageCount();
76 auto maxCount = badge_->GetMaxCount();
77 auto countLimit = maxCount > INT_MAX ? INT_MAX : maxCount;
78 badgeChildInitialOffset_ = Offset(NormalizeToPx(padding.Left()), NormalizeToPx(padding.Top()));
79 onClick_ = AceAsyncEvent<void()>::Create(badge_->GetClickEvent(), context_);
80 auto catchMode = true;
81 if (badge_->GetClickEvent().IsEmpty()) {
82 catchMode = false;
83 } else {
84 catchMode = badge_->GetClickEvent().GetCatchMode();
85 }
86 static const int32_t bubbleModeVersion = 6;
87 auto pipeline = context_.Upgrade();
88 if (!catchMode) {
89 if (pipeline && pipeline->GetMinPlatformVersion() >= bubbleModeVersion) {
90 catchMode = false;
91 } else {
92 catchMode = true;
93 }
94 }
95 clickRecognizer_->SetUseCatchMode(catchMode);
96 textData_.clear();
97 // double check for badge
98 if (showMessage_) {
99 showMessage_ = ParseBadgeStatus(badgeLabel, messageCount, countLimit);
100 }
101 badgeTextComponent_ = AceType::MakeRefPtr<TextComponent>(textData_);
102 if (!badgeRenderText_) {
103 InitialBadgeText();
104 }
105 UpdateBadgeText();
106 }
107
PerformLayout()108 void RenderBadge::PerformLayout()
109 {
110 if (!badge_) {
111 return;
112 }
113
114 if (!GetChildren().front()) {
115 SetLayoutSize(Size());
116 // For partial update code path we can get children added
117 // without executing of RenderBadge::Update
118 // In that case showMessage_ remains false and
119 // Badge never shown.
120 if (!Container::IsCurrentUsePartialUpdate()) {
121 showMessage_ = false;
122 }
123 return;
124 }
125
126 auto context = context_.Upgrade();
127 if (context) {
128 dipScale_ = context->GetDipScale();
129 }
130
131 // child layout
132 LayoutParam layoutParam = GetLayoutParam();
133 Size minSize = layoutParam.GetMinSize();
134 Size maxSize = layoutParam.GetMaxSize();
135 LayoutParam innerLayoutParam = layoutParam;
136 Size paddingSize = badge_->GetPadding().GetLayoutSizeInPx(dipScale_);
137 innerLayoutParam.SetMinSize(minSize - paddingSize);
138 innerLayoutParam.SetMaxSize(maxSize - paddingSize);
139 double maxWidth = minSize.Width();
140 double maxHeight = minSize.Height();
141 if (!GetChildren().empty()) {
142 auto child = GetChildren().front();
143 child->Layout(innerLayoutParam);
144 child->SetPosition(badgeChildInitialOffset_);
145 maxWidth = std::max(maxWidth, child->GetLayoutSize().Width() + paddingSize.Width());
146 maxHeight = std::max(maxHeight, child->GetLayoutSize().Height() + paddingSize.Height());
147 }
148
149 // calculate self layout size
150 if (maxSize.IsInfinite()) {
151 // same with child size
152 badgeSize_ = Size(maxWidth, maxHeight);
153 } else {
154 badgeSize_ = maxSize;
155 }
156 if (!badgeSize_.IsValid()) {
157 badgeSize_ = Size();
158 showMessage_ = false;
159 }
160 SetLayoutSize(badgeSize_);
161 width_ = badgeSize_.Width();
162 height_ = badgeSize_.Height();
163 }
164
InitialBadgeText()165 void RenderBadge::InitialBadgeText()
166 {
167 badgeRenderText_ = AceType::DynamicCast<RenderText>(badgeTextComponent_->CreateRenderNode());
168 LayoutParam innerLayout;
169 innerLayout.SetMaxSize(Size(Size::INFINITE_SIZE, Size::INFINITE_SIZE));
170 badgeRenderText_->Attach(GetContext());
171 badgeRenderText_->Update(badgeTextComponent_);
172 badgeRenderText_->SetLayoutParam(innerLayout);
173 }
174
ParseBadgeStatus(const std::optional<std::string> & label,int64_t messageCount,int64_t countLimit)175 bool RenderBadge::ParseBadgeStatus(const std::optional<std::string>& label, int64_t messageCount, int64_t countLimit)
176 {
177 if (label.has_value()) {
178 textData_ = label.value();
179 return true;
180 }
181 if (messageCount < 0) {
182 return true;
183 }
184 if (messageCount > 0) {
185 if (messageCount > countLimit) {
186 textData_ = std::to_string(countLimit) + '+';
187 } else {
188 textData_ = std::to_string(messageCount);
189 }
190 return true;
191 }
192 return false;
193 }
194
UpdateBadgeText()195 void RenderBadge::UpdateBadgeText()
196 {
197 auto context = context_.Upgrade();
198 if (context) {
199 auto fontManager = context->GetFontManager();
200 if (fontManager) {
201 fontManager->AddVariationNode(WeakClaim(this));
202 }
203 }
204 if (badge_) {
205 textStyle_.SetTextColor(badge_->GetBadgeTextColor());
206 textStyle_.SetFontSize(badge_->GetBadgeFontSize());
207 textStyle_.SetAllowScale(false);
208 badgeTextComponent_->SetData(textData_);
209 badgeTextComponent_->SetTextStyle(textStyle_);
210 badgeRenderText_->Update(badgeTextComponent_);
211 }
212 }
213
214 } // namespace OHOS::Ace
215