• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "bridge/declarative_frontend/jsview/models/custom_dialog_controller_model_impl.h"
17 
18 #include "base/subwindow/subwindow_manager.h"
19 #include "core/components/dialog/dialog_component.h"
20 #include "core/pipeline_ng/pipeline_context.h"
21 #include "frameworks/bridge/common/utils/engine_helper.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23 
24 namespace OHOS::Ace::Framework {
25 namespace {
26 constexpr uint32_t DELAY_TIME_FOR_STACK = 100;
27 } // namespace
28 
NotifyDialogOperation(DialogOperation operation,DialogProperties & dialogProperties,bool & pending,bool & isShown,std::function<void ()> && cancelTask,RefPtr<AceType> & dialogComponent,RefPtr<AceType> & customDialog,std::list<DialogOperation> & dialogOperation)29 void CustomDialogControllerModelImpl::NotifyDialogOperation(DialogOperation operation,
30     DialogProperties& dialogProperties, bool& pending, bool& isShown, std::function<void()>&& cancelTask,
31     RefPtr<AceType>& dialogComponent, RefPtr<AceType>& customDialog, std::list<DialogOperation>& dialogOperation)
32 {
33     LOGI("JSCustomDialogController(NotifyDialogOperation) operation: %{public}d", operation);
34     if (operation == DialogOperation::DIALOG_OPEN) {
35         isShown = true;
36         pending = false;
37         for (auto iter = dialogOperation.begin(); iter != dialogOperation.end();) {
38             if (*iter == DialogOperation::DIALOG_OPEN) {
39                 dialogOperation.erase(iter++);
40                 continue;
41             }
42 
43             if (*iter == DialogOperation::DIALOG_CLOSE) {
44                 dialogOperation.erase(iter);
45                 CloseDialog(dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog,
46                     dialogOperation);
47                 break;
48             }
49         }
50     } else if (operation == DialogOperation::DIALOG_CLOSE) {
51         isShown = false;
52         pending = false;
53         for (auto iter = dialogOperation.begin(); iter != dialogOperation.end();) {
54             if (*iter == DialogOperation::DIALOG_CLOSE) {
55                 dialogOperation.erase(iter++);
56                 continue;
57             }
58 
59             if (*iter == DialogOperation::DIALOG_OPEN) {
60                 dialogOperation.erase(iter);
61                 ShowDialog(dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog,
62                     dialogOperation);
63                 break;
64             }
65         }
66     }
67 }
68 
ShowDialog(DialogProperties & dialogProperties,bool & pending,bool & isShown,std::function<void ()> && cancelTask,RefPtr<AceType> & dialogComponent,RefPtr<AceType> & customDialog,std::list<DialogOperation> & dialogOperation)69 void CustomDialogControllerModelImpl::ShowDialog(DialogProperties& dialogProperties, bool& pending, bool& isShown,
70     std::function<void()>&& cancelTask, RefPtr<AceType>& dialogComponent, RefPtr<AceType>& customDialog,
71     std::list<DialogOperation>& dialogOperation)
72 {
73     RefPtr<Container> container;
74     auto current = Container::Current();
75     if (!current) {
76         LOGE("Container is null.");
77         return;
78     }
79     if (current->IsSubContainer()) {
80         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
81         container = AceEngine::Get().GetContainer(parentContainerId);
82     } else {
83         container = std::move(current);
84     }
85     if (!container) {
86         LOGE("Container is null.");
87         return;
88     }
89     auto context = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
90     if (!context) {
91         LOGE("JSCustomDialogController No Context");
92         return;
93     }
94     dialogProperties.customComponent = customDialog;
95     dialogProperties.callbacks.try_emplace("cancel", EventMarker(std::move(cancelTask)));
96     dialogProperties.onStatusChanged = [&isShown](bool isShownStatus) {
97         if (!isShownStatus) {
98             isShown = isShownStatus;
99         }
100     };
101 
102     auto executor = context->GetTaskExecutor();
103     if (!executor) {
104         LOGE("JSCustomDialogController(ShowDialog) No Executor. Cannot post task.");
105         return;
106     }
107 
108     if (pending) {
109         LOGI("JSCustomDialogController(ShowDialog) current state is pending.");
110         dialogOperation.emplace_back(DialogOperation::DIALOG_OPEN);
111         return;
112     }
113 
114     if (isShown) {
115         LOGI("JSCustomDialogController(ShowDialog) CustomDialog has already shown.");
116         return;
117     }
118 
119     pending = true;
120     auto task = [context, showDialogProperties = dialogProperties, &dialogProperties, &pending, &isShown, &cancelTask,
121                     &dialogComponent, &customDialog, &dialogOperation, this]() mutable {
122         if (context) {
123             dialogComponent = context->ShowDialog(showDialogProperties, false, "CustomDialog");
124         } else {
125             LOGE("JSCustomDialogController(ShowDialog) context is null.");
126         }
127         this->NotifyDialogOperation(DialogOperation::DIALOG_OPEN, dialogProperties, pending, isShown,
128             std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
129     };
130     auto stack = context->GetLastStack();
131     auto result = false;
132     if (stack) {
133         result = executor->PostTask(task, TaskExecutor::TaskType::UI);
134     } else {
135         LOGE("JSCustomDialogController(ShowDialog) stack is null, post delay task.");
136         result = executor->PostDelayedTask(task, TaskExecutor::TaskType::UI, DELAY_TIME_FOR_STACK);
137     }
138     if (!result) {
139         LOGW("JSCustomDialogController(ShowDialog) fail to post task, reset pending status");
140         pending = false;
141     }
142 }
143 
CloseDialog(DialogProperties & dialogProperties,bool & pending,bool & isShown,std::function<void ()> && cancelTask,RefPtr<AceType> & dialogComponent,RefPtr<AceType> & customDialog,std::list<DialogOperation> & dialogOperation)144 void CustomDialogControllerModelImpl::CloseDialog(DialogProperties& dialogProperties, bool& pending, bool& isShown,
145     std::function<void()>&& cancelTask, RefPtr<AceType>& dialogComponent, RefPtr<AceType>& customDialog,
146     std::list<DialogOperation>& dialogOperation)
147 {
148     LOGI("JSCustomDialogController(CloseDialog)");
149     RefPtr<Container> container;
150     auto current = Container::Current();
151     if (!current) {
152         LOGE("Container is null.");
153         return;
154     }
155     if (current->IsSubContainer()) {
156         auto parentContainerId = SubwindowManager::GetInstance()->GetParentContainerId(Container::CurrentId());
157         container = AceEngine::Get().GetContainer(parentContainerId);
158     } else {
159         container = std::move(current);
160     }
161     if (!container) {
162         LOGE("Container is null.");
163         return;
164     }
165     auto context = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
166     if (!context) {
167         LOGE("JSCustomDialogController No Context");
168         return;
169     }
170     const auto& lastStack = context->GetLastStack();
171     if (!lastStack) {
172         LOGE("JSCustomDialogController No Stack!");
173         return;
174     }
175     auto executor = context->GetTaskExecutor();
176     if (!executor) {
177         LOGE("JSCustomDialogController(CloseDialog) No Executor. Cannot post task.");
178         return;
179     }
180 
181     if (pending) {
182         LOGI("JSCustomDialogController(CloseDialog) current state is pending.");
183         dialogOperation.emplace_back(DialogOperation::DIALOG_CLOSE);
184         return;
185     }
186 
187     pending = true;
188     auto task = [lastStack, showDialogComponent = dialogComponent, &dialogProperties, &pending, &isShown, &cancelTask,
189                     &dialogComponent, &customDialog, &dialogOperation, this]() {
190         if (!lastStack || !showDialogComponent) {
191             LOGI("JSCustomDialogController(CloseDialog) stack or dialog is null.");
192             this->NotifyDialogOperation(DialogOperation::DIALOG_CLOSE, dialogProperties, pending, isShown,
193                 std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
194             return;
195         }
196         auto animator = AceType::DynamicCast<DialogComponent>(showDialogComponent)->GetAnimator();
197         auto dialogId = AceType::DynamicCast<DialogComponent>(showDialogComponent)->GetDialogId();
198         if (animator) {
199             if (!AceType::DynamicCast<DialogComponent>(showDialogComponent)->HasStopListenerAdded()) {
200                 animator->AddStopListener([lastStack, dialogId] {
201                     if (lastStack) {
202                         lastStack->PopDialog(dialogId);
203                     }
204                 });
205                 AceType::DynamicCast<DialogComponent>(showDialogComponent)->SetHasStopListenerAdded(true);
206             }
207             animator->Play();
208         } else {
209             lastStack->PopDialog(dialogId);
210         }
211         this->NotifyDialogOperation(DialogOperation::DIALOG_CLOSE, dialogProperties, pending, isShown,
212             std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
213     };
214     auto result = executor->PostTask(task, TaskExecutor::TaskType::UI);
215     if (!result) {
216         LOGW("JSCustomDialogController(CloseDialog) fail to post task, reset pending status");
217         pending = false;
218     }
219 
220     dialogComponent = nullptr;
221 }
222 
SetOpenDialog(DialogProperties & dialogProperties,std::vector<WeakPtr<AceType>> & dialogs,bool & pending,bool & isShown,std::function<void ()> && cancelTask,std::function<void ()> && buildFunc,RefPtr<AceType> & dialogComponent,RefPtr<AceType> & customDialog,std::list<DialogOperation> & dialogOperation)223 void CustomDialogControllerModelImpl::SetOpenDialog(DialogProperties& dialogProperties,
224     std::vector<WeakPtr<AceType>>& dialogs, bool& pending, bool& isShown, std::function<void()>&& cancelTask,
225     std::function<void()>&& buildFunc, RefPtr<AceType>& dialogComponent, RefPtr<AceType>& customDialog,
226     std::list<DialogOperation>& dialogOperation)
227 {
228     // Cannot reuse component because might depend on state
229     if (customDialog) {
230         customDialog = nullptr;
231     }
232     buildFunc();
233     customDialog = ViewStackProcessor::GetInstance()->Finish();
234 
235     if (!customDialog) {
236         LOGE("Builder does not generate view.");
237         return;
238     }
239 
240     ShowDialog(
241         dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
242 }
243 
SetCloseDialog(DialogProperties & dialogProperties,std::vector<WeakPtr<AceType>> & dialogs,bool & pending,bool & isShown,std::function<void ()> && cancelTask,RefPtr<AceType> & dialogComponent,RefPtr<AceType> & customDialog,std::list<DialogOperation> & dialogOperation)244 void CustomDialogControllerModelImpl::SetCloseDialog(DialogProperties& dialogProperties,
245     std::vector<WeakPtr<AceType>>& dialogs, bool& pending, bool& isShown, std::function<void()>&& cancelTask,
246     RefPtr<AceType>& dialogComponent, RefPtr<AceType>& customDialog, std::list<DialogOperation>& dialogOperation)
247 {
248     CloseDialog(
249         dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
250 }
251 } // namespace OHOS::Ace::Framework