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