1 /*
2  * Copyright (c) 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 "cj_prompt_ffi.h"
17 
18 #include <malloc.h>
19 
20 #include "cj_lambda.h"
21 #include "bridge/cj_frontend/interfaces/cj_ffi/utils.h"
22 #include "bridge/cj_frontend/frontend/cj_frontend_abstract.h"
23 
24 using namespace OHOS::Ace;
25 using namespace OHOS::Ace::Framework;
26 
27 namespace {
28 const int32_t SHOW_DIALOG_BUTTON_NUM_MAX = 3;
29 const int32_t SHOW_ACTION_MENU_BUTTON_NUM_MAX = 6;
30 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
31     DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
32     DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
33     DialogAlignment::BOTTOM_END };
34 
CheckFrontendLegality(int32_t size,CButtonInfo * buttonsInfo)35 RefPtr<OHOS::Ace::CJFrontendAbstract> CheckFrontendLegality(int32_t size, CButtonInfo* buttonsInfo)
36 {
37     auto frontend = AceType::DynamicCast<CJFrontendAbstract>(Utils::GetCurrentFrontend());
38     if (!frontend) {
39         LOGE("Can not get frontend.");
40         return nullptr;
41     }
42     if (size < 0 || buttonsInfo == nullptr) {
43         LOGE("Invalid buttons info");
44         return nullptr;
45     }
46     return frontend;
47 }
48 
CreateButtonInfoVector(CButtonInfo * buttonsInfo,int32_t size,int32_t numMax)49 std::vector<ButtonInfo> CreateButtonInfoVector(CButtonInfo* buttonsInfo, int32_t size, int32_t numMax)
50 {
51     std::vector<ButtonInfo> buttons;
52     if (size > numMax) {
53         size = numMax;
54         LOGE("Supports 1 - %{public}d buttons", numMax);
55     }
56     for (int i = 0; i < size; ++i) {
57         auto curInfo = buttonsInfo + i;
58         ButtonInfo button { .text = curInfo->text, .textColor = Color(curInfo->textColor).ColorToString() };
59         buttons.emplace_back(button);
60     }
61     return buttons;
62 }
63 } // namespace
64 
65 extern "C" {
FfiPromptMallocButtons(int64_t size)66 void* FfiPromptMallocButtons(int64_t size)
67 {
68     if (size <= 0) {
69         return nullptr;
70     }
71 
72     CButtonInfo* pButton = (CButtonInfo*)malloc(sizeof(CButtonInfo) * size);
73     if (pButton == nullptr) {
74         printf("Fail to malloc pButton.");
75         return nullptr;
76     }
77     return pButton;
78 }
79 
FfiPromptShowToast(const char * message,int32_t duration,const char * bottom,int32_t mode)80 void FfiPromptShowToast(const char* message, int32_t duration, const char* bottom, int32_t mode)
81 {
82     auto frontend = AceType::DynamicCast<CJFrontendAbstract>(Utils::GetCurrentFrontend());
83     if (!frontend) {
84         LOGE("Can not get frontend.");
85         return;
86     }
87     frontend->ShowToast(message, duration, bottom, NG::ToastShowMode(mode));
88 }
89 
FfiPromptShowDialog(const char * title,const char * message,int32_t size,CButtonInfo * buttonsInfo,ShowDialogCallBack callbackRef)90 void FfiPromptShowDialog(const char* title, const char* message, int32_t size,
91     CButtonInfo* buttonsInfo, ShowDialogCallBack callbackRef)
92 {
93     auto frontend = CheckFrontendLegality(size, buttonsInfo);
94     if (!frontend) {
95         return;
96     }
97     std::vector<ButtonInfo> buttons = CreateButtonInfoVector(buttonsInfo, size, SHOW_DIALOG_BUTTON_NUM_MAX);
98     std::set<std::string> callbacks;
99     callbacks.emplace("success");
100     callbacks.emplace("cancel");
101 
102     auto callback = [ffiOnClick = CJLambda::Create(callbackRef)](
103         int32_t callbackType, int32_t successType) { ffiOnClick(callbackType, successType); };
104     frontend->ShowDialog(title, message, buttons, std::move(callback), callbacks);
105 }
106 
FfiPromptShowActionMenu(const char * title,int32_t size,CButtonInfo * buttonsInfo,ShowActionMenuCallBack callbackRef)107 void FfiPromptShowActionMenu(
108     const char* title, int32_t size, CButtonInfo* buttonsInfo, ShowActionMenuCallBack callbackRef)
109 {
110     auto frontend = CheckFrontendLegality(size, buttonsInfo);
111     if (!frontend) {
112         return;
113     }
114     std::vector<ButtonInfo> buttons = CreateButtonInfoVector(buttonsInfo, size, SHOW_ACTION_MENU_BUTTON_NUM_MAX);
115     auto callback = [ffiOnClick = CJLambda::Create(callbackRef)](
116                         int callbackType, int successType) { ffiOnClick(callbackType, successType); };
117     frontend->ShowActionMenu(title, buttons, std::move(callback));
118 }
119 
FfiPromptOpenCustomDialog(void (* builder)(),NativeBaseOption options,void (* callback)(int32_t))120 void FfiPromptOpenCustomDialog(void(*builder)(), NativeBaseOption options, void(*callback)(int32_t))
121 {
122     auto frontend = AceType::DynamicCast<CJFrontendAbstract>(Utils::GetCurrentFrontend());
123     if (!frontend) {
124         LOGE("Can not get frontend.");
125         return;
126     }
127 
128     auto builderFunc = [func = CJLambda::Create(builder)]() {
129         func();
130     };
131     auto callbackFunc = [func = CJLambda::Create(callback)](int32_t customId) {
132         func(customId);
133     };
134 
135     std::function<void(const int32_t& info)> onWillDismiss = nullptr;
136 
137     auto alignment = DIALOG_ALIGNMENT[options.alignment];
138 
139     // parse maskRect
140     Dimension xDimen = Dimension(options.maskRect.x, static_cast<DimensionUnit>(options.maskRect.xUnit));
141     Dimension yDimen = Dimension(options.maskRect.y, static_cast<DimensionUnit>(options.maskRect.yUnit));
142     Dimension widthDimen =
143         Dimension(options.maskRect.width, static_cast<DimensionUnit>(options.maskRect.widthUnit));
144     Dimension heightDimen =
145         Dimension(options.maskRect.height, static_cast<DimensionUnit>(options.maskRect.heightUnit));
146     DimensionOffset offsetDimen(xDimen, yDimen);
147     auto maskRect = DimensionRect(widthDimen, heightDimen, offsetDimen);
148 
149     // parse offset
150     double dxVal = options.offset.dx.value;
151     int32_t dxType = options.offset.dx.unitType;
152     CalcDimension dx = CalcDimension(dxVal, static_cast<DimensionUnit>(dxType));
153     double dyVal = options.offset.dy.value;
154     int32_t dyType = options.offset.dy.unitType;
155     CalcDimension dy = CalcDimension(dyVal, static_cast<DimensionUnit>(dyType));
156     auto offset = DimensionOffset(dx, dy);
157 
158     PromptDialogAttr promptDialogAttr = {
159         .showInSubWindow = options.showInSubWindow,
160         .isModal = options.isModal,
161         .customBuilder = std::move(builderFunc),
162         .customOnWillDismiss = std::move(onWillDismiss),
163         .alignment = alignment,
164         .offset = offset,
165         .maskRect = maskRect,
166     };
167 
168     frontend->OpenCustomDialog(promptDialogAttr, std::move(callbackFunc));
169 }
170 
FfiPromptCloseCustomDialog(int32_t id)171 void FfiPromptCloseCustomDialog(int32_t id)
172 {
173     auto frontend = AceType::DynamicCast<CJFrontendAbstract>(Utils::GetCurrentFrontend());
174     if (!frontend) {
175         LOGE("Can not get frontend.");
176         return;
177     }
178 
179     frontend->CloseCustomDialog(id);
180 }
181 }
182