Page MenuHomePhorge

D340.1786191545.diff
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

D340.1786191545.diff

diff --git a/src/contents/ui/StickerPicker.qml b/src/contents/ui/StickerPicker.qml
--- a/src/contents/ui/StickerPicker.qml
+++ b/src/contents/ui/StickerPicker.qml
@@ -21,6 +21,42 @@
signal sendMessageRequested(var eventJson)
+ property var removeStickerPack
+ property string removeStickerShortCode: ''
+
+ property var removeStickerHandler: Kazv.AsyncHandler {
+ trigger: () => {
+ return matrixSession.updateStickerPack(
+ stickerPicker.removeStickerPack.removeSticker(stickerPicker.removeStickerShortCode)
+ );
+ }
+ onResolved: (success, data) => {
+ if (!success) {
+ showPassiveNotification(l10n.get('sticker-remove-failed-prompt', { errorCode: data.errorCode, errorMsg: data.error }));
+ }
+ }
+ }
+
+ function requestRemoveSticker(pack, shortCode) {
+ stickerPicker.removeStickerPack = pack;
+ stickerPicker.removeStickerShortCode = shortCode;
+ removeStickerConfirmationComp.createObject(Overlay.overlay, {
+ message: l10n.get('sticker-remove-confirmation-message', { shortCode: shortCode })
+ }).open();
+ }
+
+ property var removeStickerConfirmationComp: Component {
+ Kazv.ConfirmationOverlay {
+ objectName: 'removeStickerConfirmation'
+ shouldSelfDestroy: true
+ title: l10n.get('sticker-remove-confirmation-title')
+ message: l10n.get('sticker-remove-confirmation-message')
+ confirmActionText: l10n.get('sticker-remove-confirm-action')
+ cancelActionText: l10n.get('sticker-remove-cancel-action')
+ onAccepted: stickerPicker.removeStickerHandler.call()
+ }
+ }
+
TabBar {
id: packListView
Layout.fillWidth: true
@@ -96,6 +132,16 @@
function requestSendMessage() {
stickerPicker.sendMessageRequested(sticker.makeEventJson());
}
+
+ ContextMenu.menu: Menu {
+ objectName: 'stickerContextMenu'
+ Kirigami.Action {
+ objectName: 'removeStickerMenuItem'
+ text: l10n.get('sticker-remove-action')
+ icon.name: 'edit-delete'
+ onTriggered: stickerPicker.requestRemoveSticker(currentPack, sticker.shortCode)
+ }
+ }
}
}
}
diff --git a/src/l10n/cmn-Hans/100-ui.ftl b/src/l10n/cmn-Hans/100-ui.ftl
--- a/src/l10n/cmn-Hans/100-ui.ftl
+++ b/src/l10n/cmn-Hans/100-ui.ftl
@@ -283,6 +283,13 @@
add-sticker-popup-cancel-button = 取消
add-sticker-popup-failed-prompt = 无法添加贴纸。错误代码:{ $errorCode }。错误讯息:{ $errorMsg }。
+sticker-remove-action = 移除贴纸...
+sticker-remove-confirmation-title = 移除贴纸
+sticker-remove-confirmation-message = 确定要移除贴纸「{ $shortCode }」吗?
+sticker-remove-confirm-action = 移除
+sticker-remove-cancel-action = 不移除
+sticker-remove-failed-prompt = 无法移除贴纸。错误代码:{ $errorCode }。错误讯息:{ $errorMsg }。
+
kazv-io-download-success-prompt = 下载成功
kazv-io-download-failure-prompt = 下载失败:{ $detail }
kazv-io-failure-detail-user-cancel = 用户已取消
diff --git a/src/l10n/en/100-ui.ftl b/src/l10n/en/100-ui.ftl
--- a/src/l10n/en/100-ui.ftl
+++ b/src/l10n/en/100-ui.ftl
@@ -305,6 +305,13 @@
add-sticker-popup-cancel-button = Cancel
add-sticker-popup-failed-prompt = Unable to add sticker. Error code: { $errorCode }. Error message: { $errorMsg }.
+sticker-remove-action = Remove sticker...
+sticker-remove-confirmation-title = Remove sticker
+sticker-remove-confirmation-message = Are you sure you want to remove the sticker "{ $shortCode }"?
+sticker-remove-confirm-action = Remove
+sticker-remove-cancel-action = Do not remove
+sticker-remove-failed-prompt = Unable to remove sticker. Error code: { $errorCode }. Error message: { $errorMsg }.
+
kazv-io-download-success-prompt = Download successful
kazv-io-download-failure-prompt = Download failure: { $detail }
kazv-io-failure-detail-user-cancel = User canceled
diff --git a/src/matrix-sticker-pack.hpp b/src/matrix-sticker-pack.hpp
--- a/src/matrix-sticker-pack.hpp
+++ b/src/matrix-sticker-pack.hpp
@@ -56,4 +56,13 @@
* @return The MatrixStickerPackSource of the modified pack.
*/
Q_INVOKABLE QVariant addSticker(const QString &shortCode, MatrixEvent *event) const;
+
+ /**
+ * Remove a sticker from the pack by short code and return the
+ * source of the modified pack.
+ *
+ * @param shortCode The short code of the sticker to remove.
+ * @return The MatrixStickerPackSource of the modified pack.
+ */
+ Q_INVOKABLE QVariant removeSticker(const QString &shortCode) const;
};
diff --git a/src/matrix-sticker-pack.cpp b/src/matrix-sticker-pack.cpp
--- a/src/matrix-sticker-pack.cpp
+++ b/src/matrix-sticker-pack.cpp
@@ -121,3 +121,18 @@
return QVariant::fromValue(source);
}
+
+QVariant MatrixStickerPack::removeSticker(const QString &shortCode) const
+{
+ auto source = m_source.get();
+
+ auto eventJson = source.event.raw().get();
+ if (eventJson.contains("/content/images"_json_pointer)
+ && eventJson["content"]["images"].is_object()) {
+ eventJson["content"]["images"].erase(shortCode.toStdString());
+ }
+
+ source.event = Event(eventJson);
+
+ return QVariant::fromValue(source);
+}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -99,6 +99,7 @@
tst_SendMessageBoxDrafts.qml
tst_SendMessageBox.qml
tst_StickerPackNameProvider.qml
+ tst_StickerPicker.qml
tst_TypingIndicator.qml
tst_UserNameProvider.qml
tst_UserPage.qml
diff --git a/src/tests/matrix-sticker-pack-test.cpp b/src/tests/matrix-sticker-pack-test.cpp
--- a/src/tests/matrix-sticker-pack-test.cpp
+++ b/src/tests/matrix-sticker-pack-test.cpp
@@ -40,6 +40,7 @@
void testStickerPackList();
void testStickerPackListInRoom();
void testAddToPack();
+ void testRemoveFromPack();
};
// https://github.com/Sorunome/matrix-doc/blob/soru/emotes/proposals/2545-emotes.md
@@ -338,6 +339,31 @@
QVERIFY(newSource.event.content().get() == expected);
}
+void MatrixStickerPackTest::testRemoveFromPack()
+{
+ auto sourceCursor = lager::make_state(MatrixStickerPackSource{
+ MatrixStickerPackSource::AccountData,
+ "im.ponies.user_emotes",
+ stickerPackEvent,
+ "",
+ "",
+ }, lager::automatic_tag{});
+
+ auto stickerPack = toUniquePtr(new MatrixStickerPack(sourceCursor));
+
+ auto newSource = stickerPack->removeSticker(u"myemote"_s).template value<MatrixStickerPackSource>();
+
+ auto expected = sourceCursor.get().event.content().get();
+ expected["images"].erase("myemote");
+
+ QVERIFY(newSource.event.content().get() == expected);
+ QVERIFY(!newSource.event.content().get()["images"].contains("myemote"));
+
+ // Removing a non-existent sticker should leave the pack unchanged.
+ auto unchangedSource = stickerPack->removeSticker(u"doesnotexist"_s).template value<MatrixStickerPackSource>();
+ QVERIFY(unchangedSource.event.content().get() == sourceCursor.get().event.content().get());
+}
+
QTEST_MAIN(MatrixStickerPackTest)
#include "matrix-sticker-pack-test.moc"
diff --git a/src/tests/quick-tests/tst_StickerPicker.qml b/src/tests/quick-tests/tst_StickerPicker.qml
new file mode 100644
--- /dev/null
+++ b/src/tests/quick-tests/tst_StickerPicker.qml
@@ -0,0 +1,82 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtQuick.Window
+import QtQuick.Controls
+import QtTest 1.0
+
+import '../../contents/ui' as Kazv
+import 'test-helpers.js' as JsHelpers
+import 'test-helpers' as QmlHelpers
+
+QmlHelpers.TestItem {
+ id: item
+
+ property var someShortCode: 'myemote'
+
+ property var somePack: ListModel {
+ id: somePack
+ property string packName: 'Pack 0'
+ function removeSticker(shortCode) {
+ return { _removedShortCode: shortCode };
+ }
+ function at(index) {
+ return null;
+ }
+ }
+
+ Kazv.StickerPicker {
+ id: stickerPicker
+ anchors.fill: parent
+ stickerPackList: ListModel {
+ id: stickerPackListModel
+ ListElement {}
+ function at(index) {
+ return somePack;
+ }
+ }
+ }
+
+ TestCase {
+ id: stickerPickerTest
+ name: 'StickerPickerTest'
+ when: windowShown
+
+ function init() {
+ mockHelper.clearAll();
+ }
+
+ function _openConfirmation() {
+ stickerPicker.requestRemoveSticker(somePack, item.someShortCode);
+ const popup = findChild(Overlay.overlay, 'removeStickerConfirmation');
+ verify(popup);
+ tryVerify(() => popup.opened);
+ return popup;
+ }
+
+ function test_removeStickerConfirm() {
+ const popup = _openConfirmation();
+ mouseClick(findChild(popup, 'confirmButton'));
+ verify(matrixSession.updateStickerPack.calledTimes() === 1);
+ verify(JsHelpers.deepEqual(matrixSession.updateStickerPack.lastArgs()[0], { _removedShortCode: item.someShortCode }));
+ tryVerify(() => !popup.opened);
+ tryVerify(() => !findChild(Overlay.overlay, 'removeStickerConfirmation'));
+ compare(showPassiveNotification.calledTimes(), 0);
+ }
+
+ function test_removeStickerFailure() {
+ const popup = _openConfirmation();
+ mouseClick(findChild(popup, 'confirmButton'));
+ verify(matrixSession.updateStickerPack.calledTimes() === 1);
+ tryVerify(() => !popup.opened);
+ matrixSession.updateStickerPack.lastRetVal().resolve(false, { errorCode: 'M_FORBIDDEN', error: 'no' });
+ compare(showPassiveNotification.calledTimes(), 1);
+ compare(showPassiveNotification.lastArgs()[0], l10n.get('sticker-remove-failed-prompt', { errorCode: 'M_FORBIDDEN', errorMsg: 'no' }));
+ }
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Aug 8, 5:19 AM (15 h, 3 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1722720
Default Alt Text
D340.1786191545.diff (9 KB)

Event Timeline