diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index 83a998d..c56af5b 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -64,6 +64,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \ qml/components/ReplyMarkupButtons.qml \ qml/components/StickerPicker.qml \ qml/components/PhotoTextsListItem.qml \ + qml/components/StickerSetOverlay.qml \ qml/components/TDLibImage.qml \ qml/components/TDLibMinithumbnail.qml \ qml/components/TDLibPhoto.qml \ diff --git a/qml/components/StickerSetOverlay.qml b/qml/components/StickerSetOverlay.qml new file mode 100644 index 0000000..0cf65e3 --- /dev/null +++ b/qml/components/StickerSetOverlay.qml @@ -0,0 +1,170 @@ +/* + Copyright (C) 2020-21 Sebastian J. Wolf and other contributors + + This file is part of Fernschreiber. + + Fernschreiber is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Fernschreiber is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fernschreiber. If not, see . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import "./messageContent" +import "../js/functions.js" as Functions +import "../js/twemoji.js" as Emoji +import "../js/debug.js" as Debug + +Flickable { + id: stickerSetOverlayFlickable + anchors.fill: parent + boundsBehavior: Flickable.StopAtBounds + contentHeight: stickerSetContentColumn.height + clip: true + + property string stickerSetId; + property var stickerSet; + property bool setLoaded: false; + signal requestClose; + + Component.onCompleted: { + if (!stickerManager.hasStickerSet(stickerSetId)) { + tdLibWrapper.getStickerSet(stickerSetId); + } else { + stickerSet = stickerManager.getStickerSet(stickerSetId); + } + } + + Connections { + target: tdLibWrapper + onStickerSetReceived: { + if (stickerSet.id === stickerSetOverlayFlickable.stickerSetId) { + stickerSetOverlayFlickable.stickerSet = stickerSet; + } + } + } + + Timer { + id: stickerSetLoadedTimer + interval: 100 + running: true + repeat: false + onTriggered: { + stickerSetOverlayFlickable.setLoaded = true; + } + } + + Rectangle { + id: stickerSetContentBackground + color: Theme.overlayBackgroundColor + opacity: 0.7 + anchors.fill: parent + MouseArea { + anchors.fill: parent + onClicked: { + stickerSetOverlayFlickable.requestClose(); + } + } + } + + Column { + id: stickerSetContentColumn + spacing: Theme.paddingMedium + width: parent.width + height: parent.height + + Row { + id: stickerSetTitleRow + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + height: overlayStickerTitleText.height + ( 2 * Theme.paddingMedium ) + anchors.horizontalCenter: parent.horizontalCenter + + Label { + id: overlayStickerTitleText + + width: parent.width - ( installSetButton.visible ? installSetButton.width : 0 ) - closeSetButton.width + text: stickerSet.title + font.pixelSize: Theme.fontSizeExtraLarge + font.weight: Font.ExtraBold + maximumLineCount: 1 + truncationMode: TruncationMode.Fade + textFormat: Text.StyledText + anchors.verticalCenter: parent.verticalCenter + } + + IconButton { + id: installSetButton + icon.source: "image://theme/icon-m-add" + anchors.verticalCenter: parent.verticalCenter + visible: !stickerSet.is_installed + onClicked: { + tdLibWrapper.changeStickerSet(stickerSet.id, true); + } + } + + IconButton { + id: closeSetButton + icon.source: "image://theme/icon-m-clear" + anchors.verticalCenter: parent.verticalCenter + onClicked: { + stickerSetOverlayFlickable.requestClose(); + } + } + } + + SilicaGridView { + id: stickerSetGridView + + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + height: parent.height - stickerSetTitleRow.height - Theme.paddingMedium + anchors.horizontalCenter: parent.horizontalCenter + + cellWidth: chatPage.isLandscape ? (width / 5) : (width / 3); + cellHeight: cellWidth + + visible: count > 0 + + clip: true + + model: stickerSet.stickers + delegate: Item { + width: stickerSetGridView.cellWidth - Theme.paddingSmall + height: stickerSetGridView.cellHeight - Theme.paddingSmall + + Image { + id: singleStickerImage + source: modelData.thumbnail.file.local.is_downloading_completed ? modelData.thumbnail.file.local.path : "" + anchors.fill: parent + visible: modelData.thumbnail.file.local.is_downloading_completed + asynchronous: true + onStatusChanged: { + if (status === Image.Ready) { + stickerSetLoadedTimer.restart(); + } + } + } + Label { + font.pixelSize: Theme.fontSizeHuge + anchors.fill: parent + maximumLineCount: 1 + truncationMode: TruncationMode.Fade + text: Emoji.emojify(modelData.emoji, font.pixelSize) + visible: !modelData.thumbnail.file.local.is_downloading_completed + } + + } + + VerticalScrollDecorator {} + } + + } + +} diff --git a/qml/components/messageContent/MessageSticker.qml b/qml/components/messageContent/MessageSticker.qml index 4b698c2..5216e57 100644 --- a/qml/components/messageContent/MessageSticker.qml +++ b/qml/components/messageContent/MessageSticker.qml @@ -1,5 +1,5 @@ /* - Copyright (C) 2020 Sebastian J. Wolf and other contributors + Copyright (C) 2020-21 Sebastian J. Wolf and other contributors This file is part of Fernschreiber. @@ -96,6 +96,14 @@ MessageContentBase { opacity: !stickerVisible && !placeHolderDelayTimer.running ? 0.15 : 0 Behavior on opacity { FadeAnimation {} } } + + MouseArea { + anchors.fill: parent + onClicked: { + stickerSetOverlayLoader.stickerSetId = stickerData.set_id; + stickerSetOverlayLoader.active = true; + } + } } Timer { diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index d2346bb..1740822 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -1285,6 +1285,28 @@ Page { } } + Loader { + id: stickerSetOverlayLoader + + property string stickerSetId; + + active: false + asynchronous: true + width: parent.width + height: active ? parent.height : 0 + sourceComponent: Component { + StickerSetOverlay { + stickerSetId: stickerSetOverlayLoader.stickerSetId + onRequestClose: { + stickerSetOverlayLoader.active = false; + } + } + } + + onActiveChanged: { + } + } + InlineQuery { id: inlineQuery textField: newMessageTextField diff --git a/src/stickermanager.cpp b/src/stickermanager.cpp index e0ab6bf..479c672 100644 --- a/src/stickermanager.cpp +++ b/src/stickermanager.cpp @@ -50,6 +50,16 @@ QVariantList StickerManager::getInstalledStickerSets() return this->installedStickerSets; } +QVariantMap StickerManager::getStickerSet(const QString &stickerSetId) +{ + return this->stickerSets.value(stickerSetId).toMap(); +} + +bool StickerManager::hasStickerSet(const QString &stickerSetId) +{ + return this->stickerSets.contains(stickerSetId); +} + bool StickerManager::needsReload() { return this->reloadNeeded; @@ -104,19 +114,25 @@ void StickerManager::handleStickerSetsReceived(const QVariantList &stickerSets) this->stickerSetMap.clear(); while (stickerSetIdIterator.hasNext()) { QString stickerSetId = stickerSetIdIterator.next().toString(); - this->installedStickerSets.append(this->stickerSets.value(stickerSetId)); - this->stickerSetMap.insert(stickerSetId, i); - i++; + if (this->installedStickerSetIds.contains(stickerSetId)) { + this->installedStickerSets.append(this->stickerSets.value(stickerSetId)); + this->stickerSetMap.insert(stickerSetId, i); + i++; + } } } void StickerManager::handleStickerSetReceived(const QVariantMap &stickerSet) { QString stickerSetId = stickerSet.value("id").toString(); - LOG("Receiving complete sticker set...." << stickerSetId); this->stickerSets.insert(stickerSetId, stickerSet); - int setIndex = this->stickerSetMap.value(stickerSetId).toInt(); - this->installedStickerSets.replace(setIndex, stickerSet); + if (this->installedStickerSetIds.contains(stickerSetId)) { + LOG("Receiving installed sticker set...." << stickerSetId); + int setIndex = this->stickerSetMap.value(stickerSetId).toInt(); + this->installedStickerSets.replace(setIndex, stickerSet); + } else { + LOG("Receiving new sticker set...." << stickerSetId); + } QVariantList stickerList = stickerSet.value("stickers").toList(); QListIterator stickerIterator(stickerList); while (stickerIterator.hasNext()) { diff --git a/src/stickermanager.h b/src/stickermanager.h index 3aae40f..e952055 100644 --- a/src/stickermanager.h +++ b/src/stickermanager.h @@ -35,6 +35,8 @@ public: Q_INVOKABLE QVariantList getRecentStickers(); Q_INVOKABLE QVariantList getInstalledStickerSets(); + Q_INVOKABLE QVariantMap getStickerSet(const QString &stickerSetId); + Q_INVOKABLE bool hasStickerSet(const QString &stickerSetId); Q_INVOKABLE bool needsReload(); Q_INVOKABLE void setNeedsReload(const bool &reloadNeeded); diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index 8f42add..f1b06ff 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -1326,6 +1326,18 @@ void TDLibWrapper::deleteProfilePhoto(const QString &profilePhotoId) this->sendRequest(requestObject); } +void TDLibWrapper::changeStickerSet(const QString &stickerSetId, bool isInstalled) +{ + LOG("Change sticker set" << stickerSetId << isInstalled); + + QVariantMap requestObject; + requestObject.insert(_TYPE, "changeStickerSet"); + requestObject.insert("set_id", stickerSetId); + requestObject.insert("is_installed", isInstalled); + + this->sendRequest(requestObject); +} + void TDLibWrapper::searchEmoji(const QString &queryString) { LOG("Searching emoji" << queryString); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index 207ce56..7cd4664 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -221,6 +221,7 @@ public: Q_INVOKABLE void getUserPrivacySettingRules(UserPrivacySetting setting); Q_INVOKABLE void setProfilePhoto(const QString &filePath); Q_INVOKABLE void deleteProfilePhoto(const QString &profilePhotoId); + Q_INVOKABLE void changeStickerSet(const QString &stickerSetId, bool isInstalled); // Others (candidates for extraction ;)) Q_INVOKABLE void searchEmoji(const QString &queryString);