Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qohossharekit.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qohosjsutils.h"
8#include <QtCore/private/qnapi_p.h>
9#include <QtCore/private/qohoscommon_p.h>
10#include <qohosjsenv_p.h>
11#include <QtCore/private/qohoslogger_p.h>
12#include <cstdint>
13
15
16namespace QOhosShareKit {
17
18namespace {
19
20QOhosOptional<QNapi::Object> tryMakeShareKitSharedDataRecordObject(
21 QtOhos::JsState &jsState, const SharedRecord &record)
22{
23 auto optUtdType = record.mimeType != mimeTextUriList
24 ? tryMapMimeTypeToUtdTypeId(record.mimeType)
25 : QOhosOptional<std::string>(QOhosUdsMeta<::OH_UdsHyperlink>::udmfMetaId);
26
27 if (!optUtdType.has_value()) {
28 qOhosPrintfWarning(
29 "%s: Cannot convert mime type: %s to utd type.", Q_FUNC_INFO, record.mimeType.c_str());
31 }
32
33 std::vector<std::pair<std::string, QNapi::ValueWrapper>> objectProperties = {
34 {"utd", optUtdType.value()},
35 };
36
37 if (record.content.has_value()) {
38 objectProperties.emplace_back("content", record.content.value());
39 } else if (record.filePath.has_value()) {
40 objectProperties.emplace_back(
41 "uri",
43 } else {
44 qOhosPrintfWarning("%s: Record doesn't have content nor uri.", Q_FUNC_INFO);
46 }
47
48 if (record.title.has_value())
49 objectProperties.emplace_back("title", record.title.value());
50
51 if (record.label.has_value())
52 objectProperties.emplace_back("label", record.label.value());
53
54 if (record.description.has_value())
55 objectProperties.emplace_back("description", record.description.value());
56
57 if (record.thumbnail.has_value()) {
58 auto thumbnail = record.thumbnail.value();
59 auto napiThumbnail = QNapi::TypedArrayOf<std::uint8_t>::New(jsState.env(), thumbnail.length());
60 std::memcpy(napiThumbnail.Data(), thumbnail.data(), thumbnail.length());
61
62 objectProperties.emplace_back("thumbnail", napiThumbnail);
63 }
64
65 if (record.thumbnailFilePath.has_value()) {
66 objectProperties.emplace_back(
67 "thumbnailUri",
68 QOhosPlatformServices::mapPathToOhosUriInJsThread(record.thumbnailFilePath.value()));
69 }
70
71 if (record.extraData.has_value()) {
72 objectProperties.emplace_back(
73 "extraData",
74 QOhosJsEnv::toNapiValue(jsState.env(), QJsonObject::fromVariantMap(record.extraData.value())));
75 }
76
77 return makeQOhosOptional(QNapi::makeObject(jsState.env(), objectProperties));
78}
79
80QOhosOptional<QNapi::Object> tryMakeShareKitShareControllerAnchorObject(
81 QtOhos::JsState &jsState, const ShareControllerAnchor &anchor)
82{
83 if (anchor.windowOffset.isNull())
85
86 auto shareControllerAnchorObject = QNapi::makeObject(
87 jsState.env(),
88 {
89 {
90 "windowOffset",
91 QNapi::makeObject(
92 jsState.env(),
93 {
94 {"x", anchor.windowOffset.x()},
95 {"y", anchor.windowOffset.y()},
96 })
97 },
98 });
99
100 if (anchor.size.has_value() && anchor.size.value().isValid()) {
101 shareControllerAnchorObject.set(
102 "size",
103 QNapi::makeObject(
104 jsState.env(),
105 {
106 {"width", anchor.size.value().width()},
107 {"height", anchor.size.value().height()},
108 }));
109 }
110
111 return makeQOhosOptional(shareControllerAnchorObject);
112}
113
114QNapi::Object makeShareKitControllerOptionsObject(
115 QtOhos::JsState &jsState, ControllerOptions controllerOptions)
116{
117 auto controllerOptionsObject = QNapi::makeObject(jsState.env());
118
119 if (controllerOptions.selectionMode.has_value()) {
120 controllerOptionsObject.set(
121 "selectionMode", jsState.mapOhosEnumToJs(controllerOptions.selectionMode.value()));
122 }
123
124 if (controllerOptions.anchor.has_value()) {
125 auto controllerAnchorObject = tryMakeShareKitShareControllerAnchorObject(
126 jsState, controllerOptions.anchor.value());
127 if (controllerAnchorObject.has_value())
128 controllerOptionsObject.set("anchor", controllerAnchorObject.value());
129 }
130
131 if (controllerOptions.previewMode.has_value()) {
132 controllerOptionsObject.set(
133 "previewMode", jsState.mapOhosEnumToJs(controllerOptions.previewMode.value()));
134 }
135
136 if (controllerOptions.excludedAbilities.has_value()) {
137 controllerOptionsObject.set(
138 "excludedAbilities",
139 QNapi::makeArray(
140 jsState.env(), controllerOptions.excludedAbilities.value(),
141 [&](auto excludedAbilityType) {
142 return jsState.mapOhosEnumToJs(excludedAbilityType);
143 }));
144 }
145
146 return controllerOptionsObject;
147}
148
149std::shared_ptr<void> registerOnOffShareCompletedEventHandler(
150 QNapi::Object shareController, QOhosConsumer<ShareOperationResult> shareCompletedCallback)
151{
152 return QtOhos::registerOnOffMethodsBasedEventHandler(
153 shareController, "shareCompleted",
154 [shareCompletedCallback = std::move(shareCompletedCallback)](const QtOhos::CallbackInfo &cbInfo) {
155 const auto shareOperationResult = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
156 const auto targetAbilityName = shareOperationResult.eval<QNapi::String>(
157 "targetAbilityInfo.name");
158 shareCompletedCallback(
160 .targetAbilityName = targetAbilityName,
161 });
162 });
163}
164
165void shareDataImpl(
166 QtOhos::JsState &jsState, std::shared_ptr<QtOhos::QUiAbilityPeer> uiAbilityPeer,
167 const std::vector<SharedRecord> &recordsToShare, ControllerOptions controllerOptions,
168 std::function<void()> panelClosedCallback, QOhosConsumer<ShareOperationResult> shareCompletedCallback,
169 QOhosConsumer<std::shared_ptr<void>> resultConsumer)
170{
171 qOhosPrintfDebug("%s: sharing %lu records through ShareKit", Q_FUNC_INFO, recordsToShare.size());
172
173 if (recordsToShare.empty()) {
174 qOhosPrintfWarning("%s: No records to share. Skipping...", Q_FUNC_INFO);
175 resultConsumer(nullptr);
176 return;
177 }
178
179 auto firstRecord = tryMakeShareKitSharedDataRecordObject(jsState, recordsToShare.front());
180 if (!firstRecord.has_value()) {
181 qOhosPrintfWarning("%s: Failed to create the very first record, skip sharing", Q_FUNC_INFO);
182 resultConsumer(nullptr);
183 return;
184 }
185 qOhosPrintfDebug(
186 "%s: record #0 to be shared: %s",
187 Q_FUNC_INFO, QNapi::toJsonString(firstRecord.value()).c_str());
188
189 auto sharedDataObject = jsState.eval<QNapi::Object>(
190 "@kit.ShareKit.systemShare.SharedData<new>(*)", {firstRecord.value()});
191
192 for (std::size_t i = 1; i < recordsToShare.size(); i++) {
193 auto record = tryMakeShareKitSharedDataRecordObject(jsState, recordsToShare.at(i));
194 if (record.has_value()) {
195 qOhosPrintfDebug(
196 "%s: record #%zu to be shared: %s",
197 Q_FUNC_INFO, i, QNapi::toJsonString(record.value()).c_str());
198 sharedDataObject.call("addRecord", {record.value()});
199 } else {
200 qOhosPrintfWarning("%s: Failed to create record", Q_FUNC_INFO);
201 }
202 }
203
204 auto controller = jsState.eval<QNapi::Object>(
205 "@kit.ShareKit.systemShare.ShareController<new>(*)", {sharedDataObject});
206
207 auto callbacksHandle = QtOhos::moveToSharedPtr(
208 std::vector<std::shared_ptr<void>>{
209 QtOhos::registerOnOffMethodsBasedEventHandler(
210 controller, "dismiss", std::move(panelClosedCallback)),
211 registerOnOffShareCompletedEventHandler(controller, std::move(shareCompletedCallback)),
212 });
213
214 controller.evalToPromiseOrRejectOnThrow(
215 "show(*)",
216 {
217 uiAbilityPeer->qAbility().get<QNapi::Object>("context"),
218 makeShareKitControllerOptionsObject(jsState, controllerOptions),
219 })
220 .withContext(std::move(resultConsumer))
221 .onThenWithContext(
222 [callbacksHandle](auto &resultConsumer) {
223 resultConsumer(callbacksHandle);
224 })
225 .onCatchWithContext(
226 [](const QtOhos::CallbackInfo &cbInfo, auto &resultConsumer) {
227 QtOhos::logJsCallbackError(cbInfo, "ShareController.show()");
228 resultConsumer(nullptr);
229 });
230}
231
232template<typename ...Ts>
233QOhosConsumer<Ts...> makeAsyncConsumer(
234 QOhosConsumer<Ts...> baseConsumer, QOhosConsumer<std::function<void()>> asyncExecutor)
235{
236 auto sharedBaseConsumer = QtOhos::moveToSharedPtr(std::move(baseConsumer));
237 return [sharedBaseConsumer, asyncExecutor = std::move(asyncExecutor)](const Ts &...args) {
238 asyncExecutor(
239 [sharedBaseConsumer, args...]() mutable {
240 (*sharedBaseConsumer)(std::move(args)...);
241 });
242 };
243}
244
245}
246
247std::shared_ptr<void> shareData(
248 QWindow *optInstanceMainWindow, const std::vector<SharedRecord> &recordsToShare,
249 ControllerOptions controllerOptions, std::function<void()> panelClosedCallback,
250 QOhosConsumer<ShareOperationResult> shareCompletedCallback)
251{
252 auto optMainWindowInstanceObjectRef =
253 optInstanceMainWindow != nullptr
254 ? makeQOhosOptional(QtOhos::QObjectThreadSafeRef(optInstanceMainWindow))
256
257 auto panelClosedJsCallback = makeAsyncConsumer(
258 std::move(panelClosedCallback), &QtOhos::invokeInQtThread);
259 auto shareCompletedJsCallback = makeAsyncConsumer(
260 std::move(shareCompletedCallback), &QtOhos::invokeInQtThread);
261
262 return QtOhos::evalInJsThreadWithPromise<std::shared_ptr<void>>(
263 [&](QtOhos::JsState &jsState, QOhosTaskPromise<std::shared_ptr<void>> evalPromise) {
265 optMainWindowInstanceObjectRef.has_value()
266 ? jsState.tryGetQAbilityPeerByQWindow(optMainWindowInstanceObjectRef.value())
267 : jsState.defaultQAbilityPeer());
268 if (!uiAbilityPeer) {
269 qOhosPrintfWarning("%s only UIAbilities can share data with ShareKit", Q_FUNC_INFO);
270 evalPromise(nullptr);
271 return;
272 }
273
274 shareDataImpl(
275 jsState, uiAbilityPeer, recordsToShare, controllerOptions, std::move(panelClosedJsCallback),
276 std::move(shareCompletedJsCallback), std::move(evalPromise));
277 },
278 Q_FUNC_INFO);
279}
280
281}
282
283QT_END_NAMESPACE
static std::string mapPathToOhosUriInJsThread(const std::string &path)
virtual std::shared_ptr< QAbilityPeer > defaultQAbilityPeer()=0
static std::shared_ptr< QUiAbilityPeer > tryCastFromQAbilityPeerOrNull(std::shared_ptr< QAbilityPeer > qAbilityPeer)
std::shared_ptr< void > shareData(QWindow *optInstanceMainWindow, const std::vector< SharedRecord > &recordsToShare, ControllerOptions controllerOptions, std::function< void()> panelClosedCallback, QOhosConsumer< ShareOperationResult > shareCompletedCallback)
Combined button and popup list for selecting options.
std::nullopt_t makeEmptyQOhosOptional()