1 /*
2 * Copyright (c) 2023-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/refresh/refresh_model_ng.h"
17
18 #include <string>
19
20 #include "base/utils/multi_thread.h"
21 #include "core/components_ng/pattern/refresh/refresh_pattern.h"
22 #include "core/components_ng/pattern/render_node/render_node_pattern.h"
23 #include "frameworks/base/geometry/dimension.h"
24 #include "frameworks/base/geometry/ng/offset_t.h"
25 #include "frameworks/base/i18n/localization.h"
26 #include "frameworks/base/utils/time_util.h"
27 #include "frameworks/core/components_ng/base/frame_node.h"
28 #include "frameworks/core/components_ng/base/view_stack_processor.h"
29 #include "frameworks/core/components_ng/event/event_hub.h"
30 #include "core/common/resource/resource_parse_utils.h"
31
32 namespace OHOS::Ace::NG {
33
34 namespace {
35 constexpr double DEFAULT_INDICATOR_OFFSET = 16.0;
36 constexpr int32_t DEFAULT_FRICTION_RATIO = 62;
37 constexpr double DEFAULT_REFRESH_OFFSET = 64.0f;
38 } // namespace
39
Create()40 void RefreshModelNG::Create()
41 {
42 auto* stack = ViewStackProcessor::GetInstance();
43 auto nodeId = stack->ClaimNodeId();
44 ACE_LAYOUT_SCOPED_TRACE("Create[%s][self:%d]", V2::REFRESH_ETS_TAG, nodeId);
45 auto frameNode = FrameNode::GetOrCreateFrameNode(
46 V2::REFRESH_ETS_TAG, nodeId, []() { return AceType::MakeRefPtr<RefreshPattern>(); });
47 CHECK_NULL_VOID(frameNode);
48 stack->Push(frameNode);
49 if (frameNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
50 auto pattern = frameNode->GetPattern<RefreshPattern>();
51 CHECK_NULL_VOID(pattern);
52 pattern->UpdateNestedModeForChildren(NestedScrollOptions({
53 .forward = NestedScrollMode::PARENT_FIRST,
54 .backward = NestedScrollMode::SELF_FIRST,
55 }));
56 }
57 ACE_UPDATE_LAYOUT_PROPERTY(
58 RefreshLayoutProperty, IndicatorOffset, Dimension(DEFAULT_INDICATOR_OFFSET, DimensionUnit::VP));
59 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, Friction, DEFAULT_FRICTION_RATIO);
60 }
61
CreateFrameNode(int32_t nodeId)62 RefPtr<FrameNode> RefreshModelNG::CreateFrameNode(int32_t nodeId)
63 {
64 auto frameNode = FrameNode::CreateFrameNode(V2::REFRESH_ETS_TAG, nodeId, AceType::MakeRefPtr<RefreshPattern>());
65 CHECK_NULL_RETURN(frameNode, frameNode);
66 if (frameNode->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
67 auto pattern = frameNode->GetPattern<RefreshPattern>();
68 CHECK_NULL_RETURN(pattern, frameNode);
69 pattern->UpdateNestedModeForChildren(NestedScrollOptions({
70 .forward = NestedScrollMode::PARENT_FIRST,
71 .backward = NestedScrollMode::SELF_FIRST,
72 }));
73 }
74 auto layoutProperty = frameNode->GetLayoutProperty<RefreshLayoutProperty>();
75 layoutProperty->UpdateIndicatorOffset(Dimension(DEFAULT_INDICATOR_OFFSET, DimensionUnit::VP));
76 layoutProperty->UpdateFriction(DEFAULT_FRICTION_RATIO);
77 return frameNode;
78 }
79
SetPullToRefresh(bool pullToRefresh)80 void RefreshModelNG::SetPullToRefresh(bool pullToRefresh)
81 {
82 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, PullToRefresh, pullToRefresh);
83 }
84
SetRefreshOffset(const Dimension & offset)85 void RefreshModelNG::SetRefreshOffset(const Dimension& offset)
86 {
87 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, RefreshOffset, offset);
88 }
89
SetRefreshing(bool isRefreshing)90 void RefreshModelNG::SetRefreshing(bool isRefreshing)
91 {
92 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, IsRefreshing, isRefreshing);
93 }
94
SetIndicatorOffset(const Dimension & indicatorOffset)95 void RefreshModelNG::SetIndicatorOffset(const Dimension& indicatorOffset)
96 {
97 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, IndicatorOffset, indicatorOffset);
98 }
99
SetFriction(int32_t friction)100 void RefreshModelNG::SetFriction(int32_t friction)
101 {
102 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, Friction, friction);
103 }
104
SetLoadingText(const std::string & loadingText)105 void RefreshModelNG::SetLoadingText(const std::string& loadingText)
106 {
107 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, LoadingText, loadingText);
108 }
109
CreateWithResourceObj(const RefPtr<ResourceObject> & resObj)110 void RefreshModelNG::CreateWithResourceObj(const RefPtr<ResourceObject>& resObj)
111 {
112 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
113 CHECK_NULL_VOID(frameNode);
114 auto pattern = frameNode->GetPattern<RefreshPattern>();
115 CHECK_NULL_VOID(pattern);
116 pattern->RemoveResObj("refresh.promptText");
117 CHECK_NULL_VOID(resObj);
118 auto&& updateFunc = [weak = AceType::WeakClaim(frameNode)](const RefPtr<ResourceObject>& resObj) {
119 auto node = weak.Upgrade();
120 CHECK_NULL_VOID(node);
121 std::string result;
122 if (!ResourceParseUtils::ParseResString(resObj, result)) {
123 ACE_RESET_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, LoadingText, AceType::RawPtr(node));
124 } else {
125 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, LoadingText, result, AceType::RawPtr(node));
126 }
127 };
128 pattern->AddResObj("refresh.promptText", resObj, std::move(updateFunc));
129 }
130
ResetLoadingText()131 void RefreshModelNG::ResetLoadingText()
132 {
133 ACE_RESET_LAYOUT_PROPERTY(RefreshLayoutProperty, LoadingText);
134 }
135
SetOnStateChange(StateChangeEvent && stateChange)136 void RefreshModelNG::SetOnStateChange(StateChangeEvent&& stateChange)
137 {
138 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
139 CHECK_NULL_VOID(frameNode);
140 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
141 CHECK_NULL_VOID(eventHub);
142 eventHub->SetOnStateChange(std::move(stateChange));
143 }
144
SetOnRefreshing(RefreshingEvent && refreshing)145 void RefreshModelNG::SetOnRefreshing(RefreshingEvent&& refreshing)
146 {
147 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
148 CHECK_NULL_VOID(frameNode);
149 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
150 CHECK_NULL_VOID(eventHub);
151 eventHub->SetOnRefreshing(std::move(refreshing));
152 }
153
SetChangeEvent(RefreshChangeEvent && changeEvent)154 void RefreshModelNG::SetChangeEvent(RefreshChangeEvent&& changeEvent)
155 {
156 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
157 CHECK_NULL_VOID(frameNode);
158 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
159 CHECK_NULL_VOID(eventHub);
160 eventHub->SetChangeEvent(std::move(changeEvent));
161 }
162
SetOnOffsetChange(OffsetChangeEvent && dragOffset)163 void RefreshModelNG::SetOnOffsetChange(OffsetChangeEvent&& dragOffset)
164 {
165 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
166 CHECK_NULL_VOID(frameNode);
167 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
168 CHECK_NULL_VOID(eventHub);
169 eventHub->SetOnOffsetChange(std::move(dragOffset));
170 }
171
ResetOnOffsetChange()172 void RefreshModelNG::ResetOnOffsetChange()
173 {
174 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
175 CHECK_NULL_VOID(frameNode);
176 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
177 CHECK_NULL_VOID(eventHub);
178 eventHub->ResetOnOffsetChange();
179 }
180
SetMaxPullDownDistance(const std::optional<float> & maxDistance)181 void RefreshModelNG::SetMaxPullDownDistance(const std::optional<float>& maxDistance)
182 {
183 if (maxDistance.has_value()) {
184 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, MaxPullDownDistance, maxDistance.value());
185 } else {
186 ACE_RESET_LAYOUT_PROPERTY(RefreshLayoutProperty, MaxPullDownDistance);
187 }
188 }
189
SetMaxPullDownDistance(FrameNode * frameNode,const std::optional<float> & maxDistance)190 void RefreshModelNG::SetMaxPullDownDistance(FrameNode* frameNode, const std::optional<float>& maxDistance)
191 {
192 if (maxDistance.has_value()) {
193 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, MaxPullDownDistance, maxDistance.value(), frameNode);
194 } else {
195 ACE_RESET_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, MaxPullDownDistance, frameNode);
196 }
197 }
198
SetPullDownRatio(const std::optional<float> & pullDownRatio)199 void RefreshModelNG::SetPullDownRatio(const std::optional<float>& pullDownRatio)
200 {
201 if (pullDownRatio.has_value()) {
202 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, PullDownRatio, pullDownRatio.value());
203 } else {
204 ACE_RESET_LAYOUT_PROPERTY(RefreshLayoutProperty, PullDownRatio);
205 }
206 }
207
SetPullDownRatio(FrameNode * frameNode,const std::optional<float> & pullDownRatio)208 void RefreshModelNG::SetPullDownRatio(FrameNode* frameNode, const std::optional<float>& pullDownRatio)
209 {
210 if (pullDownRatio.has_value()) {
211 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, PullDownRatio, pullDownRatio.value(), frameNode);
212 } else {
213 ACE_RESET_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, PullDownRatio, frameNode);
214 }
215 }
216
SetCustomBuilder(const RefPtr<NG::UINode> & customBuilder)217 void RefreshModelNG::SetCustomBuilder(const RefPtr<NG::UINode>& customBuilder)
218 {
219 auto frameNode = ViewStackProcessor::GetInstance()->GetMainFrameNode();
220 CHECK_NULL_VOID(frameNode);
221 auto pattern = frameNode->GetPattern<RefreshPattern>();
222 CHECK_NULL_VOID(pattern);
223 pattern->AddCustomBuilderNode(customBuilder);
224 }
225
SetIsCustomBuilderExist(bool isCustomBuilderExist)226 void RefreshModelNG::SetIsCustomBuilderExist(bool isCustomBuilderExist)
227 {
228 ACE_UPDATE_LAYOUT_PROPERTY(RefreshLayoutProperty, IsCustomBuilderExist, isCustomBuilderExist);
229 }
230
SetCustomBuilder(FrameNode * frameNode,FrameNode * customBuilder)231 void RefreshModelNG::SetCustomBuilder(FrameNode* frameNode, FrameNode* customBuilder)
232 {
233 // call SetCustomBuilderMultiThread by multi thread
234 FREE_NODE_CHECK(frameNode, SetCustomBuilder, frameNode, customBuilder);
235 CHECK_NULL_VOID(frameNode);
236 auto pattern = frameNode->GetPattern<RefreshPattern>();
237 CHECK_NULL_VOID(pattern);
238 pattern->AddCustomBuilderNode(AceType::Claim<UINode>(customBuilder));
239 }
240
SetOnStateChange(FrameNode * frameNode,StateChangeEvent && stateChange)241 void RefreshModelNG::SetOnStateChange(FrameNode* frameNode, StateChangeEvent&& stateChange)
242 {
243 CHECK_NULL_VOID(frameNode);
244 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
245 CHECK_NULL_VOID(eventHub);
246 eventHub->SetOnStateChange(std::move(stateChange));
247 }
248
SetOnRefreshing(FrameNode * frameNode,RefreshingEvent && refreshing)249 void RefreshModelNG::SetOnRefreshing(FrameNode* frameNode, RefreshingEvent&& refreshing)
250 {
251 CHECK_NULL_VOID(frameNode);
252 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
253 CHECK_NULL_VOID(eventHub);
254 eventHub->SetOnRefreshing(std::move(refreshing));
255 }
256
SetOnOffsetChange(FrameNode * frameNode,OffsetChangeEvent && dragOffset)257 void RefreshModelNG::SetOnOffsetChange(FrameNode* frameNode, OffsetChangeEvent&& dragOffset)
258 {
259 CHECK_NULL_VOID(frameNode);
260 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
261 CHECK_NULL_VOID(eventHub);
262 eventHub->SetOnOffsetChange(std::move(dragOffset));
263 }
264
ResetOnOffsetChange(FrameNode * frameNode)265 void RefreshModelNG::ResetOnOffsetChange(FrameNode* frameNode)
266 {
267 CHECK_NULL_VOID(frameNode);
268 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
269 CHECK_NULL_VOID(eventHub);
270 eventHub->ResetOnOffsetChange();
271 }
272
SetRefreshing(FrameNode * frameNode,bool isRefreshing)273 void RefreshModelNG::SetRefreshing(FrameNode* frameNode, bool isRefreshing)
274 {
275 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, IsRefreshing, isRefreshing, frameNode);
276 }
277
GetRefreshing(FrameNode * frameNode)278 bool RefreshModelNG::GetRefreshing(FrameNode* frameNode)
279 {
280 bool value = false;
281 ACE_GET_NODE_LAYOUT_PROPERTY_WITH_DEFAULT_VALUE(RefreshLayoutProperty, IsRefreshing, value, frameNode, value);
282 return value;
283 }
284
SetRefreshOffset(FrameNode * frameNode,const Dimension & offset)285 void RefreshModelNG::SetRefreshOffset(FrameNode* frameNode, const Dimension& offset)
286 {
287 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, RefreshOffset, offset, frameNode);
288 }
289
SetPullToRefresh(FrameNode * frameNode,bool pullToRefresh)290 void RefreshModelNG::SetPullToRefresh(FrameNode* frameNode, bool pullToRefresh)
291 {
292 ACE_UPDATE_NODE_LAYOUT_PROPERTY(RefreshLayoutProperty, PullToRefresh, pullToRefresh, frameNode);
293 }
294
GetMaxPullDownDistance(FrameNode * frameNode)295 float RefreshModelNG::GetMaxPullDownDistance(FrameNode* frameNode)
296 {
297 float value = std::numeric_limits<float>::infinity();
298 ACE_GET_NODE_LAYOUT_PROPERTY_WITH_DEFAULT_VALUE(RefreshLayoutProperty, MaxPullDownDistance,
299 value, frameNode, value);
300 return value;
301 }
302
GetPullDownRatio(FrameNode * frameNode)303 float RefreshModelNG::GetPullDownRatio(FrameNode* frameNode)
304 {
305 float value = 1.0;
306 ACE_GET_NODE_LAYOUT_PROPERTY_WITH_DEFAULT_VALUE(RefreshLayoutProperty, PullDownRatio, value, frameNode, value);
307 return value;
308 }
309
GetRefreshOffset(FrameNode * frameNode)310 Dimension RefreshModelNG::GetRefreshOffset(FrameNode* frameNode)
311 {
312 Dimension value(DEFAULT_REFRESH_OFFSET, DimensionUnit::VP);
313 ACE_GET_NODE_LAYOUT_PROPERTY_WITH_DEFAULT_VALUE(RefreshLayoutProperty, RefreshOffset, value, frameNode, value);
314 return value;
315 }
316
GetPullToRefresh(FrameNode * frameNode)317 bool RefreshModelNG::GetPullToRefresh(FrameNode* frameNode)
318 {
319 bool value = true;
320 ACE_GET_NODE_LAYOUT_PROPERTY_WITH_DEFAULT_VALUE(RefreshLayoutProperty, PullToRefresh, value, frameNode, value);
321 return value;
322 }
323
SetChangeEvent(FrameNode * frameNode,RefreshChangeEvent && changeEvent)324 void RefreshModelNG::SetChangeEvent(FrameNode* frameNode, RefreshChangeEvent&& changeEvent)
325 {
326 CHECK_NULL_VOID(frameNode);
327 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
328 CHECK_NULL_VOID(eventHub);
329 eventHub->SetChangeEvent(std::move(changeEvent));
330 }
331
SetStepOffsetChange(FrameNode * frameNode,OffsetChangeEvent && dragOffset)332 void RefreshModelNG::SetStepOffsetChange(FrameNode* frameNode, OffsetChangeEvent&& dragOffset)
333 {
334 CHECK_NULL_VOID(frameNode);
335 auto eventHub = frameNode->GetOrCreateEventHub<RefreshEventHub>();
336 CHECK_NULL_VOID(eventHub);
337 eventHub->SetOnStepOffsetChange(std::move(dragOffset));
338 }
339 } // namespace OHOS::Ace::NG
340