diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index d0b1d97..5b9e6c7 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -40,6 +40,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \ qml/components/ImagePreview.qml \ qml/components/InReplyToRow.qml \ qml/components/LocationPreview.qml \ + qml/components/PollPreview.qml \ qml/components/StickerPicker.qml \ qml/components/PhotoTextsListItem.qml \ qml/components/WebPagePreview.qml \ @@ -61,6 +62,8 @@ DISTFILES += qml/harbour-fernschreiber.qml \ qml/pages/InitializationPage.qml \ qml/pages/OverviewPage.qml \ qml/pages/AboutPage.qml \ + qml/pages/PollCreationPage.qml \ + qml/pages/PollResultsPage.qml \ qml/pages/SettingsPage.qml \ qml/pages/VideoPage.qml \ rpm/harbour-fernschreiber.changes.in \ diff --git a/qml/components/PollPreview.qml b/qml/components/PollPreview.qml new file mode 100644 index 0000000..fbb3171 --- /dev/null +++ b/qml/components/PollPreview.qml @@ -0,0 +1,293 @@ +/* + Copyright (C) 2020 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.0 +import Sailfish.Silica 1.0 +import QtGraphicalEffects 1.0 + +import "../js/functions.js" as Functions +import "../js/twemoji.js" as Emoji + +Item { + id: pollMessageComponent + + property string chatId + property var message:({}) + property bool isOwnMessage + + property string messageId: message.id + property bool canEdit: message.can_be_edited + property var pollData: message.content.poll + property var chosenPollData:({}) + property var chosenIndexes: [] + property bool hasAnswered: { + return pollData.options.filter(function(option){ + return option.is_chosen + }).length > 0; + } + property bool canAnswer: !hasAnswered && !pollData.is_closed + property bool isQuiz: pollData.type['@type'] === "pollTypeQuiz" + property Item messageItem + height: pollColumn.height + opacity: 0 + Behavior on opacity { FadeAnimation {} } + function handleChoose(index) { + if(!pollData.type.allow_multiple_answers) { + chosenIndexes = [index]; + sendResponse(); + return; + } + var indexes = chosenIndexes; + var found = indexes.indexOf(index); + if(found > -1) { // uncheck + indexes.splice(found, 1); + } else { + indexes.push(index) + } + chosenIndexes = indexes; + } + function resetChosen() { + chosenIndexes = []; + sendResponse(); + } + function sendResponse() { + tdLibWrapper.setPollAnswer(chatId, messageId, chosenIndexes); + } + + Column { + id: pollColumn + width: parent.width + spacing: Theme.paddingSmall + Label { + font.pixelSize: Theme.fontSizeSmall + width: parent.width + visible: text !== "" + text: Emoji.emojify(pollData.question, Theme.fontSizeSmall) + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + color: pollMessageComponent.isOwnMessage ? Theme.highlightColor : Theme.primaryColor + } + + Label { + font.pixelSize: Theme.fontSizeTiny + width: parent.width + visible: text !== "" + text: pollData.is_closed ? qsTr("Final Result:") : (pollData.type.allow_multiple_answers ? qsTr("Multiple Answers are allowed.") : "") + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + color: pollMessageComponent.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor + } + + Item { + visible: !pollMessageComponent.canAnswer + width: parent.width + height: Theme.paddingSmall + } + + Component { + id: canAnswerDelegate + TextSwitch { + id: optionDelegate + width: pollMessageComponent.width + automaticCheck: false + // emojify does not work here :/ + text: modelData.text + checked: pollMessageComponent.chosenIndexes.indexOf(index) > -1 + onClicked: { + pollMessageComponent.handleChoose(index); + } + } + } + Component { + id: resultDelegate + Item { + id: optionDelegate + width: pollMessageComponent.width + height: displayOptionLabel.height + displayOptionStatistics.height + + Rectangle { + id: displayOptionChosenMarker + height: parent.height + width: Theme.horizontalPageMargin/2 + color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) + visible: modelData.is_chosen + x: -width + } + OpacityRampEffect { + sourceItem: displayOptionChosenMarker + direction: OpacityRamp.LeftToRight + } + Column { + id: iconsColumn + width: pollMessageComponent.isQuiz ?Theme.iconSizeSmall + Theme.paddingMedium : Theme.paddingMedium + + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + + Icon { + highlighted: pollMessageComponent.isOwnMessage + property bool isRight: pollMessageComponent.isQuiz && pollData.type.correct_option_id === index + source: "image://theme/icon-s-accept" + visible: isRight + } + } + + Label { + id: displayOptionLabel + text: Emoji.emojify(modelData.text, Theme.fontSizeMedium) + + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + anchors { + left: iconsColumn.right + top: parent.top + right: parent.right + } + color: pollMessageComponent.isOwnMessage ? Theme.highlightColor : Theme.primaryColor + } + Item { + id: displayOptionStatistics + height: optionVoterPercentage.height + optionVoterPercentageBar.height + anchors { + top: displayOptionLabel.bottom + left: iconsColumn.right + right: parent.right + } + + Label { + id: optionVoterPercentage + font.pixelSize: Theme.fontSizeTiny + text: qsTr("%L1\%", "% of votes for option").arg(modelData.vote_percentage) + horizontalAlignment: Text.AlignRight + anchors { + right: parent.right + left: parent.horizontalCenter + leftMargin: Theme.paddingSmall + } + color: pollMessageComponent.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor + } + Rectangle { + id: optionVoterPercentageBar + height: Theme.paddingSmall + width: parent.width + + color: Theme.rgba(pollMessageComponent.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor, 0.3) + radius: height/2 + anchors { + left: parent.left + bottom: parent.bottom + } + + Rectangle { + height: parent.height + color: pollMessageComponent.isOwnMessage ? Theme.highlightColor : Theme.primaryColor + radius: height/2 + width: parent.width * modelData.vote_percentage * 0.01 + } + } + } + } + } + + Repeater { + model: pollData.options + delegate: pollMessageComponent.canAnswer ? canAnswerDelegate : resultDelegate + } + + Row { + layoutDirection: Qt.RightToLeft + width: parent.width + spacing: Theme.paddingMedium + Behavior on height { NumberAnimation {}} + + + Label { + id: totalVoterCount + font.pixelSize: Theme.fontSizeTiny + anchors.verticalCenter: parent.verticalCenter + text: qsTr("%L1 vote(s) total", "number of total votes", pollData.total_voter_count).arg(pollData.total_voter_count) + width: contentWidth + height: contentHeight + horizontalAlignment: Text.AlignRight + color: pollMessageComponent.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor + } + + Row { + spacing: Theme.paddingSmall + width: parent.width - totalVoterCount.width - parent.spacing + IconButton { + visible: !pollData.is_closed && pollMessageComponent.chosenIndexes.length > 0 && pollData.type.allow_multiple_answers && !pollMessageComponent.hasAnswered + opacity: visible ? 1.0 : 0.0 + Behavior on opacity { FadeAnimation {}} + icon.source: "image://theme/icon-m-send" + onClicked: { + pollMessageComponent.sendResponse() + } + } + + + IconButton { + visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0 + icon.source: "image://theme/icon-m-media-artists" + onClicked: { + pageStack.push(Qt.resolvedUrl("../pages/PollResultsPage.qml"), { chatId:chatId, message:pollMessageComponent.message}); + } + Icon { + opacity: 0.8 + source: "image://theme/icon-s-maybe" + anchors { + right: parent.right + top: parent.top + } + } + } + } + } + + } + Component { + id: closePollMenuItemComponent + MenuItem { + text: qsTr("Close Poll") + onClicked: { + tdLibWrapper.stopPoll(pollMessageComponent.chatId, pollMessageComponent.messageId); + } + } + } + Component { + id: resetAnswerMenuItemComponent + MenuItem { + text: qsTr("Reset Answer") + onClicked: { + pollMessageComponent.resetChosen() + } + } + } + + Component.onCompleted: { + opacity = 1; + if(messageItem && messageItem.menu ) { // workaround to add menu entries + if(!pollData.is_closed && pollMessageComponent.canEdit) { + closePollMenuItemComponent.createObject(messageItem.menu._contentColumn); + } + if(!pollData.is_closed && !pollMessageComponent.isQuiz && pollMessageComponent.hasAnswered) { + resetAnswerMenuItemComponent.createObject(messageItem.menu._contentColumn); + } + } + } +} diff --git a/qml/js/functions.js b/qml/js/functions.js index 771d836..b62ffb9 100644 --- a/qml/js/functions.js +++ b/qml/js/functions.js @@ -97,6 +97,18 @@ function getMessageText(message, simple, myself) { if (message.content['@type'] === 'messageChatChangeTitle') { return myself ? qsTr("changed the chat title to %1", "myself").arg(message.content.title) : qsTr("changed the chat title to %1").arg(message.content.title); } + if (message.content['@type'] === 'messagePoll') { + if(message.content.poll.type['@type'] === "pollTypeQuiz") { + if(message.content.poll.is_anonymous) { + return myself ? qsTr("sent an anonymous quiz", "myself") : qsTr("sent an anonymous quiz"); + } + return myself ? qsTr("sent a quiz", "myself") : qsTr("sent a quiz"); + } + if(message.content.poll.is_anonymous) { + return myself ? qsTr("sent an anonymous poll", "myself") : qsTr("sent an anonymous poll"); + } + return myself ? qsTr("sent a poll", "myself") : qsTr("sent a poll"); + } return qsTr("Unsupported message: %1").arg(message.content['@type'].substring(7)); } diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index bc9d48b..ce8ff10 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -220,7 +220,6 @@ Page { tdLibWrapper.openChat(chatInformation.id); break; case PageStatus.Active: - console.log("CHAT opendirectly?", chatPage.isInitialized) if (!chatPage.isInitialized) { chatModel.initialize(chatInformation); chatPage.isInitialized = true; @@ -537,6 +536,7 @@ Page { property bool containsAudio: (( display.content['@type'] === "messageVoiceNote" ) || ( display.content['@type'] === "messageAudio" )); property bool containsDocument: ( display.content['@type'] === "messageDocument" ) property bool containsLocation: ( display.content['@type'] === "messageLocation" || ( display.content['@type'] === "messageVenue" )) + property bool containsPoll: display.content['@type'] === "messagePoll" menu: ContextMenu { MenuItem { @@ -594,6 +594,7 @@ Page { audioPreviewLoader.active = messageListItem.containsAudio; documentPreviewLoader.active = messageListItem.containsDocument; locationPreviewLoader.active = messageListItem.containsLocation; + pollPreviewLoader.active = messageListItem.containsPoll; forwardedInformationLoader.active = messageListItem.isForwarded; } } @@ -921,6 +922,25 @@ Page { } } + Loader { + id: pollPreviewLoader + active: false + asynchronous: true + width: parent.width +// height: messageListItem.containsLocation ? (item ? item.height : (parent.width * 2 / 3)) : 0 + sourceComponent: Component { + id: pollPreviewComponent + PollPreview { + id: messageLocationPreview + width: parent.width + chatId: chatInformation.id + isOwnMessage: messageListItem.isOwnMessage + message: display + messageItem: messageListItem + } + } + } + Timer { id: messageDateUpdater interval: 60000 @@ -1159,6 +1179,17 @@ Page { stickerPickerLoader.active = !stickerPickerLoader.active; } } + IconButton { + visible: !chatPage.isPrivateChat && + (chatGroupInformation.status["@type"] === "chatMemberStatusCreator" + || chatGroupInformation.status["@type"] === "chatMemberStatusAdministrator" + || (chatGroupInformation.status["@type"] === "chatMemberStatusMember" && chatInformation.permissions.can_send_polls)) + icon.source: "image://theme/icon-m-question" + onClicked: { + pageStack.push(Qt.resolvedUrl("../pages/PollCreationPage.qml"), { "chatId" : chatInformation.id, groupName: chatInformation.title}); + attachmentOptionsRow.visible = false; + } + } } Row { diff --git a/qml/pages/ImagePage.qml b/qml/pages/ImagePage.qml index 06edac7..5d99eb3 100644 --- a/qml/pages/ImagePage.qml +++ b/qml/pages/ImagePage.qml @@ -91,11 +91,9 @@ Page { } SilicaFlickable { - id: imageFlickable anchors.fill: parent - clip: true - contentWidth: imagePinchArea.width; - contentHeight: imagePinchArea.height; + flickableDirection: Flickable.VerticalFlick + interactive: !imageOnly PullDownMenu { visible: !imageOnly && imageUrl @@ -107,80 +105,89 @@ Page { } } - transitions: Transition { - NumberAnimation { properties: "contentX, contentY"; easing.type: Easing.Linear } - } - AppNotification { id: imageNotification } - MouseArea { + SilicaFlickable { + id: imageFlickable anchors.fill: parent - visible: singleImage.visible - onClicked: imageOnly = !imageOnly // Toggle "Image only" mode on tap - } + clip: true + contentWidth: imagePinchArea.width + contentHeight: imagePinchArea.height + flickableDirection: Flickable.HorizontalAndVerticalFlick + quickScrollEnabled: false - PinchArea { - id: imagePinchArea - width: Math.max( singleImage.width * singleImage.scale, imageFlickable.width ) - height: Math.max( singleImage.height * singleImage.scale, imageFlickable.height ) + PinchArea { + id: imagePinchArea + width: Math.max( singleImage.width * singleImage.scale, imageFlickable.width ) + height: Math.max( singleImage.height * singleImage.scale, imageFlickable.height ) - enabled: singleImage.visible - pinch { - target: singleImage - minimumScale: 1 - maximumScale: 4 - } + enabled: singleImage.status === Image.Ready + pinch { + target: singleImage + minimumScale: 1 + maximumScale: 4 + } - onPinchUpdated: { - imagePage.centerX = pinch.center.x; - imagePage.centerY = pinch.center.y; - } + onPinchUpdated: { + imagePage.centerX = pinch.center.x + imagePage.centerY = pinch.center.y + imageFlickable.returnToBounds() + } - Image { - id: singleImage - source: imageUrl - width: imagePage.imageWidth * imagePage.sizingFactor - height: imagePage.imageHeight * imagePage.sizingFactor - anchors.centerIn: parent + Image { + id: singleImage + source: imageUrl + width: imagePage.imageWidth * imagePage.sizingFactor + height: imagePage.imageHeight * imagePage.sizingFactor + anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - asynchronous: true + fillMode: Image.PreserveAspectFit + asynchronous: true - visible: status === Image.Ready ? true : false - opacity: status === Image.Ready ? 1 : 0 - Behavior on opacity { NumberAnimation {} } - onScaleChanged: { - var newWidth = singleImage.width * singleImage.scale; - var newHeight = singleImage.height * singleImage.scale; - var oldWidth = singleImage.width * imagePage.previousScale; - var oldHeight = singleImage.height * imagePage.previousScale; - var widthDifference = newWidth - oldWidth; - var heightDifference = newHeight - oldHeight; + visible: opacity > 0 + opacity: status === Image.Ready ? 1 : 0 + Behavior on opacity { FadeAnimation {} } + onScaleChanged: { + var newWidth = singleImage.width * singleImage.scale; + var newHeight = singleImage.height * singleImage.scale; + var oldWidth = singleImage.width * imagePage.previousScale; + var oldHeight = singleImage.height * imagePage.previousScale; + var widthDifference = newWidth - oldWidth; + var heightDifference = newHeight - oldHeight; - if (oldWidth > imageFlickable.width || newWidth > imageFlickable.width) { - var xRatioNew = imagePage.centerX / newWidth; - var xRatioOld = imagePage.centerX / oldHeight; - imageFlickable.contentX = imageFlickable.contentX + ( xRatioNew * widthDifference ); - } - if (oldHeight > imageFlickable.height || newHeight > imageFlickable.height) { - var yRatioNew = imagePage.centerY / newHeight; - var yRatioOld = imagePage.centerY / oldHeight; - imageFlickable.contentY = imageFlickable.contentY + ( yRatioNew * heightDifference ); + if (oldWidth > imageFlickable.width || newWidth > imageFlickable.width) { + var xRatioNew = imagePage.centerX / newWidth; + var xRatioOld = imagePage.centerX / oldHeight; + imageFlickable.contentX = imageFlickable.contentX + ( xRatioNew * widthDifference ); + } + if (oldHeight > imageFlickable.height || newHeight > imageFlickable.height) { + var yRatioNew = imagePage.centerY / newHeight; + var yRatioOld = imagePage.centerY / oldHeight; + imageFlickable.contentY = imageFlickable.contentY + ( yRatioNew * heightDifference ); + } + + imagePage.previousScale = singleImage.scale; + imagePage.oldCenterX = imagePage.centerX; + imagePage.oldCenterY = imagePage.centerY; } + } - imagePage.previousScale = singleImage.scale; - imagePage.oldCenterX = imagePage.centerX; - imagePage.oldCenterY = imagePage.centerY; + MouseArea { + anchors.fill: parent + visible: singleImage.visible + + onClicked: imageOnly = !imageOnly // Toggle "Image only" mode on tap + onDoubleClicked: ; // This introduces a delay before onClicked is invoked } } - } + ScrollDecorator { flickable: imageFlickable } + } } BackgroundImage { visible: singleImage.status !== Image.Ready } - } diff --git a/qml/pages/OverviewPage.qml b/qml/pages/OverviewPage.qml index f3533f5..cda297f 100644 --- a/qml/pages/OverviewPage.qml +++ b/qml/pages/OverviewPage.qml @@ -154,7 +154,6 @@ Page { } onChatReceived: { if(chat["@extra"] === "openDirectly") { - console.log("ON CHAT RECEIVED", JSON.stringify(chat, null, 2)); if (status !== PageStatus.Active) { pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate); } diff --git a/qml/pages/PollCreationPage.qml b/qml/pages/PollCreationPage.qml new file mode 100644 index 0000000..3f630ac --- /dev/null +++ b/qml/pages/PollCreationPage.qml @@ -0,0 +1,351 @@ +/* + Copyright (C) 2020 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 QtMultimedia 5.0 +import "../components" +import "../js/functions.js" as Functions +import "../js/twemoji.js" as Emoji + +Dialog { + id: pollCreationPage + allowedOrientations: Orientation.All + property string groupName + // poll request data start + property string chatId + property alias pollQuestion: questionTextArea.text + property ListModel options: ListModel { + ListElement { + text: "" + } + } + property alias anonymous: anonymousSwitch.checked + property int correctOption: -1 + property alias quiz: quizSwitch.checked + property alias multiple: multipleSwitch.checked + property string replyToMessageId: "0" + // poll request data end + + canAccept: validationErrors.length === 0 + onDone: { + } + onAcceptPendingChanged: { + if(acceptPending) { + + validate(); + + if(validationErrors.length > 0) { + validationErrorsVisible = true; + contentFlickable.scrollToTop(); + } + } + } + + property var validationErrorsVisible: false + property var validationErrors:[""] + + function validate() { + var errors = []; + if(pollQuestion.length === 0) { + errors.push(qsTr("You have to enter a question.")); + } else if(pollQuestion.length > 255) { + errors.push(qsTr("The question has to be shorter than 256 characters.")); + } + + if(options.count < 2 || options.count > 10) { + errors.push(qsTr("A poll requires 2-10 answers.")); + } else { + for(var i = 0; i < options.count; i += 1) { + var len = options.get(i).text.length + if(len < 1 || len > 100) { + errors.push(qsTr("All answers have to contain 1-100 characters.")); + break; + } + } + } + if(quiz && (correctOption < 0 || correctOption > options.count - 1)) { + errors.push(qsTr("To send a quiz, you have to specify the right answer.")); + } + if(errors.length === 0) { + validationErrorsVisible = false; + } + + validationErrors = errors; + } + function createNewOption() { + if(options.count < 10) { + pollCreationPage.options.append({text:""}); + focusLastOptionTimer.start(); + } + } + + signal focusOption(int focusIndex) + DialogHeader { + id: header + dialog: pollCreationPage + title: qsTr("Create a Poll", "Dialog Header") + } + Label { + id: subHeaderLabel + anchors { + verticalCenter: header.bottom + left: parent.left + right: parent.right + leftMargin: Theme.horizontalPageMargin + rightMargin: Theme.horizontalPageMargin + } + + color: Theme.secondaryHighlightColor + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + text: qsTr("in %1", "After dialog header… Create a Poll in [group name]").arg(Emoji.emojify(pollCreationPage.groupName, font.pixelSize)) + font.pixelSize: Theme.fontSizeSmall + } + + SilicaFlickable { + id: contentFlickable + clip: true + anchors { + top: subHeaderLabel.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + + contentHeight: contentColumn.height + + Column { + id: contentColumn + width: parent.width + topPadding: Theme.paddingLarge + bottomPadding: Theme.paddingLarge + + Item { + id: errorItem + width: parent.width - Theme.horizontalPageMargin * 2 + x: Theme.horizontalPageMargin + property bool shown: pollCreationPage.validationErrorsVisible && pollCreationPage.validationErrors.length > 0 + property int visibleHeight: errorContentColumn.height + height: pollCreationPage.validationErrorsVisible ? visibleHeight : 0 + clip: true; + opacity: pollCreationPage.validationErrorsVisible ? 1.0 : 0.0 + Behavior on opacity { FadeAnimation {} } + Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.InOutQuad}} + Rectangle { + color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) + anchors.fill: parent + radius: Theme.paddingLarge + IconButton { + icon.source: "image://theme/icon-m-close" + anchors { + right: parent.right + top: parent.top + } + onClicked: { + pollCreationPage.validationErrorsVisible = false + } + } + } + + + Column { + id: errorContentColumn + width: parent.width - Theme.paddingLarge * 2 - Theme.itemSizeSmall + spacing: Theme.paddingMedium + padding: Theme.paddingLarge + Repeater { + model: pollCreationPage.validationErrors + delegate: Label { + font.pixelSize: Theme.fontSizeSmall + color: Theme.highlightColor + width: errorContentColumn.width + text: modelData + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + leftPadding: Theme.iconSizeSmall + Theme.paddingSmall + Icon { + highlighted: true + source: "image://theme/icon-s-high-importance" + y: Theme.paddingSmall / 2 + } + } + } + + } + } + + TextArea { + id: questionTextArea + width: parent.width + placeholderText: qsTr("Enter your question here") + property int charactersLeft: 255 - text.length + color: charactersLeft < 0 ? Theme.errorColor : Theme.highlightColor + label: qsTr("Question (%n1 characters left)", "", charactersLeft).arg(charactersLeft) + wrapMode: TextEdit.Wrap + onFocusChanged: { + validate(); + } + } + SectionHeader { + topPadding: 0 + text: qsTr("Answers", "Section header") + } + + Column { + id: optionsListView + width: parent.width - Theme.horizontalPageMargin * 2 + x: Theme.horizontalPageMargin + add: Transition { + NumberAnimation { properties: "opacity"; from: 0; to: 1; duration: 200; easing.type: Easing.InOutCubic } + NumberAnimation { properties: "height"; from: 0; to: ViewTransition.item.childrenRect.height; duration: 200; easing.type: Easing.InOutCubic } + } + move: Transition { + NumberAnimation { properties: "y"; duration: 200; easing.type: Easing.InOutCubic } + } + Behavior on height { NumberAnimation {duration: 200; easing.type: Easing.InOutCubic}} + Repeater { + model: pollCreationPage.options + delegate: Row { + width: parent.width + BackgroundItem { + id: answerCorrectBackgroundItem + width: enabled ? Theme.itemSizeSmall : 0 + contentItem.radius: height/2 + height: Theme.itemSizeSmall + property bool checked: pollCreationPage.correctOption === index + enabled: pollCreationPage.quiz + opacity: enabled ? (checked ? 1.0 : 0.5) : 0.0 + Behavior on opacity { FadeAnimation {} } + Behavior on width { NumberAnimation {duration: 500; easing.type: Easing.InOutQuad}} + Icon { + source: "image://theme/icon-m-accept" + anchors.centerIn: parent + } + onClicked: { + pollCreationPage.correctOption = index + validate(); + } + } + + TextField { + id: answerTextArea + textMargin: Theme.paddingSmall + width: answerCorrectBackgroundItem.enabled ? parent.width - Theme.itemSizeSmall * 2 : parent.width - Theme.itemSizeSmall + Behavior on width { NumberAnimation {duration: 500; easing.type: Easing.InOutCubic}} + text: model.text + onTextChanged: { + pollCreationPage.options.setProperty(index, "text", text) + pollCreationPage.validate() + } + placeholderText: qsTr("Enter an answer here") + property int charactersLeft: 100 - text.length + color: charactersLeft < 0 ? Theme.errorColor : Theme.highlightColor + label: qsTr("Answer (%n1 characters left)", "", charactersLeft).arg(charactersLeft) + property bool hasNextOption: index < pollCreationPage.options.count - 1 + EnterKey.onClicked: { + if(hasNextOption) { + pollCreationPage.focusOption(index + 1); + } else if(pollCreationPage.options.count < 10) { + pollCreationPage.createNewOption(); + } else { + focus = false; + } + } + EnterKey.iconSource: hasNextOption ? "image://theme/icon-m-enter-next" : (pollCreationPage.options.count < 10 ? "image://theme/icon-m-add" : "image://theme/icon-m-enter-close") + + onFocusChanged: { + validate(); + } + } + Connections { + target: pollCreationPage + onFocusOption: { + if(focusIndex === index) answerTextArea.forceActiveFocus() + } + } + + IconButton { + icon.source: "image://theme/icon-m-remove" + onClicked: { + pollCreationPage.options.remove(index) + + validate(); + } + } + } + } + } + ButtonLayout { + Button { + enabled: pollCreationPage.options.count < 10 + text: qsTr("Add an answer") + onClicked: { + pollCreationPage.createNewOption(); + validate(); + } + } + } + Timer { + id: focusLastOptionTimer + interval: 20 + onTriggered: { + pollCreationPage.focusOption(pollCreationPage.options.count - 1); + } + } + + SectionHeader { + text: qsTr("Poll Options", "Section header") + } + TextSwitch { + id: anonymousSwitch + text: qsTr("Anonymous answers") + } + TextSwitch { + id: multipleSwitch + text: qsTr("Multiple answers allowed") + onCheckedChanged: { + if(checked) { + quizSwitch.checked = false + } + } + } + TextSwitch { + id: quizSwitch + text: qsTr("Quiz Mode") + onCheckedChanged: { + if(checked) { + multipleSwitch.checked = false + } + validate(); + } + description: qsTr("Quizzes have one correct answer. Participants can't revoke their responses.") + } + } + } + + onAccepted: { + var optionsArr = []; + for(var i = 0; i < options.count; i += 1) { + optionsArr.push(options.get(i).text); + } + + tdLibWrapper.sendPollMessage(chatId, pollQuestion, optionsArr, anonymous, quiz ? correctOption : -1, multiple, "0"); + + } + + +} diff --git a/qml/pages/PollResultsPage.qml b/qml/pages/PollResultsPage.qml new file mode 100644 index 0000000..764754c --- /dev/null +++ b/qml/pages/PollResultsPage.qml @@ -0,0 +1,328 @@ +/* + Copyright (C) 2020 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 QtMultimedia 5.0 +import "../components" +import "../js/functions.js" as Functions +import "../js/twemoji.js" as Emoji + +Page { + id: pollResultsPage + allowedOrientations: Orientation.All + property string chatId; + property var message: ({}); + + property string messageId: message.id; + + property var pollData: message.content.poll + + property var userInformation: tdLibWrapper.getUserInformation(message.sender_user_id) + + property bool isQuiz: pollData.type['@type'] === "pollTypeQuiz" + + property bool hasAnswered: { + return pollData.options.filter(function(option){ + return option.is_chosen + }).length > 0; + } + + property bool canAnswer: !hasAnswered && !pollData.is_closed + onCanAnswerChanged: { + if(canAnswer) { // vote removed from another client? + pageStack.pop() + } + } + + SilicaFlickable { + anchors.fill: parent + contentHeight: pageHeader.height + contentColumn.height + + PageHeader { + id: pageHeader + title: pollResultsPage.isQuiz ? qsTr("Quiz Results") : qsTr("Poll Results") + description: qsTr("%L1 vote(s) total", "number of total votes", pollData.total_voter_count).arg(pollData.total_voter_count) + leftMargin: headerPictureThumbnail.width + Theme.paddingLarge + Theme.horizontalPageMargin + ProfileThumbnail { + id: headerPictureThumbnail + photoData: (typeof pollResultsPage.userInformation.profile_photo !== "undefined") ? pollResultsPage.userInformation.profile_photo.small : "" + replacementStringHint: Emoji.emojify(Functions.getUserName(pollResultsPage.userInformation), font.pixelSize) + width: visible ? Theme.itemSizeSmall : 0 + height: visible ? Theme.itemSizeSmall : 0 + anchors { + verticalCenter: pageHeader.verticalCenter + left: parent.left + leftMargin: Theme.horizontalPageMargin + } + } + } + Column { + id: contentColumn + anchors { + left: parent.left + leftMargin: Theme.horizontalPageMargin + right: parent.right + rightMargin: Theme.horizontalPageMargin + top: pageHeader.bottom + } + SectionHeader { + x: 0 + text: qsTr("Question", "section header") + } +// Label { +// width: parent.width +// font.pixelSize: Theme.fontSizeTiny +// wrapMode: Text.Wrap +// color: Theme.secondaryHighlightColor +// text: JSON.stringify(pollData, null, 2) +// } +// Label { +// width: parent.width +// font.pixelSize: Theme.fontSizeTiny +// wrapMode: Text.Wrap +// color: Theme.secondaryHighlightColor +// text: JSON.stringify(userInformation, null, 2) +// } + Label { + width: parent.width + wrapMode: Text.Wrap + color: Theme.secondaryHighlightColor + text: Emoji.emojify(pollData.question, font.pixelSize) + } + + Column { + id: resultsColumn + width: parent.width + topPadding: Theme.paddingLarge + bottomPadding: Theme.paddingLarge + + SectionHeader { + x: 0 + text: qsTr("Results", "section header") + } + Repeater { + model: pollData.options + delegate: Item { + id: optionDelegate + width: resultsColumn.width + height: displayOptionLabel.height + displayOptionStatistics.height + displayOptionUsers.height + Theme.paddingLarge + property ListModel users: ListModel {} + property string usersResponseIdentifierString: "pollResults."+pollResultsPage.chatId+"."+pollResultsPage.messageId+"."+index + function loadUsers() { + if(users.count < modelData.voter_count) { + tdLibWrapper.getPollVoters(pollResultsPage.chatId, pollResultsPage.messageId, index, 50, users.length, usersResponseIdentifierString) + } + } + Component.onCompleted: { +// loadUsers() + loadUsersTimer.start() + } + Timer { + id: loadUsersTimer + interval: index * 80 + onTriggered: { + optionDelegate.loadUsers(); + } + } + + Connections { + target: tdLibWrapper + onUsersReceived: { + if(extra === optionDelegate.usersResponseIdentifierString) { + for(var i = 0; i < userIds.length; i += 1) { + optionDelegate.users.append({id: userIds[i], user:tdLibWrapper.getUserInformation(userIds[i])}); + console.log("APPEND USER", JSON.stringify({id: userIds[i], user:tdLibWrapper.getUserInformation(userIds[i])})); + } + loadUsersTimer.start(); + } + } + } + Rectangle { + id: displayOptionChosenMarker + height: parent.height + width: Theme.horizontalPageMargin/2 + color: Theme.rgba(Theme.highlightBackgroundColor, Theme.highlightBackgroundOpacity) + visible: modelData.is_chosen + x: -width + } + OpacityRampEffect { + sourceItem: displayOptionChosenMarker + direction: OpacityRamp.LeftToRight + } + Column { + id: iconsColumn + width: pollResultsPage.isQuiz ?Theme.iconSizeSmall + Theme.paddingMedium : Theme.paddingMedium + height: displayOptionLabel.height + displayOptionStatistics.height + anchors { + left: parent.left +// verticalCenter: parent.verticalCenter + } + + Icon { + highlighted: true + property bool isRight: pollResultsPage.isQuiz && pollData.type.correct_option_id === index + source: "image://theme/icon-s-accept" + visible: isRight + anchors.verticalCenter: parent.verticalCenter + } + } + + Label { + id: displayOptionLabel + text: Emoji.emojify(modelData.text, Theme.fontSizeMedium) + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + anchors { + left: iconsColumn.right + top: parent.top + right: parent.right + } + color: Theme.highlightColor + } + Item { + id: displayOptionStatistics + height: optionVoterPercentage.height + optionVoterPercentageBar.height + anchors { + top: displayOptionLabel.bottom + left: iconsColumn.right + right: parent.right + } + + Label { + id: optionVoterCount + font.pixelSize: Theme.fontSizeTiny + text: modelData.is_chosen ? qsTr("%L1 vote(s) including yours", "number of votes for option", modelData.voter_count).arg(modelData.voter_count) : qsTr("%L1 vote(s)", "number of votes for option", modelData.voter_count).arg(modelData.voter_count) + anchors { + left: parent.left + right: parent.horizontalCenter + rightMargin: Theme.paddingSmall + } + color: Theme.secondaryHighlightColor + } + Label { + id: optionVoterPercentage + font.pixelSize: Theme.fontSizeTiny + text: qsTr("%L1\%", "% of votes for option").arg(modelData.vote_percentage) + horizontalAlignment: Text.AlignRight + anchors { + right: parent.right + left: parent.horizontalCenter + leftMargin: Theme.paddingSmall + } + color: Theme.secondaryHighlightColor + } + Rectangle { + id: optionVoterPercentageBar + height: Theme.paddingSmall + width: parent.width + + color: Theme.rgba(Theme.secondaryHighlightColor, 0.3) + radius: height/2 + anchors { + left: parent.left + bottom: parent.bottom + } + + Rectangle { + height: parent.height + color: Theme.highlightColor + radius: height/2 + width: parent.width * modelData.vote_percentage * 0.01 + } + } + } + + + // users voted for this: + Flow { + id: displayOptionUsers + anchors.top: displayOptionStatistics.bottom + width: parent.width + visible: optionDelegate.users.count > 0 + topPadding: Theme.paddingLarge + spacing: Theme.paddingMedium + leftPadding: iconsColumn.width + property int itemHeight: Theme.itemSizeExtraSmall / 2 + Item { + height: displayOptionUsers.itemHeight + width: chosenByUserText.width + Label { + id: chosenByUserText + font.pixelSize: Theme.fontSizeTiny + text: qsTr("Chosen by:", "This answer has been chosen by the following users") + width: contentWidth + anchors.centerIn: parent + color: Theme.secondaryHighlightColor + } + } + Repeater { + model: optionDelegate.users + delegate: + Item { + id: chosenByUserItem + width: chosenByUserPictureThumbnail.width + chosenByUserLabel.width + Theme.paddingSmall + height: displayOptionUsers.itemHeight + + ProfileThumbnail { + id: chosenByUserPictureThumbnail + photoData: (typeof model.user.profile_photo !== "undefined") ? model.user.profile_photo.small : "" + replacementStringHint: chosenByUserLabel.text + width: visible ? parent.height : 0 + height: width + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + } + + Label { + id: chosenByUserLabel + font.pixelSize: Theme.fontSizeSmall + text: Emoji.emojify(Functions.getUserName(model.user), font.pixelSize) + width: contentWidth + height: contentHeight + color: Theme.highlightColor + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + } + } + + + } + } + + } + } + + } + + } + } + + Connections { + target: tdLibWrapper + onMessageContentUpdated: { + if(chatId === pollResultsPage.chatId && messageId === pollResultsPage.messageId) { + pollResultsPage.pollData = newContent.poll; + } + } + } + +} diff --git a/src/fernschreiberutils.cpp b/src/fernschreiberutils.cpp index b52122e..99c05e6 100644 --- a/src/fernschreiberutils.cpp +++ b/src/fernschreiberutils.cpp @@ -54,5 +54,11 @@ QString FernschreiberUtils::getMessageShortText(const QVariantMap &messageConten if (contentType == "messageChatChangeTitle") { return myself ? tr("changed the chat title", "myself") : tr("changed the chat title"); } + if (contentType == "messagePoll") { + if(messageContent.value("poll").toMap().value("type").toMap().value("@type").toString() == "pollTypeQuiz") { + return myself ? tr("sent a quiz", "myself") : tr("sent a quiz"); + } + return myself ? tr("sent a poll", "myself") : tr("sent a poll"); + } return tr("Unsupported message: %1").arg(contentType.mid(7)); } diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp index cb80fe1..383108a 100644 --- a/src/tdlibreceiver.cpp +++ b/src/tdlibreceiver.cpp @@ -116,9 +116,10 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren handlers.insert("userProfilePhotos", &TDLibReceiver::processUserProfilePhotos); handlers.insert("updateChatPermissions", &TDLibReceiver::processUpdateChatPermissions); handlers.insert("updateChatTitle", &TDLibReceiver::processUpdateChatTitle); + handlers.insert("users", &TDLibReceiver::processUsers); } -void TDLibReceiver::setActive(const bool &active) +void TDLibReceiver::setActive(bool active) { if (active) { LOG("Activating receiver loop..."); @@ -494,3 +495,9 @@ void TDLibReceiver::processUpdateChatTitle(const QVariantMap &receivedInformatio LOG("Received UpdateChatTitle"); emit chatTitleUpdated(receivedInformation.value("chat_id").toString(), receivedInformation.value("title").toString()); } + +void TDLibReceiver::processUsers(const QVariantMap &receivedInformation) +{ + LOG("Received Users"); + emit usersReceived(receivedInformation.value(EXTRA).toString(), receivedInformation.value("user_ids").toList(), receivedInformation.value("total_count").toInt()); +} diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h index a8eb27a..36f4fc5 100644 --- a/src/tdlibreceiver.h +++ b/src/tdlibreceiver.h @@ -33,7 +33,7 @@ class TDLibReceiver : public QThread } public: explicit TDLibReceiver(void *tdLibClient, QObject *parent = nullptr); - void setActive(const bool &active); + void setActive(bool active); signals: void versionDetected(const QString &version); @@ -48,12 +48,12 @@ signals: void unreadChatCountUpdated(const QVariantMap &chatCountInformation); void chatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage); void chatOrderUpdated(const QString &chatId, const QString &order); - void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); + void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void basicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); - void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void messagesReceived(const QVariantList &messages, const int &totalCount); + void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount); + void messagesReceived(const QVariantList &messages, int totalCount); void newMessageReceived(const QString &chatId, const QVariantMap &message); void messageInformation(const QString &messageId, const QVariantMap &message); void messageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message); @@ -70,16 +70,17 @@ signals: void installedStickerSetsUpdated(const QVariantList &stickerSetIds); void stickerSets(const QVariantList &stickerSets); void stickerSet(const QVariantMap &stickerSet); - void chatMembers(const QString &extra, const QVariantList &members, const int &totalMembers); + void chatMembers(const QString &extra, const QVariantList &members, int totalMembers); void userFullInfo(const QVariantMap &userFullInfo); void userFullInfoUpdated(const QString &userId,const QVariantMap &userFullInfo); void basicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); void basicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); void supergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); void supergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); - void userProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos); + void userProfilePhotos(const QString &extra, const QVariantList &photos, int totalPhotos); void chatPermissionsUpdated(const QString &chatId, const QVariantMap &chatPermissions); void chatTitleUpdated(const QString &chatId, const QString &title); + void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers); private: typedef void (TDLibReceiver::*Handler)(const QVariantMap &); @@ -134,6 +135,7 @@ private: void processUserProfilePhotos(const QVariantMap &receivedInformation); void processUpdateChatPermissions(const QVariantMap &receivedInformation); void processUpdateChatTitle(const QVariantMap &receivedInformation); + void processUsers(const QVariantMap &receivedInformation); }; #endif // TDLIBRECEIVER_H diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index c1d6ffc..6ecdb62 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -70,42 +70,41 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) connect(this->tdLibReceiver, SIGNAL(newChatDiscovered(QVariantMap)), this, SLOT(handleNewChatDiscovered(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(unreadMessageCountUpdated(QVariantMap)), this, SLOT(handleUnreadMessageCountUpdated(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(unreadChatCountUpdated(QVariantMap)), this, SLOT(handleUnreadChatCountUpdated(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chatLastMessageUpdated(QString, QString, QVariantMap)), this, SLOT(handleChatLastMessageUpdated(QString, QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SLOT(handleChatOrderUpdated(QString, QString))); - connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int))); - connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString))); + connect(this->tdLibReceiver, SIGNAL(chatLastMessageUpdated(QString, QString, QVariantMap)), this, SIGNAL(chatLastMessageUpdated(QString, QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chatOrderUpdated(QString, QString)), this, SIGNAL(chatOrderUpdated(QString, QString))); + connect(this->tdLibReceiver, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SIGNAL(chatReadInboxUpdated(QString, QString, int))); + connect(this->tdLibReceiver, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SIGNAL(chatReadOutboxUpdated(QString, QString))); connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleBasicGroupUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SLOT(handleChatOnlineMemberCountUpdated(QString, int))); - connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int))); - connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SLOT(handleMessageInformation(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SLOT(handleUpdateActiveNotifications(QVariantList))); - connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SLOT(handleUpdateNotificationGroup(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(notificationUpdated(QVariantMap)), this, SLOT(handleUpdateNotification(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SLOT(handleChatNotificationSettingsUpdated(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SLOT(handleMessageContentUpdated(QString, QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(messagesDeleted(QString, QVariantList)), this, SLOT(handleMessagesDeleted(QString, QVariantList))); - connect(this->tdLibReceiver, SIGNAL(chats(QVariantMap)), this, SLOT(handleChats(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chat(QVariantMap)), this, SLOT(handleChat(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(recentStickersUpdated(QVariantList)), this, SLOT(handleRecentStickersUpdated(QVariantList))); - connect(this->tdLibReceiver, SIGNAL(stickers(QVariantList)), this, SLOT(handleStickers(QVariantList))); - connect(this->tdLibReceiver, SIGNAL(installedStickerSetsUpdated(QVariantList)), this, SLOT(handleInstalledStickerSetsUpdated(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SIGNAL(chatOnlineMemberCountUpdated(QString, int))); + connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SIGNAL(messagesReceived(QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SIGNAL(newMessageReceived(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SIGNAL(receivedMessage(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(activeNotificationsUpdated(QVariantList)), this, SIGNAL(activeNotificationsUpdated(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(notificationGroupUpdated(QVariantMap)), this, SIGNAL(notificationGroupUpdated(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(notificationUpdated(QVariantMap)), this, SIGNAL(notificationUpdated(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap)), this, SIGNAL(chatNotificationSettingsUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SIGNAL(messageContentUpdated(QString, QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(messagesDeleted(QString, QVariantList)), this, SIGNAL(messagesDeleted(QString, QVariantList))); + connect(this->tdLibReceiver, SIGNAL(chats(QVariantMap)), this, SIGNAL(chatsReceived(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chat(QVariantMap)), this, SIGNAL(chatReceived(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(recentStickersUpdated(QVariantList)), this, SIGNAL(recentStickersUpdated(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(stickers(QVariantList)), this, SIGNAL(stickersReceived(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(installedStickerSetsUpdated(QVariantList)), this, SIGNAL(installedStickerSetsUpdated(QVariantList))); connect(this->tdLibReceiver, SIGNAL(stickerSets(QVariantList)), this, SLOT(handleStickerSets(QVariantList))); - connect(this->tdLibReceiver, SIGNAL(stickerSet(QVariantMap)), this, SLOT(handleStickerSet(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(chatMembers(QString, QVariantList, int)), this, SLOT(handleChatMembers(QString, QVariantList, int))); - connect(this->tdLibReceiver, SIGNAL(userFullInfo(QVariantMap)), this, SLOT(handleUserFullInfo(QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(userFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleUserFullInfoUpdated(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfo(QString, QVariantMap)), this, SLOT(handleBasicGroupFullInfo(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleBasicGroupFullInfoUpdated(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(supergroupFullInfo(QString, QVariantMap)), this, SLOT(handleSupergroupFullInfo(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(supergroupFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleSupergroupFullInfoUpdated(QString, QVariantMap))); - connect(this->tdLibReceiver, SIGNAL(userProfilePhotos(QString, QVariantList, int)), this, SLOT(handleUserProfilePhotos(QString, QVariantList, int))); - connect(this->tdLibReceiver, SIGNAL(userProfilePhotos(QString, QVariantList, int)), this, SLOT(handleUserProfilePhotos(QString, QVariantList, int))); - connect(this->tdLibReceiver, SIGNAL(chatPermissionsUpdated(QString, QVariantMap)), this, SLOT(handleChatPermissionsUpdated(QString, QVariantMap))); - - connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString))); + connect(this->tdLibReceiver, SIGNAL(stickerSet(QVariantMap)), this, SIGNAL(stickerSetReceived(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chatMembers(QString, QVariantList, int)), this, SIGNAL(chatMembersReceived(QString, QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(userFullInfo(QVariantMap)), this, SIGNAL(userFullInfoReceived(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(userFullInfoUpdated(QString, QVariantMap)), this, SIGNAL(userFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfo(QString, QVariantMap)), this, SIGNAL(basicGroupFullInfoReceived(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfoUpdated(QString, QVariantMap)), this, SIGNAL(basicGroupFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(supergroupFullInfo(QString, QVariantMap)), this, SIGNAL(supergroupFullInfoReceived(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(supergroupFullInfoUpdated(QString, QVariantMap)), this, SIGNAL(supergroupFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(userProfilePhotos(QString, QVariantList, int)), this, SIGNAL(userProfilePhotosReceived(QString, QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(chatPermissionsUpdated(QString, QVariantMap)), this, SIGNAL(chatPermissionsUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SIGNAL(chatTitleUpdated(QString, QString))); + connect(this->tdLibReceiver, SIGNAL(usersReceived(QString, QVariantList, int)), this, SIGNAL(usersReceived(QString, QVariantList, int))); connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList))); @@ -245,7 +244,7 @@ void TDLibWrapper::leaveChat(const QString &chatId) this->sendRequest(requestObject); } -void TDLibWrapper::getChatHistory(const QString &chatId, const qlonglong &fromMessageId, const int &offset, const int &limit, const bool &onlyLocal) +void TDLibWrapper::getChatHistory(const QString &chatId, const qlonglong &fromMessageId, int offset, int limit, bool onlyLocal) { LOG("Retrieving chat history" << chatId << fromMessageId << offset << limit << onlyLocal); QVariantMap requestObject; @@ -258,7 +257,7 @@ void TDLibWrapper::getChatHistory(const QString &chatId, const qlonglong &fromMe this->sendRequest(requestObject); } -void TDLibWrapper::viewMessage(const QString &chatId, const QString &messageId, const bool &force = false) +void TDLibWrapper::viewMessage(const QString &chatId, const QString &messageId, bool force) { LOG("Mark message as viewed" << chatId << messageId); QVariantMap requestObject; @@ -384,6 +383,36 @@ void TDLibWrapper::sendStickerMessage(const QString &chatId, const QString &file this->sendRequest(requestObject); } +void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, const bool &anonymous, const int &correctOption, const bool &multiple, const QString &replyToMessageId) +{ + LOG("Sending poll message" << chatId << question << replyToMessageId); + QVariantMap requestObject; + requestObject.insert(_TYPE, "sendMessage"); + requestObject.insert("chat_id", chatId); + if (replyToMessageId != "0") { + requestObject.insert("reply_to_message_id", replyToMessageId); + } + QVariantMap inputMessageContent; + inputMessageContent.insert(_TYPE, "inputMessagePoll"); + + QVariantMap pollType; + if(correctOption > -1) { + pollType.insert(_TYPE, "pollTypeQuiz"); + pollType.insert("correct_option_id", correctOption); + } else { + pollType.insert(_TYPE, "pollTypeRegular"); + pollType.insert("allow_multiple_answers", multiple); + } + + inputMessageContent.insert("type", pollType); + inputMessageContent.insert("question", question); + inputMessageContent.insert("options", options); + inputMessageContent.insert("is_anonymous", anonymous); + + requestObject.insert("input_message_content", inputMessageContent); + this->sendRequest(requestObject); +} + void TDLibWrapper::getMessage(const QString &chatId, const QString &messageId) { LOG("Retrieving message" << chatId << messageId); @@ -394,7 +423,7 @@ void TDLibWrapper::getMessage(const QString &chatId, const QString &messageId) this->sendRequest(requestObject); } -void TDLibWrapper::setOptionInteger(const QString &optionName, const int &optionValue) +void TDLibWrapper::setOptionInteger(const QString &optionName, int optionValue) { LOG("Setting integer option" << optionName << optionValue); QVariantMap requestObject; @@ -444,7 +473,7 @@ void TDLibWrapper::deleteMessages(const QString &chatId, const QVariantList mess this->sendRequest(requestObject); } -void TDLibWrapper::getMapThumbnailFile(const QString &chatId, const double &latitude, const double &longitude, const int &width, const int &height) +void TDLibWrapper::getMapThumbnailFile(const QString &chatId, double latitude, double longitude, int width, int height) { LOG("Getting Map Thumbnail File" << chatId); QVariantMap location; @@ -491,7 +520,7 @@ void TDLibWrapper::getStickerSet(const QString &setId) requestObject.insert("set_id", setId); this->sendRequest(requestObject); } -void TDLibWrapper::getSupergroupMembers(const QString &groupId, const int &limit = 200, const int &offset = 0) +void TDLibWrapper::getSupergroupMembers(const QString &groupId, int limit, int offset) { LOG("Retrieving SupergroupMembers"); QVariantMap requestObject; @@ -503,7 +532,7 @@ void TDLibWrapper::getSupergroupMembers(const QString &groupId, const int &limit this->sendRequest(requestObject); } -void TDLibWrapper::getGroupFullInfo(const QString &groupId, const bool &isSuperGroup) +void TDLibWrapper::getGroupFullInfo(const QString &groupId, bool isSuperGroup) { LOG("Retrieving GroupFullInfo"); QVariantMap requestObject; @@ -538,7 +567,7 @@ void TDLibWrapper::createPrivateChat(const QString &userId) this->sendRequest(requestObject); } -void TDLibWrapper::getGroupsInCommon(const QString &userId, const int &limit, const int &offset) +void TDLibWrapper::getGroupsInCommon(const QString &userId, int limit, int offset) { LOG("Retrieving Groups in Common"); QVariantMap requestObject; @@ -550,7 +579,7 @@ void TDLibWrapper::getGroupsInCommon(const QString &userId, const int &limit, co this->sendRequest(requestObject); } -void TDLibWrapper::getUserProfilePhotos(const QString &userId, const int &limit, const int &offset) +void TDLibWrapper::getUserProfilePhotos(const QString &userId, int limit, int offset) { LOG("Retrieving User Profile Photos"); QVariantMap requestObject; @@ -573,7 +602,7 @@ void TDLibWrapper::setChatPermissions(const QString &chatId, const QVariantMap & this->sendRequest(requestObject); } -void TDLibWrapper::setChatSlowModeDelay(const QString &chatId, const int &delay) +void TDLibWrapper::setChatSlowModeDelay(const QString &chatId, int delay) { LOG("Setting Chat Slow Mode Delay"); @@ -613,7 +642,7 @@ void TDLibWrapper::setBio(const QString &bio) this->sendRequest(requestObject); } -void TDLibWrapper::toggleSupergroupIsAllHistoryAvailable(const QString &groupId, const bool &isAllHistoryAvailable) +void TDLibWrapper::toggleSupergroupIsAllHistoryAvailable(const QString &groupId, bool isAllHistoryAvailable) { LOG("Toggling SupergroupIsAllHistoryAvailable"); QVariantMap requestObject; @@ -623,6 +652,41 @@ void TDLibWrapper::toggleSupergroupIsAllHistoryAvailable(const QString &groupId, this->sendRequest(requestObject); } +void TDLibWrapper::setPollAnswer(const QString &chatId, const qlonglong &messageId, QVariantList optionIds) +{ + LOG("Setting Poll Answer"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setPollAnswer"); + requestObject.insert("chat_id", chatId); + requestObject.insert("message_id", messageId); + requestObject.insert("option_ids", optionIds); + this->sendRequest(requestObject); +} + +void TDLibWrapper::stopPoll(const QString &chatId, const qlonglong &messageId) +{ + LOG("Stopping Poll"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "stopPoll"); + requestObject.insert("chat_id", chatId); + requestObject.insert("message_id", messageId); + this->sendRequest(requestObject); +} + +void TDLibWrapper::getPollVoters(const QString &chatId, const qlonglong &messageId, const int &optionId, const int &limit, const int &offset, const QString &extra) +{ + LOG("Retrieving Poll Voters"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "getPollVoters"); + requestObject.insert(_EXTRA, extra); + requestObject.insert("chat_id", chatId); + requestObject.insert("message_id", messageId); + requestObject.insert("option_id", optionId); + requestObject.insert("offset", offset); + requestObject.insert("limit", limit); //max 50 + this->sendRequest(requestObject); +} + void TDLibWrapper::searchEmoji(const QString &queryString) { LOG("Searching emoji" << queryString); @@ -717,7 +781,7 @@ void TDLibWrapper::openFileOnDevice(const QString &filePath) } } -void TDLibWrapper::controlScreenSaver(const bool &enabled) +void TDLibWrapper::controlScreenSaver(bool enabled) { LOG("Controlling device screen saver" << enabled); QDBusConnection dbusConnection = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "system"); @@ -878,26 +942,6 @@ void TDLibWrapper::handleUnreadChatCountUpdated(const QVariantMap &chatCountInfo } } -void TDLibWrapper::handleChatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage) -{ - emit chatLastMessageUpdated(chatId, order, lastMessage); -} - -void TDLibWrapper::handleChatOrderUpdated(const QString &chatId, const QString &order) -{ - emit chatOrderUpdated(chatId, order); -} - -void TDLibWrapper::handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount) -{ - emit chatReadInboxUpdated(chatId, lastReadInboxMessageId, unreadCount); -} - -void TDLibWrapper::handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId) -{ - emit chatReadOutboxUpdated(chatId, lastReadOutboxMessageId); -} - void TDLibWrapper::handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation) { emit basicGroupUpdated(updateGroup(groupId, groupInformation, &basicGroups)->groupId); @@ -908,86 +952,6 @@ void TDLibWrapper::handleSuperGroupUpdated(qlonglong groupId, const QVariantMap emit superGroupUpdated(updateGroup(groupId, groupInformation, &superGroups)->groupId); } -void TDLibWrapper::handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount) -{ - emit chatOnlineMemberCountUpdated(chatId, onlineMemberCount); -} - -void TDLibWrapper::handleMessagesReceived(const QVariantList &messages, const int &totalCount) -{ - emit messagesReceived(messages, totalCount); -} - -void TDLibWrapper::handleNewMessageReceived(const QString &chatId, const QVariantMap &message) -{ - emit newMessageReceived(chatId, message); -} - -void TDLibWrapper::handleMessageInformation(const QString &messageId, const QVariantMap &message) -{ - emit receivedMessage(messageId, message); -} - -void TDLibWrapper::handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message) -{ - emit messageSendSucceeded(messageId, oldMessageId, message); -} - -void TDLibWrapper::handleUpdateActiveNotifications(const QVariantList notificationGroups) -{ - emit activeNotificationsUpdated(notificationGroups); -} - -void TDLibWrapper::handleUpdateNotificationGroup(const QVariantMap notificationGroupUpdate) -{ - emit notificationGroupUpdated(notificationGroupUpdate); -} - -void TDLibWrapper::handleUpdateNotification(const QVariantMap updatedNotification) -{ - emit notificationUpdated(updatedNotification); -} - -void TDLibWrapper::handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings) -{ - emit chatNotificationSettingsUpdated(chatId, chatNotificationSettings); -} - -void TDLibWrapper::handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent) -{ - emit messageContentUpdated(chatId, messageId, newContent); -} - -void TDLibWrapper::handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds) -{ - emit messagesDeleted(chatId, messageIds); -} - -void TDLibWrapper::handleChats(const QVariantMap &chats) -{ - emit this->chatsReceived(chats); -} - -void TDLibWrapper::handleChat(const QVariantMap &chat) -{ - emit this->chatReceived(chat); -} - -void TDLibWrapper::handleRecentStickersUpdated(const QVariantList &stickerIds) -{ - emit this->recentStickersUpdated(stickerIds); -} - -void TDLibWrapper::handleStickers(const QVariantList &stickers) -{ - emit this->stickersReceived(stickers); -} - -void TDLibWrapper::handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds) -{ - emit this->installedStickerSetsUpdated(stickerSetIds); -} - void TDLibWrapper::handleStickerSets(const QVariantList &stickerSets) { QListIterator stickerSetIterator(stickerSets); @@ -998,67 +962,12 @@ void TDLibWrapper::handleStickerSets(const QVariantList &stickerSets) emit this->stickerSetsReceived(stickerSets); } -void TDLibWrapper::handleStickerSet(const QVariantMap &stickerSet) -{ - emit stickerSetReceived(stickerSet); -} - void TDLibWrapper::handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList) { LOG("Emoji search completed" << queryString); emit emojiSearchSuccessful(resultList); } -void TDLibWrapper::handleChatMembers(const QString &extra, const QVariantList &members, const int &totalMembers) -{ - emit this->chatMembersReceived(extra, members, totalMembers); -} - -void TDLibWrapper::handleUserFullInfo(const QVariantMap &userFullInfo) -{ - emit this->userFullInfoReceived(userFullInfo); -} - -void TDLibWrapper::handleUserFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo) -{ - emit this->userFullInfoUpdated(userId, userFullInfo); -} - -void TDLibWrapper::handleBasicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo) -{ - emit this->basicGroupFullInfoReceived(groupId, groupFullInfo); -} - -void TDLibWrapper::handleBasicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo) -{ - emit this->basicGroupFullInfoUpdated(groupId, groupFullInfo); -} - -void TDLibWrapper::handleSupergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo) -{ - emit this->supergroupFullInfoReceived(groupId, groupFullInfo); -} - -void TDLibWrapper::handleSupergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo) -{ - emit this->supergroupFullInfoUpdated(groupId, groupFullInfo); -} - -void TDLibWrapper::handleUserProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos) -{ - emit this->userProfilePhotosReceived(extra, photos, totalPhotos); -} - -void TDLibWrapper::handleChatPermissionsUpdated(const QString &chatId, const QVariantMap permissions) -{ - emit this->chatPermissionsUpdated(chatId, permissions); -} - -void TDLibWrapper::handleChatTitleUpdated(const QString &chatId, const QString title) -{ - emit this->chatTitleUpdated(chatId, title); -} - void TDLibWrapper::setInitialParameters() { LOG("Sending initial parameters to TD Lib"); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index d440b04..677e907 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -99,7 +99,7 @@ public: Q_INVOKABLE QVariantMap getChat(const QString &chatId); Q_INVOKABLE void copyFileToDownloads(const QString &filePath); Q_INVOKABLE void openFileOnDevice(const QString &filePath); - Q_INVOKABLE void controlScreenSaver(const bool &enabled); + Q_INVOKABLE void controlScreenSaver(bool enabled); DBusAdaptor *getDBusAdaptor(); @@ -114,34 +114,38 @@ public: Q_INVOKABLE void openChat(const QString &chatId); Q_INVOKABLE void closeChat(const QString &chatId); Q_INVOKABLE void leaveChat(const QString &chatId); - Q_INVOKABLE void getChatHistory(const QString &chatId, const qlonglong &fromMessageId = 0, const int &offset = 0, const int &limit = 50, const bool &onlyLocal = false); - Q_INVOKABLE void viewMessage(const QString &chatId, const QString &messageId, const bool &force); + Q_INVOKABLE void getChatHistory(const QString &chatId, const qlonglong &fromMessageId = 0, int offset = 0, int limit = 50, bool onlyLocal = false); + Q_INVOKABLE void viewMessage(const QString &chatId, const QString &messageId, bool force); Q_INVOKABLE void sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendPhotoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendVideoMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendDocumentMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0"); Q_INVOKABLE void sendStickerMessage(const QString &chatId, const QString &fileId, const QString &replyToMessageId = "0"); + Q_INVOKABLE void sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, const bool &anonymous, const int &correctOption, const bool &multiple, const QString &replyToMessageId = "0"); Q_INVOKABLE void getMessage(const QString &chatId, const QString &messageId); - Q_INVOKABLE void setOptionInteger(const QString &optionName, const int &optionValue); + Q_INVOKABLE void setOptionInteger(const QString &optionName, int optionValue); Q_INVOKABLE void setChatNotificationSettings(const QString &chatId, const QVariantMap ¬ificationSettings); Q_INVOKABLE void editMessageText(const QString &chatId, const QString &messageId, const QString &message); Q_INVOKABLE void deleteMessages(const QString &chatId, const QVariantList messageIds); - Q_INVOKABLE void getMapThumbnailFile(const QString &chatId, const double &latitude, const double &longitude, const int &width, const int &height); + Q_INVOKABLE void getMapThumbnailFile(const QString &chatId, double latitude, double longitude, int width, int height); Q_INVOKABLE void getRecentStickers(); Q_INVOKABLE void getInstalledStickerSets(); Q_INVOKABLE void getStickerSet(const QString &setId); - Q_INVOKABLE void getSupergroupMembers(const QString &groupId, const int &limit, const int &offset); - Q_INVOKABLE void getGroupFullInfo(const QString &groupId, const bool &isSuperGroup); + Q_INVOKABLE void getSupergroupMembers(const QString &groupId, int limit, int offset); + Q_INVOKABLE void getGroupFullInfo(const QString &groupId, bool isSuperGroup); Q_INVOKABLE void getUserFullInfo(const QString &userId); Q_INVOKABLE void createPrivateChat(const QString &userId); - Q_INVOKABLE void getGroupsInCommon(const QString &userId, const int &limit, const int &offset); - Q_INVOKABLE void getUserProfilePhotos(const QString &userId, const int &limit, const int &offset); + Q_INVOKABLE void getGroupsInCommon(const QString &userId, int limit, int offset); + Q_INVOKABLE void getUserProfilePhotos(const QString &userId, int limit, int offset); Q_INVOKABLE void setChatPermissions(const QString &chatId, const QVariantMap &chatPermissions); - Q_INVOKABLE void setChatSlowModeDelay(const QString &chatId, const int &delay); + Q_INVOKABLE void setChatSlowModeDelay(const QString &chatId, int delay); Q_INVOKABLE void setChatDescription(const QString &chatId, const QString &description); Q_INVOKABLE void setChatTitle(const QString &chatId, const QString &title); Q_INVOKABLE void setBio(const QString &bio); - Q_INVOKABLE void toggleSupergroupIsAllHistoryAvailable(const QString &groupId, const bool &isAllHistoryAvailable); + Q_INVOKABLE void toggleSupergroupIsAllHistoryAvailable(const QString &groupId, bool isAllHistoryAvailable); + Q_INVOKABLE void setPollAnswer(const QString &chatId, const qlonglong &messageId, QVariantList optionIds); + Q_INVOKABLE void stopPoll(const QString &chatId, const qlonglong &messageId); + Q_INVOKABLE void getPollVoters(const QString &chatId, const qlonglong &messageId, const int &optionId, const int &limit, const int &offset, const QString &extra); // Others (candidates for extraction ;)) Q_INVOKABLE void searchEmoji(const QString &queryString); @@ -156,19 +160,19 @@ signals: void authorizationStateChanged(const TDLibWrapper::AuthorizationState &authorizationState, const QVariantMap &authorizationStateData); void optionUpdated(const QString &optionName, const QVariant &optionValue); void connectionStateChanged(const TDLibWrapper::ConnectionState &connectionState); - void fileUpdated(const int fileId, const QVariantMap &fileInformation); + void fileUpdated(int fileId, const QVariantMap &fileInformation); void newChatDiscovered(const QString &chatId, const QVariantMap &chatInformation); void unreadMessageCountUpdated(const QVariantMap &messageCountInformation); void unreadChatCountUpdated(const QVariantMap &chatCountInformation); void chatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage); void chatOrderUpdated(const QString &chatId, const QString &order); - void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); + void chatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, int unreadCount); void chatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void userUpdated(const QString &userId, const QVariantMap &userInformation); void basicGroupUpdated(qlonglong groupId); void superGroupUpdated(qlonglong groupId); - void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void messagesReceived(const QVariantList &messages, const int &totalCount); + void chatOnlineMemberCountUpdated(const QString &chatId, int onlineMemberCount); + void messagesReceived(const QVariantList &messages, int totalCount); void newMessageReceived(const QString &chatId, const QVariantMap &message); void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath); void copyToDownloadsError(const QString &fileName, const QString &filePath); @@ -188,16 +192,17 @@ signals: void stickerSetsReceived(const QVariantList &stickerSets); void stickerSetReceived(const QVariantMap &stickerSet); void emojiSearchSuccessful(const QVariantList &result); - void chatMembersReceived(const QString &extra, const QVariantList &members, const int &totalMembers); + void chatMembersReceived(const QString &extra, const QVariantList &members, int totalMembers); void userFullInfoReceived(const QVariantMap &userFullInfo); void userFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo); void basicGroupFullInfoReceived(const QString &groupId, const QVariantMap &groupFullInfo); void supergroupFullInfoReceived(const QString &groupId, const QVariantMap &groupFullInfo); void basicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); void supergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); - void userProfilePhotosReceived(const QString &extra, const QVariantList &photos, const int &totalPhotos); + void userProfilePhotosReceived(const QString &extra, const QVariantList &photos, int totalPhotos); void chatPermissionsUpdated(const QString &chatId, const QVariantMap &permissions); void chatTitleUpdated(const QString &chatId, const QString &title); + void usersReceived(const QString &extra, const QVariantList &userIds, int totalUsers); public slots: void handleVersionDetected(const QString &version); @@ -210,41 +215,10 @@ public slots: void handleNewChatDiscovered(const QVariantMap &chatInformation); void handleUnreadMessageCountUpdated(const QVariantMap &messageCountInformation); void handleUnreadChatCountUpdated(const QVariantMap &chatCountInformation); - void handleChatLastMessageUpdated(const QString &chatId, const QString &order, const QVariantMap &lastMessage); - void handleChatOrderUpdated(const QString &chatId, const QString &order); - void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); - void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); void handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); - void handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void handleMessagesReceived(const QVariantList &messages, const int &totalCount); - void handleNewMessageReceived(const QString &chatId, const QVariantMap &message); - void handleMessageInformation(const QString &messageId, const QVariantMap &message); - void handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message); - void handleUpdateActiveNotifications(const QVariantList notificationGroups); - void handleUpdateNotificationGroup(const QVariantMap notificationGroupUpdate); - void handleUpdateNotification(const QVariantMap updatedNotification); - void handleChatNotificationSettingsUpdated(const QString &chatId, const QVariantMap &chatNotificationSettings); - void handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent); - void handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds); - void handleChats(const QVariantMap &chats); - void handleChat(const QVariantMap &chat); - void handleRecentStickersUpdated(const QVariantList &stickerIds); - void handleStickers(const QVariantList &stickers); - void handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds); void handleStickerSets(const QVariantList &stickerSets); - void handleStickerSet(const QVariantMap &stickerSet); void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList); - void handleChatMembers(const QString &extra, const QVariantList &members, const int &totalMembers); - void handleUserFullInfo(const QVariantMap &userFullInfo); - void handleUserFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo); - void handleBasicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); - void handleBasicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); - void handleSupergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); - void handleSupergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); - void handleUserProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos); - void handleChatPermissionsUpdated(const QString &chatId, const QVariantMap permissions); - void handleChatTitleUpdated(const QString &chatId, const QString title); private: void setInitialParameters(); diff --git a/translations/harbour-fernschreiber-de.ts b/translations/harbour-fernschreiber-de.ts index 93e44cf..eaae40c 100644 --- a/translations/harbour-fernschreiber-de.ts +++ b/translations/harbour-fernschreiber-de.ts @@ -542,6 +542,24 @@ changed the chat title hat den Chattitel geändert + + sent a poll + myself + haben eine Umfrage geschickt + + + sent a poll + hat eine Umfrage geschickt + + + sent a quiz + myself + haben ein Quiz geschickt + + + sent a quiz + hat ein Quiz geschickt + ImagePage @@ -685,6 +703,178 @@ Sie haben noch keine Chats. + + PollCreationPage + + All answers have to contain 1-100 characters. + Alle Antworten müssen 1-100 Zeichen beinhalten. + + + To send a quiz, you have to specify the right answer. + Um ein Quiz zu senden, müssen Sie die richtige Antwort auswählen. + + + You have to enter a question. + Sie müssen eine Frage eingeben. + + + The question has to be shorter than 256 characters. + Die Frage muss kürzer als 256 Zeichen sein. + + + A poll requires 2-10 answers. + Eine Umfrage benötigt 2-10 Antworten. + + + Create a Poll + Dialog Header + Erstellen Sie eine Umfrage + + + in %1 + After dialog header… Create a Poll in [group name] + in %1 + + + Enter your question here + Geben Sie Ihre Frage ein + + + Question (%n1 characters left) + + Frage (%n1 Zeichen übrig) + Frage (%n1 Zeichen übrig) + + + + Answers + Section header + Antworten + + + Enter an answer here + Geben Sie eine Antwort ein + + + Answer (%n1 characters left) + + Antwort (%n1 Zeichen übrig) + Antwort (%n1 Zeichen übrig) + + + + Add an answer + Antwort hinzufügen + + + Poll Options + Section header + Umfrageoptionen + + + Anonymous answers + Anonyme Antworten + + + Multiple answers allowed + Mehrere Antworten erlaubt + + + Quiz Mode + Quizmodus + + + Quizzes have one correct answer. Participants can't revoke their responses. + Quizze haben eine korrekte Antwort. Teilnehmer können ihre Antwort nicht zurückziehen. + + + + PollPreview + + %L1% + % of votes for option + %L1% + + + Final Result: + Endergebnis: + + + Multiple Answers are allowed. + Mehrfachauswahl ist erlaubt. + + + %L1 vote(s) total + number of total votes + + %L1 Stimme insgesamt + %L1 Stimmen insgesamt + + + + Close Poll + Umfrage beenden + + + Reset Answer + Antwort zurückziehen + + + + PollResultsPage + + Quiz Results + Quizergebnis + + + Poll Results + Umfrageergebnis + + + %L1 vote(s) total + number of total votes + + %L1 Stimme insgesamt + %L1 Stimmen insgesamt + + + + Question + section header + Frage + + + Results + section header + Ergebnis + + + %L1 vote(s) + number of votes for option + + %L1 Antwort + %L1 Antworten + + + + %L1% + % of votes for option + %L1% + + + Chosen by: + This answer has been chosen by the following users + Gewählt von: + + + %L1 vote(s) including yours + number of votes for option + + %L1 Antwort inklusive Ihrer + %L1 Antworten inklusive Ihrer + + + SettingsPage @@ -964,5 +1154,41 @@ changed the chat title to %1 hat den Chattitel zu %1 geändert + + sent a poll + myself + haben eine Umfrage gesendet + + + sent a poll + hat eine Umfrage gesendet + + + sent an anonymous quiz + myself + haben ein anonymes Quiz gesendet + + + sent an anonymous quiz + hat ein anonymes Quiz gesendet + + + sent a quiz + myself + haben ein Quiz gesendet + + + sent a quiz + hat ein Quiz gesendet + + + sent an anonymous poll + myself + haben eine anonyme Umfrage gesendet + + + sent an anonymous poll + hat eine anonyme Umfrage gesendet + diff --git a/translations/harbour-fernschreiber-es.ts b/translations/harbour-fernschreiber-es.ts index 53f5120..2843445 100644 --- a/translations/harbour-fernschreiber-es.ts +++ b/translations/harbour-fernschreiber-es.ts @@ -542,6 +542,24 @@ changed the chat title el título del charla se cambió + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,172 @@ No hay todavía ninguna charla. + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + SettingsPage @@ -964,5 +1148,41 @@ changed the chat title to %1 se cambió el título de la charla a %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-fi.ts b/translations/harbour-fernschreiber-fi.ts index 21b13b2..c7dfa43 100644 --- a/translations/harbour-fernschreiber-fi.ts +++ b/translations/harbour-fernschreiber-fi.ts @@ -543,6 +543,24 @@ changed the chat title muutti keskustelun otsikkoa + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -686,6 +704,178 @@ Sinulla ei ole vielä keskusteluja. + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + + SettingsPage @@ -965,5 +1155,41 @@ changed the chat title to %1 vaihtoi keskustelun otsikoksi %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-hu.ts b/translations/harbour-fernschreiber-hu.ts index 5955b06..42c4433 100644 --- a/translations/harbour-fernschreiber-hu.ts +++ b/translations/harbour-fernschreiber-hu.ts @@ -542,6 +542,24 @@ changed the chat title + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,172 @@ + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + SettingsPage @@ -964,5 +1148,41 @@ changed the chat title to %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-it.ts b/translations/harbour-fernschreiber-it.ts index 4e804ad..7188854 100644 --- a/translations/harbour-fernschreiber-it.ts +++ b/translations/harbour-fernschreiber-it.ts @@ -542,6 +542,24 @@ changed the chat title Ha modificato il titolo della chat + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,178 @@ Non hai nessuna chat. + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + + SettingsPage @@ -964,5 +1154,41 @@ changed the chat title to %1 ha modificato il titolo della chat in %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-pl.ts b/translations/harbour-fernschreiber-pl.ts index 83b1565..0ad2981 100644 --- a/translations/harbour-fernschreiber-pl.ts +++ b/translations/harbour-fernschreiber-pl.ts @@ -542,6 +542,24 @@ changed the chat title + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,184 @@ Nie masz jeszcze żadnych czatów. + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + + + SettingsPage @@ -964,5 +1160,41 @@ changed the chat title to %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-ru.ts b/translations/harbour-fernschreiber-ru.ts index 263552a..69bf463 100644 --- a/translations/harbour-fernschreiber-ru.ts +++ b/translations/harbour-fernschreiber-ru.ts @@ -542,6 +542,24 @@ changed the chat title + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,184 @@ Тут пока ничего нет + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + + + SettingsPage @@ -964,5 +1160,41 @@ changed the chat title to %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber-zh_CN.ts b/translations/harbour-fernschreiber-zh_CN.ts index a18810d..7ef0098 100644 --- a/translations/harbour-fernschreiber-zh_CN.ts +++ b/translations/harbour-fernschreiber-zh_CN.ts @@ -542,6 +542,24 @@ changed the chat title + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,172 @@ 你尚无任何对话。 + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + SettingsPage @@ -964,5 +1148,41 @@ changed the chat title to %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + + diff --git a/translations/harbour-fernschreiber.ts b/translations/harbour-fernschreiber.ts index da0dd42..48bfa9e 100644 --- a/translations/harbour-fernschreiber.ts +++ b/translations/harbour-fernschreiber.ts @@ -542,6 +542,24 @@ changed the chat title + + sent a poll + myself + + + + sent a poll + + + + sent a quiz + myself + + + + sent a quiz + + ImagePage @@ -685,6 +703,172 @@ + + PollCreationPage + + All answers have to contain 1-100 characters. + + + + To send a quiz, you have to specify the right answer. + + + + You have to enter a question. + + + + The question has to be shorter than 256 characters. + + + + A poll requires 2-10 answers. + + + + Create a Poll + Dialog Header + + + + in %1 + After dialog header… Create a Poll in [group name] + + + + Enter your question here + + + + Question (%n1 characters left) + + + + + + Answers + Section header + + + + Enter an answer here + + + + Answer (%n1 characters left) + + + + + + Add an answer + + + + Poll Options + Section header + + + + Anonymous answers + + + + Multiple answers allowed + + + + Quiz Mode + + + + Quizzes have one correct answer. Participants can't revoke their responses. + + + + + PollPreview + + %L1% + % of votes for option + + + + Final Result: + + + + Multiple Answers are allowed. + + + + %L1 vote(s) total + number of total votes + + + + + + Close Poll + + + + Reset Answer + + + + + PollResultsPage + + Quiz Results + + + + Poll Results + + + + %L1 vote(s) total + number of total votes + + + + + + Question + section header + + + + Results + section header + + + + %L1 vote(s) + number of votes for option + + + + + + %L1% + % of votes for option + + + + Chosen by: + This answer has been chosen by the following users + + + + %L1 vote(s) including yours + number of votes for option + + + + + SettingsPage @@ -964,5 +1148,41 @@ changed the chat title to %1 + + sent a poll + myself + + + + sent a poll + + + + sent an anonymous quiz + myself + + + + sent an anonymous quiz + + + + sent a quiz + myself + + + + sent a quiz + + + + sent an anonymous poll + myself + + + + sent an anonymous poll + +