Merge remote-tracking branch 'origin/master' into userPreferences
This commit is contained in:
commit
2fcacef6d4
26 changed files with 488 additions and 186 deletions
|
@ -64,6 +64,8 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
||||||
qml/components/StickerPicker.qml \
|
qml/components/StickerPicker.qml \
|
||||||
qml/components/PhotoTextsListItem.qml \
|
qml/components/PhotoTextsListItem.qml \
|
||||||
qml/components/TDLibImage.qml \
|
qml/components/TDLibImage.qml \
|
||||||
|
qml/components/TDLibMinithumbnail.qml \
|
||||||
|
qml/components/TDLibPhoto.qml \
|
||||||
qml/components/TDLibThumbnail.qml \
|
qml/components/TDLibThumbnail.qml \
|
||||||
qml/components/VoiceNoteOverlay.qml \
|
qml/components/VoiceNoteOverlay.qml \
|
||||||
qml/components/chatInformationPage/ChatInformationPageContent.qml \
|
qml/components/chatInformationPage/ChatInformationPageContent.qml \
|
||||||
|
|
56
qml/components/TDLibMinithumbnail.qml
Normal file
56
qml/components/TDLibMinithumbnail.qml
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import QtQuick 2.6
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
property var minithumbnail
|
||||||
|
property bool highlighted
|
||||||
|
anchors.fill: parent
|
||||||
|
active: !!minithumbnail
|
||||||
|
visible: active
|
||||||
|
sourceComponent: Component {
|
||||||
|
Item {
|
||||||
|
Image {
|
||||||
|
id: minithumbnailImage
|
||||||
|
anchors.fill: parent
|
||||||
|
source: "data:image/jpg;base64,"+minithumbnail.data
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: tdLibImage.fillMode
|
||||||
|
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||||
|
cache: false
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
|
||||||
|
layer {
|
||||||
|
enabled: loader.highlighted
|
||||||
|
effect: PressEffect { source: minithumbnailImage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FastBlur {
|
||||||
|
anchors.fill: parent
|
||||||
|
source: minithumbnailImage
|
||||||
|
radius: Theme.paddingLarge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
69
qml/components/TDLibPhoto.qml
Normal file
69
qml/components/TDLibPhoto.qml
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import QtQuick 2.6
|
||||||
|
import WerkWolf.Fernschreiber 1.0
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
import QtGraphicalEffects 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: tdLibPhoto
|
||||||
|
property var photo
|
||||||
|
property bool highlighted
|
||||||
|
readonly property alias fileInformation: tdLibImage.fileInformation
|
||||||
|
readonly property alias image: tdLibImage
|
||||||
|
|
||||||
|
onWidthChanged: setImageFile()
|
||||||
|
onPhotoChanged: setImageFile()
|
||||||
|
|
||||||
|
function setImageFile() {
|
||||||
|
if (photo) {
|
||||||
|
var photoSize;
|
||||||
|
for (var i = 0; i < photo.sizes.length; i++) {
|
||||||
|
photoSize = photo.sizes[i].photo;
|
||||||
|
if (photo.sizes[i].width >= width) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (photoSize && photoSize.id !== tdLibImage.fileInformation.id) {
|
||||||
|
tdLibImage.fileInformation = photoSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TDLibMinithumbnail {
|
||||||
|
id: minithumbnailLoader
|
||||||
|
active: !!minithumbnail && tdLibImage.opacity < 1.0
|
||||||
|
minithumbnail: tdLibPhoto.photo.minithumbnail
|
||||||
|
highlighted: parent.highlighted
|
||||||
|
}
|
||||||
|
|
||||||
|
BackgroundImage {
|
||||||
|
visible: tdLibImage.opacity < 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
TDLibImage {
|
||||||
|
id: tdLibImage
|
||||||
|
width: parent.width //don't use anchors here for easier custom scaling
|
||||||
|
height: parent.height
|
||||||
|
cache: false
|
||||||
|
highlighted: parent.highlighted
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: setImageFile()
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ Item {
|
||||||
- video
|
- video
|
||||||
- videoNote
|
- videoNote
|
||||||
*/
|
*/
|
||||||
property var minithumbnail
|
property alias minithumbnail: minithumbnailLoader.minithumbnail
|
||||||
property bool useBackgroundImage: true
|
property bool useBackgroundImage: true
|
||||||
property bool highlighted
|
property bool highlighted
|
||||||
|
|
||||||
|
@ -65,29 +65,12 @@ Item {
|
||||||
effect: PressEffect { source: tdlibThumbnail }
|
effect: PressEffect { source: tdlibThumbnail }
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
TDLibMinithumbnail {
|
||||||
id: backgroundLoader
|
id: minithumbnailLoader
|
||||||
anchors.fill: parent
|
active: !!minithumbnail && thumbnailImage.opacity < 1.0
|
||||||
active: !parent.hasVisibleThumbnail
|
}
|
||||||
asynchronous: true
|
BackgroundImage {
|
||||||
sourceComponent: !!parent.minithumbnail ? miniThumbnailComponent : parent.useBackgroundImage ? backgroundImageComponent : ""
|
visible: tdlibThumbnail.useBackgroundImage && thumbnailImage.opacity < 1.0
|
||||||
Component {
|
|
||||||
id: backgroundImageComponent
|
|
||||||
BackgroundImage {}
|
|
||||||
}
|
|
||||||
Component {
|
|
||||||
id: miniThumbnailComponent
|
|
||||||
Image {
|
|
||||||
clip: true
|
|
||||||
asynchronous: true
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
|
||||||
smooth: false
|
|
||||||
source: "data:image/jpg;base64," + tdlibThumbnail.miniThumbnail.data
|
|
||||||
visible: opacity > 0
|
|
||||||
Behavior on opacity { FadeAnimation {} }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// image thumbnail
|
// image thumbnail
|
||||||
|
|
|
@ -17,52 +17,13 @@
|
||||||
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
import Sailfish.Silica 1.0
|
|
||||||
import QtMultimedia 5.6
|
|
||||||
import WerkWolf.Fernschreiber 1.0
|
|
||||||
import "../"
|
import "../"
|
||||||
|
|
||||||
InlineQueryResult {
|
InlineQueryResult {
|
||||||
id: queryResultItem
|
id: queryResultItem
|
||||||
|
|
||||||
|
TDLibPhoto {
|
||||||
TDLibFile {
|
|
||||||
id: file
|
|
||||||
tdlib: tdLibWrapper
|
|
||||||
autoLoad: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
asynchronous: true
|
|
||||||
active: file.isDownloadingCompleted
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: item && item.status === Image.Ready ? 1.0 : 0.0
|
photo: model.photo
|
||||||
Behavior on opacity { FadeAnimation {} }
|
|
||||||
sourceComponent: Component {
|
|
||||||
Image {
|
|
||||||
id: image
|
|
||||||
source: file.path
|
|
||||||
asynchronous: true
|
|
||||||
clip: true
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
layer.enabled: queryResultItem.pressed
|
|
||||||
layer.effect: PressEffect { source: image }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Component.onCompleted: {
|
|
||||||
if (model.photo) {
|
|
||||||
// Check first which size fits best...
|
|
||||||
var photo
|
|
||||||
for (var i = 0; i < model.photo.sizes.length; i++) {
|
|
||||||
photo = model.photo.sizes[i].photo
|
|
||||||
if (model.photo.sizes[i].width >= queryResultItem.width) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (photo) {
|
|
||||||
file.fileInformation = photo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,72 +22,51 @@ import Sailfish.Silica 1.0
|
||||||
import "../"
|
import "../"
|
||||||
|
|
||||||
MessageContentBase {
|
MessageContentBase {
|
||||||
|
id: contentItem
|
||||||
id: imagePreviewItem
|
|
||||||
|
|
||||||
property var locationData : ( rawMessage.content['@type'] === "messageLocation" ) ? rawMessage.content.location : ( ( rawMessage.content['@type'] === "messageVenue" ) ? rawMessage.content.venue.location : "" )
|
|
||||||
|
|
||||||
property string chatId: rawMessage.chat_id
|
|
||||||
property var pictureFileInformation;
|
|
||||||
height: width * 0.66666666;
|
height: width * 0.66666666;
|
||||||
property string fileExtra
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
property var locationData : rawMessage.content.location
|
||||||
updatePicture();
|
property string fileExtra;
|
||||||
}
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if(!processLauncher.launchProgram('harbour-pure-maps', ["geo:"+locationData.latitude+","+locationData.longitude])) {
|
if(!processLauncher.launchProgram('harbour-pure-maps', ["geo:"+locationData.latitude+","+locationData.longitude])) {
|
||||||
imageNotification.show(qsTr("Install Pure Maps to inspect this location."));
|
imageNotification.show(qsTr("Install Pure Maps to inspect this location."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onLocationDataChanged: updatePicture()
|
||||||
|
onWidthChanged: updatePicture()
|
||||||
|
|
||||||
function updatePicture() {
|
function updatePicture() {
|
||||||
imagePreviewItem.pictureFileInformation = null;
|
|
||||||
if (locationData) {
|
if (locationData) {
|
||||||
fileExtra = "location:" + locationData.latitude + ":" + locationData.longitude + ":" + Math.round(imagePreviewItem.width) + ":" + Math.round(imagePreviewItem.height);
|
fileExtra = "location:" + locationData.latitude + ":" + locationData.longitude + ":" + Math.round(contentItem.width) + ":" + Math.round(contentItem.height);
|
||||||
tdLibWrapper.getMapThumbnailFile(chatId, locationData.latitude, locationData.longitude, Math.round(imagePreviewItem.width), Math.round(imagePreviewItem.height), fileExtra);
|
tdLibWrapper.getMapThumbnailFile(rawMessage.chat_id, locationData.latitude, locationData.longitude, Math.round(contentItem.width), Math.round(contentItem.height), fileExtra);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: tdLibWrapper
|
target: tdLibWrapper
|
||||||
onFileUpdated: {
|
onFileUpdated: {
|
||||||
if(fileInformation["@extra"] !== imagePreviewItem.fileExtra && (!imagePreviewItem.pictureFileInformation || imagePreviewItem.pictureFileInformation.id !== fileInformation.id)) {
|
if(fileInformation["@extra"] === contentItem.fileExtra) {
|
||||||
return;
|
if(fileInformation.id !== image.file.fileId) {
|
||||||
|
image.fileInformation = fileInformation
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(fileInformation.local.is_downloading_completed) {
|
|
||||||
singleImage.source = fileInformation.local.path;
|
|
||||||
} else if(fileInformation.local.can_be_downloaded && !fileInformation.local.is_downloading_active) {
|
|
||||||
tdLibWrapper.downloadFile(fileInformation.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
imagePreviewItem.pictureFileInformation = fileInformation;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppNotification {
|
AppNotification {
|
||||||
id: imageNotification
|
id: imageNotification
|
||||||
}
|
}
|
||||||
|
TDLibImage {
|
||||||
Image {
|
id: image
|
||||||
id: singleImage
|
anchors.fill: parent
|
||||||
width: parent.width - Theme.paddingSmall
|
cache: false
|
||||||
height: parent.height - Theme.paddingSmall
|
highlighted: contentItem.highlighted
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
autoTransform: true
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
opacity: status === Image.Ready ? 1 : 0
|
|
||||||
Behavior on opacity { NumberAnimation {} }
|
|
||||||
|
|
||||||
layer.enabled: imagePreviewItem.highlighted
|
|
||||||
layer.effect: PressEffect { source: singleImage }
|
|
||||||
Item {
|
Item {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: markerImage.width
|
width: markerImage.width
|
||||||
height: markerImage.height * 1.75 // 0.875 (vertical pin point) * 2
|
height: markerImage.height * 1.75 // 0.875 (vertical pin point) * 2
|
||||||
Image {
|
Icon {
|
||||||
id: markerImage
|
id: markerImage
|
||||||
source: 'image://theme/icon-m-location'
|
source: 'image://theme/icon-m-location'
|
||||||
}
|
}
|
||||||
|
@ -105,7 +84,10 @@ MessageContentBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
BackgroundImage {
|
BackgroundImage {
|
||||||
visible: singleImage.status !== Image.Ready
|
visible: image.status !== Image.Ready
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
updatePicture();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,68 +18,40 @@
|
||||||
*/
|
*/
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
import Sailfish.Silica 1.0
|
import Sailfish.Silica 1.0
|
||||||
import WerkWolf.Fernschreiber 1.0
|
|
||||||
import "../"
|
import "../"
|
||||||
|
|
||||||
MessageContentBase {
|
MessageContentBase {
|
||||||
id: imagePreviewItem
|
|
||||||
|
|
||||||
readonly property int defaultHeight: Math.round(width * 2 / 3)
|
function calculateBiggest() {
|
||||||
|
var candidateBiggest = rawMessage.content.photo.sizes[rawMessage.content.photo.sizes.length - 1];
|
||||||
|
if (candidateBiggest.width === 0 && rawMessage.content.photo.sizes.length > 1) {
|
||||||
|
for (var i = (rawMessage.content.photo.sizes.length - 2); i >= 0; i--) {
|
||||||
|
candidateBiggest = rawMessage.content.photo.sizes[i];
|
||||||
|
if (candidateBiggest.width > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return candidateBiggest;
|
||||||
|
}
|
||||||
|
|
||||||
height: singleImage.visible ? Math.min(defaultHeight, singleImage.bestHeight + Theme.paddingSmall) : defaultHeight
|
height: Math.max(Theme.itemSizeExtraSmall, Math.min(defaultHeight, width / (biggest.width/biggest.height)))
|
||||||
|
readonly property int defaultHeight: Math.round(width * 0.66666666)
|
||||||
|
readonly property var biggest: calculateBiggest();
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), {
|
pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), {
|
||||||
"photoData" : imagePreviewItem.rawMessage.content.photo
|
"photoData" : photo.photo,
|
||||||
|
// "pictureFileInformation" : photo.fileInformation
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
TDLibPhoto {
|
||||||
Component.onCompleted: updateImage()
|
id: photo
|
||||||
|
anchors.fill: parent
|
||||||
onRawMessageChanged: updateImage()
|
photo: rawMessage.content.photo
|
||||||
|
highlighted: parent.highlighted
|
||||||
function updateImage() {
|
|
||||||
if (rawMessage.content.photo) {
|
|
||||||
// Check first which size fits best...
|
|
||||||
var photo
|
|
||||||
var photoData = rawMessage.content.photo
|
|
||||||
for (var i = 0; i < photoData.sizes.length; i++) {
|
|
||||||
photo = photoData.sizes[i].photo
|
|
||||||
if (photoData.sizes[i].width >= imagePreviewItem.width) {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (photo) {
|
|
||||||
imageFile.fileInformation = photo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TDLibFile {
|
|
||||||
id: imageFile
|
|
||||||
tdlib: tdLibWrapper
|
|
||||||
autoLoad: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: singleImage
|
|
||||||
width: parent.width - Theme.paddingSmall
|
|
||||||
height: parent.height - Theme.paddingSmall
|
|
||||||
readonly property int bestHeight: (status === Image.Ready) ? Math.round(implicitHeight * width / implicitWidth) : 0
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
autoTransform: true
|
|
||||||
asynchronous: true
|
|
||||||
source: imageFile.isDownloadingCompleted ? imageFile.path : ""
|
|
||||||
visible: status === Image.Ready
|
|
||||||
opacity: visible ? 1 : 0
|
|
||||||
Behavior on opacity { FadeAnimation {} }
|
|
||||||
layer.enabled: imagePreviewItem.highlighted
|
|
||||||
layer.effect: PressEffect { source: singleImage }
|
|
||||||
}
|
|
||||||
|
|
||||||
BackgroundImage {
|
BackgroundImage {
|
||||||
visible: singleImage.status !== Image.Ready
|
visible: !rawMessage.content.photo.minithumbnail && photo.image.status !== Image.Ready
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,6 +230,24 @@ MessageContentBase {
|
||||||
width: 1
|
width: 1
|
||||||
height: Theme.paddingSmall
|
height: Theme.paddingSmall
|
||||||
}
|
}
|
||||||
|
Label {
|
||||||
|
width: parent.width
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
visible: isQuiz && text.length > 0
|
||||||
|
text: Emoji.emojify(Functions.enhanceMessageText(pollData.type.explanation) || "", font.pixelSize)
|
||||||
|
textFormat: Text.StyledText
|
||||||
|
color: pollMessageComponent.isOwnMessage || pollMessageComponent.highlighted ? Theme.highlightColor : Theme.primaryColor
|
||||||
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
|
leftPadding: Theme.iconSizeSmall
|
||||||
|
bottomPadding: Theme.paddingSmall
|
||||||
|
Icon {
|
||||||
|
source: "image://theme/icon-s-high-importance"
|
||||||
|
asynchronous: true
|
||||||
|
width: Theme.iconSizeExtraSmall
|
||||||
|
height: Theme.iconSizeExtraSmall
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
x: -Theme.horizontalPageMargin/2
|
x: -Theme.horizontalPageMargin/2
|
||||||
|
@ -259,7 +277,7 @@ MessageContentBase {
|
||||||
visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0
|
visible: !pollMessageComponent.canAnswer && !pollData.is_anonymous && pollData.total_voter_count > 0
|
||||||
icon.source: "image://theme/icon-m-media-artists"
|
icon.source: "image://theme/icon-m-media-artists"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
pageStack.push(Qt.resolvedUrl("../../pages/PollResultsPage.qml"), { chatId:chatId, message:pollMessageComponent.message});
|
pageStack.push(Qt.resolvedUrl("../../pages/PollResultsPage.qml"), { chatId:chatId, message:pollMessageComponent.rawMessage});
|
||||||
}
|
}
|
||||||
Icon {
|
Icon {
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
|
|
|
@ -16,6 +16,9 @@
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
|
|
||||||
MessageLocation {}
|
MessageLocation {
|
||||||
|
locationData: rawMessage.content.venue.location
|
||||||
|
}
|
||||||
|
|
|
@ -1059,7 +1059,7 @@ Page {
|
||||||
function getContentComponentHeight(contentType, content, parentWidth) {
|
function getContentComponentHeight(contentType, content, parentWidth) {
|
||||||
switch(contentType) {
|
switch(contentType) {
|
||||||
case "messageAnimation":
|
case "messageAnimation":
|
||||||
return Functions.getVideoHeight(parentWidth, content.video);
|
return Functions.getVideoHeight(parentWidth, content.animation);
|
||||||
case "messageAudio":
|
case "messageAudio":
|
||||||
case "messageVoiceNote":
|
case "messageVoiceNote":
|
||||||
case "messageDocument":
|
case "messageDocument":
|
||||||
|
@ -1067,9 +1067,12 @@ Page {
|
||||||
case "messageGame":
|
case "messageGame":
|
||||||
return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3;
|
return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3;
|
||||||
case "messageLocation":
|
case "messageLocation":
|
||||||
case "messagePhoto":
|
|
||||||
case "messageVenue":
|
case "messageVenue":
|
||||||
return parentWidth * 0.66666666; // 2 / 3;
|
return parentWidth * 0.66666666; // 2 / 3;
|
||||||
|
case "messagePhoto":
|
||||||
|
var biggest = content.photo.sizes[content.photo.sizes.length - 1];
|
||||||
|
var aspectRatio = biggest.width/biggest.height;
|
||||||
|
return Math.max(Theme.itemSizeExtraSmall, Math.min(parentWidth * 0.66666666, parentWidth / aspectRatio));
|
||||||
case "messagePoll":
|
case "messagePoll":
|
||||||
return Theme.itemSizeSmall * (4 + content.poll.options);
|
return Theme.itemSizeSmall * (4 + content.poll.options);
|
||||||
case "messageSticker":
|
case "messageSticker":
|
||||||
|
|
|
@ -47,28 +47,20 @@ Page {
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (photoData) {
|
if (photoData) {
|
||||||
// Check first which size fits best...
|
var biggestIndex = -1
|
||||||
var photo
|
|
||||||
for (var i = 0; i < photoData.sizes.length; i++) {
|
for (var i = 0; i < photoData.sizes.length; i++) {
|
||||||
imagePage.imageWidth = photoData.sizes[i].width;
|
if (biggestIndex === -1 || photoData.sizes[i].width > photoData.sizes[biggestIndex].width) {
|
||||||
imagePage.imageHeight = photoData.sizes[i].height;
|
biggestIndex = i;
|
||||||
photo = photoData.sizes[i].photo
|
|
||||||
if (photoData.sizes[i].width >= imagePage.width) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (photo) {
|
if (biggestIndex > -1) {
|
||||||
imageFile.fileInformation = photo
|
imagePage.imageWidth = photoData.sizes[biggestIndex].width;
|
||||||
|
imagePage.imageHeight = photoData.sizes[biggestIndex].height;
|
||||||
|
singleImage.fileInformation = photoData.sizes[biggestIndex].photo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TDLibFile {
|
|
||||||
id: imageFile
|
|
||||||
tdlib: tdLibWrapper
|
|
||||||
autoLoad: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: tdLibWrapper
|
target: tdLibWrapper
|
||||||
onCopyToDownloadsSuccessful: {
|
onCopyToDownloadsSuccessful: {
|
||||||
|
@ -86,11 +78,11 @@ Page {
|
||||||
interactive: !imageOnly
|
interactive: !imageOnly
|
||||||
|
|
||||||
PullDownMenu {
|
PullDownMenu {
|
||||||
visible: !imageOnly && imageFile.isDownloadingCompleted && imageFile.path
|
visible: !imageOnly && singleImage.file.isDownloadingCompleted
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: qsTr("Download Picture")
|
text: qsTr("Download Picture")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
tdLibWrapper.copyFileToDownloads(imageFile.path);
|
tdLibWrapper.copyFileToDownloads(singleImage.file.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,9 +114,8 @@ Page {
|
||||||
imageFlickable.returnToBounds()
|
imageFlickable.returnToBounds()
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
TDLibImage {
|
||||||
id: singleImage
|
id: singleImage
|
||||||
source: imageFile.isDownloadingCompleted ? imageFile.path : ""
|
|
||||||
width: imagePage.imageWidth * imagePage.sizingFactor
|
width: imagePage.imageWidth * imagePage.sizingFactor
|
||||||
height: imagePage.imageHeight * imagePage.sizingFactor
|
height: imagePage.imageHeight * imagePage.sizingFactor
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
|
@ -39,6 +39,7 @@ Dialog {
|
||||||
property alias quiz: quizSwitch.checked
|
property alias quiz: quizSwitch.checked
|
||||||
property alias multiple: multipleSwitch.checked
|
property alias multiple: multipleSwitch.checked
|
||||||
property string replyToMessageId: "0"
|
property string replyToMessageId: "0"
|
||||||
|
property alias quizExplanation: quizExplanationTextArea.text
|
||||||
// poll request data end
|
// poll request data end
|
||||||
|
|
||||||
canAccept: validationErrors.length === 0
|
canAccept: validationErrors.length === 0
|
||||||
|
@ -81,6 +82,9 @@ Dialog {
|
||||||
if(quiz && (correctOption < 0 || correctOption > options.count - 1)) {
|
if(quiz && (correctOption < 0 || correctOption > options.count - 1)) {
|
||||||
errors.push(qsTr("To send a quiz, you have to specify the right answer."));
|
errors.push(qsTr("To send a quiz, you have to specify the right answer."));
|
||||||
}
|
}
|
||||||
|
if(quiz && quizExplanationTextArea.hasError) {
|
||||||
|
errors.push(qsTr("An explanation can be up to 200 characters long."));
|
||||||
|
}
|
||||||
if(errors.length === 0) {
|
if(errors.length === 0) {
|
||||||
validationErrorsVisible = false;
|
validationErrorsVisible = false;
|
||||||
}
|
}
|
||||||
|
@ -333,6 +337,25 @@ Dialog {
|
||||||
}
|
}
|
||||||
description: qsTr("Quizzes have one correct answer. Participants can't revoke their responses.")
|
description: qsTr("Quizzes have one correct answer. Participants can't revoke their responses.")
|
||||||
}
|
}
|
||||||
|
TextArea {
|
||||||
|
id: quizExplanationTextArea
|
||||||
|
width: parent.width
|
||||||
|
opacity: pollCreationPage.quiz ? 1.0 : 0.0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
height: pollCreationPage.quiz ? implicitHeight : 0
|
||||||
|
Behavior on height { NumberAnimation { duration: quizExplanationTextArea.focus ? 0 : 200 } }
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
placeholderText: qsTr("Enter an optional explanation")
|
||||||
|
property int charactersLeft: 200 - text.length
|
||||||
|
property bool hasError: charactersLeft < 0
|
||||||
|
color: hasError ? Theme.errorColor : Theme.highlightColor
|
||||||
|
label: qsTr("Shown when the user selects a wrong answer.")
|
||||||
|
wrapMode: TextEdit.Wrap
|
||||||
|
onFocusChanged: {
|
||||||
|
validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,7 +365,7 @@ Dialog {
|
||||||
optionsArr.push(options.get(i).text);
|
optionsArr.push(options.get(i).text);
|
||||||
}
|
}
|
||||||
|
|
||||||
tdLibWrapper.sendPollMessage(chatId, pollQuestion, optionsArr, anonymous, quiz ? correctOption : -1, multiple, "0");
|
tdLibWrapper.sendPollMessage(chatId, pollQuestion, optionsArr, anonymous, quiz ? correctOption : -1, multiple, quizExplanation, "0");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,9 @@ QString FernschreiberUtils::getMessageShortText(TDLibWrapper *tdLibWrapper, cons
|
||||||
if (contentType == "messageVideo") {
|
if (contentType == "messageVideo") {
|
||||||
return myself ? tr("sent a video", "myself") : tr("sent a video");
|
return myself ? tr("sent a video", "myself") : tr("sent a video");
|
||||||
}
|
}
|
||||||
|
if (contentType == "messageVideoNote") {
|
||||||
|
return myself ? tr("sent a video note", "myself") : tr("sent a video note");
|
||||||
|
}
|
||||||
if (contentType == "messageAnimation") {
|
if (contentType == "messageAnimation") {
|
||||||
return myself ? tr("sent an animation", "myself") : tr("sent an animation");
|
return myself ? tr("sent an animation", "myself") : tr("sent an animation");
|
||||||
}
|
}
|
||||||
|
|
|
@ -569,7 +569,7 @@ void TDLibWrapper::sendStickerMessage(const QString &chatId, const QString &file
|
||||||
this->sendRequest(requestObject);
|
this->sendRequest(requestObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &replyToMessageId)
|
void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, const QString &replyToMessageId)
|
||||||
{
|
{
|
||||||
LOG("Sending poll message" << chatId << question << replyToMessageId);
|
LOG("Sending poll message" << chatId << question << replyToMessageId);
|
||||||
QVariantMap requestObject;
|
QVariantMap requestObject;
|
||||||
|
@ -585,6 +585,11 @@ void TDLibWrapper::sendPollMessage(const QString &chatId, const QString &questio
|
||||||
if(correctOption > -1) {
|
if(correctOption > -1) {
|
||||||
pollType.insert(_TYPE, "pollTypeQuiz");
|
pollType.insert(_TYPE, "pollTypeQuiz");
|
||||||
pollType.insert("correct_option_id", correctOption);
|
pollType.insert("correct_option_id", correctOption);
|
||||||
|
if(!explanation.isEmpty()) {
|
||||||
|
QVariantMap formattedExplanation;
|
||||||
|
formattedExplanation.insert("text", explanation);
|
||||||
|
pollType.insert("explanation", formattedExplanation);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
pollType.insert(_TYPE, "pollTypeRegular");
|
pollType.insert(_TYPE, "pollTypeRegular");
|
||||||
pollType.insert("allow_multiple_answers", multiple);
|
pollType.insert("allow_multiple_answers", multiple);
|
||||||
|
|
|
@ -163,7 +163,7 @@ public:
|
||||||
Q_INVOKABLE void sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0");
|
Q_INVOKABLE void sendVoiceNoteMessage(const QString &chatId, const QString &filePath, const QString &message, const QString &replyToMessageId = "0");
|
||||||
Q_INVOKABLE void sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId = "0");
|
Q_INVOKABLE void sendLocationMessage(const QString &chatId, double latitude, double longitude, double horizontalAccuracy, const QString &replyToMessageId = "0");
|
||||||
Q_INVOKABLE void sendStickerMessage(const QString &chatId, const QString &fileId, 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, bool anonymous, int correctOption, bool multiple, const QString &replyToMessageId = "0");
|
Q_INVOKABLE void sendPollMessage(const QString &chatId, const QString &question, const QVariantList &options, bool anonymous, int correctOption, bool multiple, const QString &explanation, const QString &replyToMessageId = "0");
|
||||||
Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, bool sendCopy, bool removeCaption);
|
Q_INVOKABLE void forwardMessages(const QString &chatId, const QString &fromChatId, const QVariantList &messageIds, bool sendCopy, bool removeCaption);
|
||||||
Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId);
|
Q_INVOKABLE void getMessage(qlonglong chatId, qlonglong messageId);
|
||||||
Q_INVOKABLE void getCallbackQueryAnswer(const QString &chatId, const QString &messageId, const QVariantMap &payload);
|
Q_INVOKABLE void getCallbackQueryAnswer(const QString &chatId, const QString &messageId, const QVariantMap &payload);
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation>hat ein Spiel gesendet</translation>
|
<translation>hat ein Spiel gesendet</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation>haben eine Videonachricht geschickt</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation>hat eine Videonachricht geschickt</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1064,7 +1073,7 @@
|
||||||
<name>MessageVoiceNote</name>
|
<name>MessageVoiceNote</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Voice Note</source>
|
<source>Voice Note</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>Sprachnotiz</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Quizze haben eine korrekte Antwort. Teilnehmer können ihre Antwort nicht zurückziehen.</translation>
|
<translation>Quizze haben eine korrekte Antwort. Teilnehmer können ihre Antwort nicht zurückziehen.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation>Geben Sie eine optionale Erklärung ein</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation>Wird bei Auswahl einer falschen Antwort gezeigt.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation>Eine Erklärung kann bis zu 200 Zeichen lang sein.</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
@ -1966,7 +1987,7 @@
|
||||||
<message>
|
<message>
|
||||||
<source>sent a video note</source>
|
<source>sent a video note</source>
|
||||||
<comment>myself</comment>
|
<comment>myself</comment>
|
||||||
<translation>haben eine Videonachricht geschicht</translation>
|
<translation>haben eine Videonachricht geschickt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>sent a video note</source>
|
<source>sent a video note</source>
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation>sent a game</translation>
|
<translation>sent a game</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation>sent a video note</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation>sent a video note</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1064,7 +1073,7 @@
|
||||||
<name>MessageVoiceNote</name>
|
<name>MessageVoiceNote</name>
|
||||||
<message>
|
<message>
|
||||||
<source>Voice Note</source>
|
<source>Voice Note</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation>Voice Note</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Quizzes have one correct answer. Participants can't revoke their responses.</translation>
|
<translation>Quizzes have one correct answer. Participants can't revoke their responses.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation>Enter an optional explanation</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation>Shown when the user selects a wrong answer.</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation>An explanation can be up to 200 characters long.</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished">envió una nota de video</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished">envió una nota de video</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Los interrogatorios tienen una respuesta correcta. Los participantes no pueden revocar sus respuestas.</translation>
|
<translation>Los interrogatorios tienen una respuesta correcta. Los participantes no pueden revocar sus respuestas.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -841,6 +841,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1299,6 +1308,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Visoilla on yksi oikea vastaus. Osallistujat eivät voi kumota vastaustaan.</translation>
|
<translation>Visoilla on yksi oikea vastaus. Osallistujat eivät voi kumota vastaustaan.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -828,6 +828,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1279,6 +1288,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>I quiz hanno una sola risposta corretta. I partecipanti non possono revocare le risposte.</translation>
|
<translation>I quiz hanno una sola risposta corretta. I partecipanti non possono revocare le risposte.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -852,6 +852,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1317,6 +1326,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Quizy mają jedną poprawną odpowiedź. Uczestnicy nie mogą odwołać swoich odpowiedzi.</translation>
|
<translation>Quizy mają jedną poprawną odpowiedź. Uczestnicy nie mogą odwołać swoich odpowiedzi.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -852,6 +852,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished">отправлена видео заметка</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished">отправлена видео заметка</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1317,6 +1326,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Тесты имеют один правильный ответ. Участники не могут отозвать свои ответы.</translation>
|
<translation>Тесты имеют один правильный ответ. Участники не могут отозвать свои ответы.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished">skickade ett videomeddelande</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished">skickade ett videomeddelande</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Frågor har ett (1) korrekt svar. Deltagarna kan inte återkalla sina svar.</translation>
|
<translation>Frågor har ett (1) korrekt svar. Deltagarna kan inte återkalla sina svar.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -828,6 +828,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation>发送游戏</translation>
|
<translation>发送游戏</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished">发送视频消息</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished">发送视频消息</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1279,6 +1288,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Quiz 拥有一个正确选项,参与者无法撤销回答。</translation>
|
<translation>Quiz 拥有一个正确选项,参与者无法撤销回答。</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
|
@ -840,6 +840,15 @@
|
||||||
<source>sent a game</source>
|
<source>sent a game</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<comment>myself</comment>
|
||||||
|
<translation type="unfinished">sent a video note</translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>sent a video note</source>
|
||||||
|
<translation type="unfinished">sent a video note</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>ImagePage</name>
|
<name>ImagePage</name>
|
||||||
|
@ -1298,6 +1307,18 @@
|
||||||
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
<source>Quizzes have one correct answer. Participants can't revoke their responses.</source>
|
||||||
<translation>Quizzes have one correct answer. Participants can't revoke their responses.</translation>
|
<translation>Quizzes have one correct answer. Participants can't revoke their responses.</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Enter an optional explanation</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Shown when the user selects a wrong answer.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>An explanation can be up to 200 characters long.</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>PollResultsPage</name>
|
<name>PollResultsPage</name>
|
||||||
|
|
Loading…
Reference in a new issue