• 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 "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)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 {
227     // Cannot reuse component because might depend on state
228     if (customDialog) {
229         customDialog = nullptr;
230     }
231     buildFunc();
232     customDialog = ViewStackProcessor::GetInstance()->Finish();
233     if (!customDialog) {
234         LOGE("Builder does not generate view.");
235         return;
236     }
237 
238     ShowDialog(
239         dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
240 }
241 
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)242 void CustomDialogControllerModelImpl::SetCloseDialog(DialogProperties& dialogProperties,
243     const WeakPtr<AceType>& controller, std::vector<WeakPtr<AceType>>& dialogs,
244     bool& pending, bool& isShown, std::function<void()>&& cancelTask, RefPtr<AceType>& dialogComponent,
245     RefPtr<AceType>& customDialog, std::list<DialogOperation>& dialogOperation)
246 {
247     CloseDialog(
248         dialogProperties, pending, isShown, std::move(cancelTask), dialogComponent, customDialog, dialogOperation);
249 }
250 } // namespace OHOS::Ace::Framework
251