• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_ng/pattern/stage/page_pattern.h"
17 
18 #include "base/utils/utils.h"
19 #include "core/animation/animator.h"
20 #include "core/components/common/properties/alignment.h"
21 #include "core/pipeline_ng/pipeline_context.h"
22 
23 namespace OHOS::Ace::NG {
24 
25 namespace {
IterativeAddToSharedMap(const RefPtr<UINode> & node,SharedTransitionMap & map)26 void IterativeAddToSharedMap(const RefPtr<UINode>& node, SharedTransitionMap& map)
27 {
28     const auto& children = node->GetChildren();
29     for (const auto& child : children) {
30         auto frameChild = AceType::DynamicCast<FrameNode>(child);
31         if (!frameChild) {
32             IterativeAddToSharedMap(child, map);
33             continue;
34         }
35         auto id = frameChild->GetRenderContext()->GetShareId();
36         if (!id.empty()) {
37             LOGD("add id:%{public}s", id.c_str());
38             map[id] = frameChild;
39         }
40         IterativeAddToSharedMap(frameChild, map);
41     }
42 }
43 } // namespace
44 
OnAttachToFrameNode()45 void PagePattern::OnAttachToFrameNode()
46 {
47     auto host = GetHost();
48     CHECK_NULL_VOID(host);
49     host->GetLayoutProperty()->UpdateMeasureType(MeasureType::MATCH_PARENT);
50     host->GetLayoutProperty()->UpdateAlignment(Alignment::TOP_LEFT);
51 }
52 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> &,const DirtySwapConfig &)53 bool PagePattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& /*wrapper*/, const DirtySwapConfig& /*config*/)
54 {
55     if (isFirstLoad_) {
56         isFirstLoad_ = false;
57         if (firstBuildCallback_) {
58             firstBuildCallback_();
59             firstBuildCallback_ = nullptr;
60         }
61     }
62     return false;
63 }
64 
TriggerPageTransition(PageTransitionType type,const std::function<void ()> & onFinish)65 bool PagePattern::TriggerPageTransition(PageTransitionType type, const std::function<void()>& onFinish)
66 {
67     auto host = GetHost();
68     CHECK_NULL_RETURN(host, false);
69     auto renderContext = host->GetRenderContext();
70     CHECK_NULL_RETURN(renderContext, false);
71     if (pageTransitionFunc_) {
72         pageTransitionFunc_();
73     }
74     auto effect = FindPageTransitionEffect(type);
75     pageTransitionFinish_ = std::make_shared<std::function<void()>>(onFinish);
76     auto wrappedOnFinish = [weak = WeakClaim(this), sharedFinish = pageTransitionFinish_]() {
77         auto pattern = weak.Upgrade();
78         CHECK_NULL_VOID_NOLOG(pattern);
79         if (sharedFinish == pattern->pageTransitionFinish_) {
80             // ensure this is exactly the finish callback saved in pagePattern,
81             // otherwise means new pageTransition started
82             pattern->FirePageTransitionFinish();
83         }
84     };
85     if (effect && effect->GetUserCallback()) {
86         if (!controller_) {
87             controller_ = AceType::MakeRefPtr<Animator>(PipelineContext::GetCurrentContext());
88         }
89         if (!controller_->IsStopped()) {
90             controller_->Finish();
91         }
92         controller_->ClearInterpolators();
93         RouteType routeType = (type == PageTransitionType::ENTER_POP || type == PageTransitionType::EXIT_POP)
94                                   ? RouteType::POP
95                                   : RouteType::PUSH;
96         auto floatAnimation = AceType::MakeRefPtr<CurveAnimation<float>>(0.0f, 1.0f, effect->GetCurve());
97         floatAnimation->AddListener(
98             [routeType, handler = effect->GetUserCallback(), weak = WeakClaim(this)](const float& progress) {
99                 auto pattern = weak.Upgrade();
100                 CHECK_NULL_VOID(pattern);
101                 handler(routeType, progress);
102             });
103         if (effect->GetDelay() >= 0) {
104             controller_->SetStartDelay(effect->GetDelay());
105         }
106         controller_->SetDuration(effect->GetDuration());
107         controller_->AddInterpolator(floatAnimation);
108         controller_->AddStopListener(wrappedOnFinish);
109         controller_->Forward();
110         return renderContext->TriggerPageTransition(type, nullptr);
111     }
112     return renderContext->TriggerPageTransition(type, wrappedOnFinish);
113 }
114 
ProcessHideState()115 void PagePattern::ProcessHideState()
116 {
117     auto host = GetHost();
118     CHECK_NULL_VOID(host);
119     host->SetActive(false);
120     host->OnVisibleChange(false);
121     host->GetLayoutProperty()->UpdateVisibility(VisibleType::INVISIBLE);
122     auto parent = host->GetAncestorNodeOfFrame();
123     CHECK_NULL_VOID(parent);
124     parent->MarkNeedSyncRenderTree();
125     parent->RebuildRenderContextTree();
126 }
127 
ProcessShowState()128 void PagePattern::ProcessShowState()
129 {
130     auto host = GetHost();
131     CHECK_NULL_VOID(host);
132     host->SetActive(true);
133     host->OnVisibleChange(true);
134     host->GetLayoutProperty()->UpdateVisibility(VisibleType::VISIBLE);
135     auto parent = host->GetAncestorNodeOfFrame();
136     CHECK_NULL_VOID(parent);
137     parent->MarkNeedSyncRenderTree();
138     parent->RebuildRenderContextTree();
139 }
140 
OnShow()141 void PagePattern::OnShow()
142 {
143     // Do not invoke onPageShow unless the initialRender function has been executed.
144     CHECK_NULL_VOID_NOLOG(isRenderDone_);
145     CHECK_NULL_VOID_NOLOG(!isOnShow_);
146     isOnShow_ = true;
147     auto context = PipelineContext::GetCurrentContext();
148     CHECK_NULL_VOID(context);
149     if (onPageShow_) {
150         context->PostAsyncEvent([onPageShow = onPageShow_]() { onPageShow(); });
151     }
152 }
153 
OnHide()154 void PagePattern::OnHide()
155 {
156     CHECK_NULL_VOID_NOLOG(isOnShow_);
157     isOnShow_ = false;
158     auto context = PipelineContext::GetCurrentContext();
159     CHECK_NULL_VOID(context);
160     if (onPageHide_) {
161         context->PostAsyncEvent([onPageHide = onPageHide_]() { onPageHide(); });
162     }
163 }
164 
BuildSharedTransitionMap()165 void PagePattern::BuildSharedTransitionMap()
166 {
167     auto host = GetHost();
168     CHECK_NULL_VOID(host);
169     sharedTransitionMap_.clear();
170     IterativeAddToSharedMap(host, sharedTransitionMap_);
171 }
172 
ReloadPage()173 void PagePattern::ReloadPage()
174 {
175     auto host = GetHost();
176     CHECK_NULL_VOID(host);
177     auto customNode = DynamicCast<CustomNodeBase>(host->GetFirstChild());
178     CHECK_NULL_VOID(customNode);
179     customNode->FireReloadFunction(true);
180 }
181 
FindPageTransitionEffect(PageTransitionType type)182 RefPtr<PageTransitionEffect> PagePattern::FindPageTransitionEffect(PageTransitionType type)
183 {
184     RefPtr<PageTransitionEffect> result;
185     for (auto iter = pageTransitionEffects_.rbegin(); iter != pageTransitionEffects_.rend(); ++iter) {
186         auto effect = *iter;
187         if (effect->CanFit(type)) {
188             result = effect;
189             break;
190         }
191     }
192     return result;
193 }
194 
ClearPageTransitionEffect()195 void PagePattern::ClearPageTransitionEffect()
196 {
197     pageTransitionEffects_.clear();
198 }
199 
GetTopTransition() const200 RefPtr<PageTransitionEffect> PagePattern::GetTopTransition() const
201 {
202     return pageTransitionEffects_.empty() ? nullptr : pageTransitionEffects_.back();
203 }
204 
AddPageTransition(const RefPtr<PageTransitionEffect> & effect)205 void PagePattern::AddPageTransition(const RefPtr<PageTransitionEffect>& effect)
206 {
207     pageTransitionEffects_.emplace_back(effect);
208 }
209 
AddJsAnimator(const std::string & animatorId,const RefPtr<Framework::AnimatorInfo> & animatorInfo)210 void PagePattern::AddJsAnimator(const std::string& animatorId, const RefPtr<Framework::AnimatorInfo>& animatorInfo)
211 {
212     CHECK_NULL_VOID(animatorInfo);
213     auto animator = animatorInfo->GetAnimator();
214     CHECK_NULL_VOID(animator);
215     animator->AttachScheduler(PipelineContext::GetCurrentContext());
216     jsAnimatorMap_[animatorId] = animatorInfo;
217 }
218 
GetJsAnimator(const std::string & animatorId)219 RefPtr<Framework::AnimatorInfo> PagePattern::GetJsAnimator(const std::string& animatorId)
220 {
221     auto iter = jsAnimatorMap_.find(animatorId);
222     if (iter != jsAnimatorMap_.end()) {
223         return iter->second;
224     }
225     return nullptr;
226 }
227 
SetFirstBuildCallback(std::function<void ()> && buildCallback)228 void PagePattern::SetFirstBuildCallback(std::function<void()>&& buildCallback)
229 {
230     if (isFirstLoad_) {
231         firstBuildCallback_ = std::move(buildCallback);
232     } else if (buildCallback) {
233         buildCallback();
234     }
235 }
236 
FirePageTransitionFinish()237 void PagePattern::FirePageTransitionFinish()
238 {
239     if (pageTransitionFinish_) {
240         auto onFinish = *pageTransitionFinish_;
241         pageTransitionFinish_ = nullptr;
242         if (onFinish) {
243             onFinish();
244         }
245     }
246 }
247 
StopPageTransition()248 void PagePattern::StopPageTransition()
249 {
250     if (controller_ && !controller_->IsStopped()) {
251         controller_->Finish();
252         return;
253     }
254     FirePageTransitionFinish();
255 }
256 
257 } // namespace OHOS::Ace::NG