Implement inline queries (among others)
This commit is contained in:
parent
be2f08553b
commit
1ce981c147
49 changed files with 2954 additions and 76 deletions
|
@ -45,12 +45,15 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
|||
qml/components/BackgroundImage.qml \
|
||||
qml/components/ChatListViewItem.qml \
|
||||
qml/components/DocumentPreview.qml \
|
||||
qml/components/GamePreview.qml \
|
||||
qml/components/ImagePreview.qml \
|
||||
qml/components/InReplyToRow.qml \
|
||||
qml/components/InlineQuery.qml \
|
||||
qml/components/LocationPreview.qml \
|
||||
qml/components/MessageListViewItem.qml \
|
||||
qml/components/MessageListViewItemSimple.qml \
|
||||
qml/components/MessageOverlayFlickable.qml \
|
||||
qml/components/MessageViaLabel.qml \
|
||||
qml/components/MultilineEmojiLabel.qml \
|
||||
qml/components/PinnedMessageItem.qml \
|
||||
qml/components/PollPreview.qml \
|
||||
|
@ -72,6 +75,20 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
|||
qml/components/chatInformationPage/ChatInformationTextItem.qml \
|
||||
qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml \
|
||||
qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResult.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultAnimation.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultArticle.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultAudio.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultContact.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultDefaultBase.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultDocument.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultGame.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultLocation.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultPhoto.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultSticker.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultVenue.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultVideo.qml \
|
||||
qml/components/inlineQueryResults/InlineQueryResultVoiceNote.qml \
|
||||
qml/js/debug.js \
|
||||
qml/js/functions.js \
|
||||
qml/pages/ChatInformationPage.qml \
|
||||
|
|
126
qml/components/GamePreview.qml
Normal file
126
qml/components/GamePreview.qml
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../js/functions.js" as Functions
|
||||
import "../js/twemoji.js" as Emoji
|
||||
|
||||
Column {
|
||||
id: gamePreviewItem
|
||||
|
||||
property ListItem messageListItem
|
||||
property MessageOverlayFlickable overlayFlickable
|
||||
property var rawMessage: messageListItem ? messageListItem.myMessage : overlayFlickable.overlayMessage
|
||||
property bool highlighted
|
||||
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
font.bold: true
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
text: Emoji.emojify(rawMessage.content.game.title || "", font.pixelSize)
|
||||
truncationMode: TruncationMode.Fade
|
||||
textFormat: Text.StyledText
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: Emoji.emojify(rawMessage.content.game.description || "", font.pixelSize)
|
||||
truncationMode: TruncationMode.Fade
|
||||
textFormat: Text.StyledText
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: Emoji.emojify(Functions.enhanceMessageText(rawMessage.content.game.text) || "", font.pixelSize)
|
||||
truncationMode: TruncationMode.Fade
|
||||
wrapMode: Text.Wrap
|
||||
textFormat: Text.StyledText
|
||||
onLinkActivated: {
|
||||
var chatCommand = Functions.handleLink(link);
|
||||
if(chatCommand) {
|
||||
tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
Item {
|
||||
width: parent.width
|
||||
height: Theme.paddingLarge
|
||||
}
|
||||
|
||||
Image {
|
||||
id: thumbnail
|
||||
source: thumbnailFile.isDownloadingCompleted ? thumbnailFile.path : ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
width: visible ? parent.width : 0
|
||||
// height: width
|
||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
layer.enabled: queryResultItem.pressed
|
||||
layer.effect: PressEffect { source: thumbnail }
|
||||
|
||||
TDLibFile {
|
||||
id: thumbnailFile
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: true
|
||||
}
|
||||
Rectangle {
|
||||
width: Theme.iconSizeMedium
|
||||
height: width
|
||||
anchors {
|
||||
top: parent.top
|
||||
topMargin: Theme.paddingSmall
|
||||
left: parent.left
|
||||
leftMargin: Theme.paddingSmall
|
||||
}
|
||||
|
||||
color: Theme.rgba(Theme.overlayBackgroundColor, 0.2)
|
||||
radius: Theme.paddingSmall
|
||||
Icon {
|
||||
id: icon
|
||||
source: "image://theme/icon-m-game-controller"
|
||||
asynchronous: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (rawMessage.content.game.photo) {
|
||||
// Check first which size fits best...
|
||||
var photo
|
||||
for (var i = 0; i < rawMessage.content.game.photo.sizes.length; i++) {
|
||||
photo = rawMessage.content.game.photo.sizes[i].photo
|
||||
if (rawMessage.content.game.photo.sizes[i].width >= gamePreviewItem.width) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (photo) {
|
||||
thumbnailFile.fileInformation = photo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
431
qml/components/InlineQuery.qml
Normal file
431
qml/components/InlineQuery.qml
Normal file
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
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 "../js/debug.js" as Debug
|
||||
import "../js/twemoji.js" as Emoji
|
||||
import "../js/functions.js" as Functions
|
||||
|
||||
Loader {
|
||||
id: inlineQueryLoader
|
||||
active: userName.length > 1
|
||||
asynchronous: true
|
||||
anchors.fill: parent
|
||||
property bool hasOverlay: active && status === Loader.Ready && item.overlay && item.overlay.status === Loader.Ready
|
||||
property bool hasButton: active && status === Loader.Ready && item.button && item.button.status === Loader.Ready
|
||||
|
||||
property int buttonPadding: hasButton ? item.button.height + Theme.paddingSmall : 0
|
||||
Behavior on buttonPadding { NumberAnimation { duration: 200} }
|
||||
|
||||
property int chatId
|
||||
property string userName
|
||||
property string query
|
||||
property int currentOffset: 0
|
||||
property string responseExtra: chatId+"|"+userName+"|"+query+"|"+currentOffset
|
||||
|
||||
property bool queued: false
|
||||
property TextArea textField
|
||||
property bool isLoading
|
||||
onIsLoadingChanged: {
|
||||
requestTimeout.start();
|
||||
}
|
||||
|
||||
onStatusChanged: {
|
||||
inlineBotInformation = null;
|
||||
if(status === Loader.Ready && userName !== "") {
|
||||
isLoading = true;
|
||||
tdLibWrapper.searchPublicChat(userName, false);
|
||||
}
|
||||
}
|
||||
|
||||
onUserNameChanged: {
|
||||
inlineBotInformation = null;
|
||||
|
||||
if(status === Loader.Ready && userName !== "") {
|
||||
isLoading = true;
|
||||
tdLibWrapper.searchPublicChat(userName, false);
|
||||
}
|
||||
}
|
||||
|
||||
onQueryChanged: {
|
||||
if(userName.length > 0) {
|
||||
isLoading = true;
|
||||
requestTimer.start();
|
||||
}
|
||||
}
|
||||
property var inlineBotInformation: null
|
||||
|
||||
|
||||
function handleQuery(name, query, offset) {
|
||||
if(!name) {
|
||||
inlineQueryLoader.userName = "";
|
||||
inlineQueryLoader.query = "";
|
||||
return;
|
||||
}
|
||||
if(inlineQueryLoader.userName !== name) {
|
||||
inlineQueryLoader.userName = name
|
||||
}
|
||||
if(inlineQueryLoader.query !== query) {
|
||||
inlineQueryLoader.query = query
|
||||
}
|
||||
inlineQueryLoader.currentOffset = offset || 0
|
||||
}
|
||||
function request() {
|
||||
if(userName.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!inlineBotInformation) {
|
||||
queued = true;
|
||||
} else {
|
||||
queued = false;
|
||||
var location = null;
|
||||
if(inlineBotInformation.type.need_location && fernschreiberUtils.supportsGeoLocation()) {
|
||||
// TODO add location
|
||||
fernschreiberUtils.startGeoLocationUpdates();
|
||||
if(!attachmentPreviewRow.locationData.latitude) {
|
||||
queued = true;
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
tdLibWrapper.getInlineQueryResults(inlineBotInformation.id, chatId, location, query, inlineQueryLoader.currentOffset, inlineQueryLoader.responseExtra);
|
||||
isLoading = true;
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: requestTimeout
|
||||
interval: 5000
|
||||
onTriggered: {
|
||||
inlineQueryLoader.isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: requestTimer
|
||||
interval: 1000
|
||||
onTriggered: {
|
||||
request();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: fernschreiberUtils
|
||||
onNewPositionInformation: {
|
||||
attachmentPreviewRow.locationData = positionInformation;
|
||||
if (inlineQueryLoader.queued) {
|
||||
inlineQueryLoader.queued = false;
|
||||
inlineQueryLoader.request()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: textField
|
||||
onTextChanged: {
|
||||
if(textField.text.charAt(0) === '@') {
|
||||
var queryMatch = textField.text.match(/^@([a-zA-Z0-9_]+)\s(.*)/);
|
||||
if(queryMatch) {
|
||||
inlineQueryLoader.handleQuery(queryMatch[1], queryMatch[2]);
|
||||
} else {
|
||||
inlineQueryLoader.handleQuery();
|
||||
}
|
||||
} else {
|
||||
inlineQueryLoader.handleQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceComponent: Component {
|
||||
Item {
|
||||
id: inlineQueryComponent
|
||||
anchors.fill: parent
|
||||
property alias overlay: resultsOverlay
|
||||
property alias button: switchToPmLoader
|
||||
property string nextOffset
|
||||
property string inlineQueryId
|
||||
property string switchPmText
|
||||
property string switchPmParameter
|
||||
property ListModel resultModel: ListModel {
|
||||
dynamicRoles: true
|
||||
}
|
||||
|
||||
property string inlineQueryPlaceholder: inlineBotInformation ? inlineBotInformation.type.inline_query_placeholder : ""
|
||||
property bool showInlineQueryPlaceholder: !!inlineQueryPlaceholder && query === ""
|
||||
property string useDelegateSize: "default"
|
||||
property var dimensions: ({
|
||||
"default": [[Screen.width, Screen.height / 2], [Theme.itemSizeLarge, Theme.itemSizeLarge]], // whole line (portrait half)
|
||||
"inlineQueryResultAnimation": [[Screen.width / 3, Screen.height / 6], [Screen.width / 3, Screen.height / 6]],
|
||||
"inlineQueryResultVideo": [[Screen.width / 2, Screen.height / 4], [Theme.itemSizeLarge, Theme.itemSizeLarge]],
|
||||
"inlineQueryResultSticker": [[Screen.width / 3, Screen.height / 6], [Screen.width / 3, Screen.height / 6]],
|
||||
"inlineQueryResultPhoto": [[Screen.width/2, Screen.height / 3], [Theme.itemSizeExtraLarge, Theme.itemSizeExtraLarge]],
|
||||
})
|
||||
property int delegateWidth: chatPage.isPortrait ? dimensions[useDelegateSize][0][0] : dimensions[useDelegateSize][0][1]
|
||||
property int delegateHeight: chatPage.isPortrait ? dimensions[useDelegateSize][1][0] : dimensions[useDelegateSize][1][1]
|
||||
|
||||
function setDelegateSizes() {
|
||||
var sizeKey = "default";
|
||||
var modelCount = resultModel.count;
|
||||
if(modelCount > 0) {
|
||||
var firstType = resultModel.get(0)["@type"];
|
||||
if(firstType && dimensions[firstType]) {
|
||||
var startIndex = inlineQueryLoader.currentOffset === 0 ? 1 : inlineQueryLoader.currentOffset;
|
||||
var same = true;
|
||||
for(var i = startIndex; i < modelCount; i += 1) {
|
||||
if(resultModel.get(i)["@type"] !== firstType) {
|
||||
same = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(same) {
|
||||
sizeKey = firstType;
|
||||
}
|
||||
}
|
||||
}
|
||||
useDelegateSize = sizeKey;
|
||||
}
|
||||
function loadMore() {
|
||||
if(nextOffset) {
|
||||
inlineQueryLoader.currentOffset = nextOffset;
|
||||
inlineQueryLoader.request();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: tdLibWrapper
|
||||
|
||||
onChatReceived: {
|
||||
if(chat["@extra"] === "searchPublicChat:"+inlineQueryLoader.userName) {
|
||||
requestTimeout.stop();
|
||||
inlineQueryLoader.isLoading = false;
|
||||
var inlineBotInformation = tdLibWrapper.getUserInformation(chat.type.user_id);
|
||||
if(inlineBotInformation && inlineBotInformation.type["@type"] === "userTypeBot" && inlineBotInformation.type.is_inline) {
|
||||
inlineQueryLoader.inlineBotInformation = inlineBotInformation;
|
||||
requestTimer.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
onInlineQueryResults: {
|
||||
if(extra === inlineQueryLoader.responseExtra) {
|
||||
requestTimeout.stop();
|
||||
inlineQueryLoader.isLoading = false;
|
||||
inlineQueryComponent.inlineQueryId = inlineQueryId
|
||||
inlineQueryComponent.nextOffset = nextOffset
|
||||
inlineQueryComponent.switchPmText = switchPmText
|
||||
inlineQueryComponent.switchPmParameter = switchPmParameter
|
||||
|
||||
if(inlineQueryLoader.currentOffset === 0) {
|
||||
inlineQueryComponent.resultModel.clear()
|
||||
}
|
||||
for(var i = 0; i < results.length; i++) {
|
||||
inlineQueryComponent.resultModel.append(results[i]);
|
||||
}
|
||||
|
||||
if(inlineQueryLoader.currentOffset === 0 || inlineQueryLoader.useDelegateSize !== "default") {
|
||||
inlineQueryComponent.setDelegateSizes()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// switch to pm Button
|
||||
Loader {
|
||||
id: switchToPmLoader
|
||||
asynchronous: true
|
||||
active: inlineQueryComponent.switchPmText.length > 0
|
||||
opacity: status === Loader.Ready ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
// onActiveChanged: {
|
||||
// inlineQueryLoader.buttonPadding = active ? height + Theme.paddingSmall : 0
|
||||
// if(active) {
|
||||
// newMessageColumn.topPadding = Theme.itemSizeExtraSmall + Theme.paddingSmall
|
||||
// } else {
|
||||
|
||||
// newMessageColumn.topPadding = heme.paddingSmall
|
||||
// }
|
||||
// }
|
||||
|
||||
height: Theme.itemSizeSmall
|
||||
anchors {
|
||||
top: parent.bottom
|
||||
topMargin: Theme.paddingSmall
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
}
|
||||
|
||||
sourceComponent: Component {
|
||||
|
||||
MouseArea {
|
||||
id: customButton
|
||||
onClicked: {
|
||||
Debug.log("now we should switch to pm somehow ;) ooooor: ")
|
||||
tdLibWrapper.createPrivateChat(inlineQueryLoader.inlineBotInformation.id, "openAndSendStartToBot:"+(inlineQueryComponent.switchPmParameter.length > 0 ? " "+inlineQueryComponent.switchPmParameter:""));
|
||||
}
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.paddingSmall
|
||||
color: parent.pressed ? Theme.highlightBackgroundColor : Theme.rgba(Theme.DarkOnLight ? Qt.lighter(Theme.primaryColor) : Qt.darker(Theme.primaryColor), Theme.opacityFaint)
|
||||
Label {
|
||||
anchors {
|
||||
fill: parent
|
||||
leftMargin: Theme.paddingLarge
|
||||
rightMargin: Theme.paddingLarge
|
||||
}
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
fontSizeMode: Text.Fit;
|
||||
minimumPixelSize: Theme.fontSizeTiny;
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
||||
color: customButton.pressed ? Theme.highlightColor : Theme.primaryColor
|
||||
text: Emoji.emojify(inlineQueryComponent.switchPmText, font.pixelSize)// + "we are gonna make this a bit longer"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// results grid overlay
|
||||
Loader {
|
||||
id: resultsOverlay
|
||||
asynchronous: true
|
||||
active: inlineQueryComponent.resultModel.count > 0
|
||||
anchors.fill: parent
|
||||
opacity: !!item ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
property var supportedResultTypes: [
|
||||
"inlineQueryResultAnimation",
|
||||
"inlineQueryResultArticle",
|
||||
"inlineQueryResultAudio",
|
||||
"inlineQueryResultContact",
|
||||
"inlineQueryResultDocument",
|
||||
"inlineQueryResultGame",
|
||||
"inlineQueryResultLocation",
|
||||
"inlineQueryResultPhoto",
|
||||
"inlineQueryResultSticker",
|
||||
"inlineQueryResultVenue",
|
||||
"inlineQueryResultVideo",
|
||||
"inlineQueryResultVoiceNote",
|
||||
]
|
||||
sourceComponent: Component {
|
||||
Item {
|
||||
Rectangle {
|
||||
id: messageContentBackground
|
||||
color: Theme.overlayBackgroundColor
|
||||
opacity: 0.7
|
||||
anchors.fill: parent
|
||||
// MouseArea {
|
||||
// anchors.fill: parent
|
||||
// onClicked: {
|
||||
// // handleQuery();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
Timer {
|
||||
id: autoLoadMoreTimer
|
||||
interval: 400
|
||||
onTriggered: {
|
||||
if (inlineQueryComponent.nextOffset && resultView.height > resultView.contentHeight - Theme.itemSizeHuge) {
|
||||
inlineQueryComponent.loadMore();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SilicaGridView {
|
||||
id: resultView
|
||||
anchors.fill: parent
|
||||
cellWidth: inlineQueryComponent.delegateWidth
|
||||
cellHeight: inlineQueryComponent.delegateHeight
|
||||
|
||||
signal requestPlayback(url playbackSource)
|
||||
clip: true
|
||||
model: inlineQueryComponent.resultModel
|
||||
delegate: Loader {
|
||||
id: queryResultDelegate
|
||||
// asynchronous: true
|
||||
height: resultView.cellHeight
|
||||
width: resultView.cellWidth
|
||||
// TODO: if all are the same, use global?
|
||||
source: "inlineQueryResults/" + (resultsOverlay.supportedResultTypes.indexOf(model["@type"]) > -1 ? (model["@type"].charAt(0).toUpperCase() + model["@type"].substring(1)) : "InlineQueryResultDefaultBase") +".qml"
|
||||
// Component.onCompleted: {
|
||||
// Debug.log("delegate", source)
|
||||
// }
|
||||
}
|
||||
footer: Component {
|
||||
Item {
|
||||
width: resultView.width
|
||||
visible: height > 0
|
||||
height: inlineQueryComponent.nextOffset ? Theme.itemSizeLarge : 0
|
||||
Behavior on height { NumberAnimation { duration: 500 } }
|
||||
}
|
||||
}
|
||||
|
||||
onContentYChanged: {
|
||||
if(!inlineQueryLoader.isLoading && inlineQueryComponent.nextOffset && contentHeight - contentY - height < Theme.itemSizeHuge) {
|
||||
|
||||
inlineQueryComponent.loadMore();
|
||||
|
||||
}
|
||||
}
|
||||
ScrollDecorator { flickable: resultView }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// textarea placeholder
|
||||
Loader {
|
||||
asynchronous: true
|
||||
active: inlineQueryComponent.showInlineQueryPlaceholder
|
||||
// onActiveChanged: {
|
||||
// Debug.log("inline: placeholder active changed", active)
|
||||
// }
|
||||
|
||||
sourceComponent: Component {
|
||||
Label {
|
||||
text: Emoji.emojify(inlineQueryComponent.inlineQueryPlaceholder, font.pixelSize);
|
||||
parent: textField
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: textMetrics.boundingRect.width + Theme.paddingSmall
|
||||
font: textField.font
|
||||
color: Theme.secondaryColor
|
||||
|
||||
truncationMode: TruncationMode.Fade
|
||||
TextMetrics {
|
||||
id: textMetrics
|
||||
font: textField.font
|
||||
text: textField.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -35,6 +35,7 @@ Item {
|
|||
property var pictureFileInformation;
|
||||
width: parent.width
|
||||
height: width / 2
|
||||
property string fileExtra
|
||||
|
||||
Component.onCompleted: {
|
||||
updatePicture();
|
||||
|
@ -47,14 +48,18 @@ Item {
|
|||
function updatePicture() {
|
||||
imagePreviewItem.pictureFileInformation = null;
|
||||
if (locationData) {
|
||||
tdLibWrapper.getMapThumbnailFile(chatId, locationData.latitude, locationData.longitude, Math.round(imagePreviewItem.width), Math.round(imagePreviewItem.height));
|
||||
fileExtra = "location:" + locationData.latitude + ":" + locationData.longitude + ":" + Math.round(imagePreviewItem.width) + ":" + Math.round(imagePreviewItem.height);
|
||||
tdLibWrapper.getMapThumbnailFile(chatId, locationData.latitude, locationData.longitude, Math.round(imagePreviewItem.width), Math.round(imagePreviewItem.height), fileExtra);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: tdLibWrapper
|
||||
onFileUpdated: {
|
||||
// we do not have a way of knowing if this is the correct file, so we have to guess the first new one should be right.
|
||||
if(fileInformation["@extra"] !== imagePreviewItem.fileExtra) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(!imagePreviewItem.pictureFileInformation) {
|
||||
imagePreviewItem.pictureFileInformation = fileInformation;
|
||||
tdLibWrapper.downloadFile(imagePreviewItem.pictureFileInformation.id);
|
||||
|
|
|
@ -241,7 +241,7 @@ ListItem {
|
|||
anchors.fill: parent
|
||||
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
|
||||
onClicked: {
|
||||
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
|
||||
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,11 +299,15 @@ ListItem {
|
|||
anchors.fill: parent
|
||||
enabled: !(messageListItem.precalculatedValues.pageIsSelecting || messageListItem.isAnonymous)
|
||||
onClicked: {
|
||||
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id);
|
||||
tdLibWrapper.createPrivateChat(messageListItem.userInformation.id, "openDirectly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MessageViaLabel {
|
||||
message: myMessage
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: messageInReplyToLoader
|
||||
active: myMessage.reply_to_message_id !== 0
|
||||
|
|
|
@ -20,12 +20,14 @@ import QtQuick 2.6
|
|||
import Sailfish.Silica 1.0
|
||||
import "../js/twemoji.js" as Emoji
|
||||
import "../js/functions.js" as Functions
|
||||
import "../js/debug.js" as Debug
|
||||
|
||||
Item {
|
||||
id: messageListItem
|
||||
property var myMessage: display
|
||||
property var userInformation: tdLibWrapper.getUserInformation(myMessage.sender.user_id)
|
||||
property bool isOwnMessage: chatPage.myUserId === myMessage.sender.user_id
|
||||
property var linkedMessage
|
||||
height: backgroundRectangle.height + Theme.paddingMedium
|
||||
|
||||
Rectangle {
|
||||
|
@ -43,11 +45,40 @@ Item {
|
|||
color: Theme.highlightColor
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: "<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + messageListItem.userInformation.id + "\">" + (!messageListItem.isOwnMessage ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")) + "</a> " + Emoji.emojify(Functions.getMessageText(messageListItem.myMessage, false, chatPage.myUserId, false), font.pixelSize)
|
||||
property string messageContentText: Functions.getMessageText(messageListItem.myMessage, false, chatPage.myUserId, false)
|
||||
text: "<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + messageListItem.userInformation.id + "\">" + (!messageListItem.isOwnMessage ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")) + "</a> " + Emoji.emojify(messageContentText, font.pixelSize)
|
||||
textFormat: Text.RichText
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
onLinkActivated: {
|
||||
Functions.handleLink(link);
|
||||
if(link === "linkedmessage" && linkedMessage) {
|
||||
messageOverlayLoader.overlayMessage = linkedMessage;
|
||||
messageOverlayLoader.active = true;
|
||||
} else {
|
||||
Functions.handleLink(link);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: gameScoreInfoLoader
|
||||
active: myMessage.content["@type"] === "messageGameScore"
|
||||
asynchronous: true
|
||||
sourceComponent: Component {
|
||||
Connections {
|
||||
target: tdLibWrapper
|
||||
onReceivedMessage: {
|
||||
if(chatId === chatPage.chatInformation.id && messageId === myMessage.content.game_message_id) {
|
||||
messageListItem.linkedMessage = message;
|
||||
messageText.messageContentText = messageListItem.isOwnMessage ?
|
||||
qsTr("scored %Ln points in %2", "myself", myMessage.content.score).arg("<a href=\"linkedmessage\" style=\"text-decoration: none; color:"+Theme.primaryColor+"\">"+message.content.game.title+"</a>") :
|
||||
|
||||
qsTr("scored %Ln points in %2", "", myMessage.content.score).arg("<a href=\"linkedmessage\" style=\"text-decoration: none; color:"+Theme.primaryColor+"\" >"+message.content.game.title+"</a>");
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
tdLibWrapper.getMessage(chatPage.chatInformation.id, myMessage.content.game_message_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@
|
|||
*/
|
||||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
import "../components"
|
||||
import "../js/functions.js" as Functions
|
||||
import "../js/twemoji.js" as Emoji
|
||||
import "../js/debug.js" as Debug
|
||||
|
||||
Flickable {
|
||||
id: messageOverlayFlickable
|
||||
|
@ -124,6 +124,10 @@ Flickable {
|
|||
}
|
||||
}
|
||||
|
||||
MessageViaLabel {
|
||||
message: overlayMessage
|
||||
}
|
||||
|
||||
Text {
|
||||
id: overlayForwardedInfoText
|
||||
width: parent.width
|
||||
|
@ -179,6 +183,16 @@ Flickable {
|
|||
asynchronous: true
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: replyMarkupLoader
|
||||
property var myMessage: overlayMessage
|
||||
width: parent.width
|
||||
height: active ? (overlayMessage.reply_markup.rows.length * (Theme.itemSizeSmall + Theme.paddingSmall) - Theme.paddingSmall) : 0
|
||||
asynchronous: true
|
||||
active: !!overlayMessage.reply_markup && myMessage.reply_markup.rows
|
||||
source: Qt.resolvedUrl("ReplyMarkupButtons.qml")
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: messageDateUpdater
|
||||
interval: 60000
|
||||
|
|
49
qml/components/MessageViaLabel.qml
Normal file
49
qml/components/MessageViaLabel.qml
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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 "../js/functions.js" as Functions
|
||||
import "../js/twemoji.js" as Emoji
|
||||
|
||||
|
||||
Loader {
|
||||
id: botUserLoader
|
||||
active: !!message.via_bot_user_id
|
||||
width: parent.width
|
||||
asynchronous: true
|
||||
sourceComponent: Label {
|
||||
property var botUserInformation: tdLibWrapper.getUserInformation(message.via_bot_user_id)
|
||||
color: Theme.secondaryColor
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: qsTr("via %1", "message posted via bot user").arg("<a style=\"text-decoration: none; font-weight: bold; color:"+Theme.primaryColor+"\" href=\"userId://" + message.via_bot_user_id + "\">@" + Emoji.emojify(botUserInformation.username, font.pixelSize)+"</a>")
|
||||
textFormat: Text.RichText
|
||||
truncationMode: TruncationMode.Fade
|
||||
onLinkActivated: {
|
||||
if(link === "userId://" + message.via_bot_user_id && botUserInformation.type.is_inline) {
|
||||
newMessageTextField.text = "@"+botUserInformation.username+" "
|
||||
newMessageTextField.cursorPosition = newMessageTextField.text.length
|
||||
lostFocusTimer.start();
|
||||
}
|
||||
else {
|
||||
Functions.handleLink(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
property var message
|
||||
}
|
|
@ -23,6 +23,7 @@ import "../js/functions.js" as Functions
|
|||
import "../js/debug.js" as Debug
|
||||
|
||||
Column {
|
||||
id: replyMarkupButtons
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
spacing: Theme.paddingSmall
|
||||
|
@ -36,7 +37,7 @@ Column {
|
|||
Repeater {
|
||||
id: buttonsRepeater
|
||||
model: modelData
|
||||
property int itemWidth:precalculatedValues.textColumnWidth / count
|
||||
property int itemWidth: replyMarkupButtons.width / count
|
||||
delegate: MouseArea {
|
||||
/*
|
||||
Unimplemented callback types:
|
||||
|
@ -48,15 +49,35 @@ Column {
|
|||
*/
|
||||
property var callbacks: ({
|
||||
inlineKeyboardButtonTypeCallback: function(){
|
||||
tdLibWrapper.getCallbackQueryAnswer(messageListItem.chatId, messageListItem.messageId, {data: modelData.type.data, "@type": "callbackQueryPayloadData"})
|
||||
tdLibWrapper.getCallbackQueryAnswer(myMessage.chat_id, myMessage.id, {data: modelData.type.data, "@type": "callbackQueryPayloadData"})
|
||||
},
|
||||
|
||||
inlineKeyboardButtonTypeCallbackGame: function(){
|
||||
tdLibWrapper.getCallbackQueryAnswer(myMessage.chat_id, myMessage.id, {game_short_name: myMessage.content.game.short_name, "@type": "callbackQueryPayloadGame"})
|
||||
},
|
||||
inlineKeyboardButtonTypeUrl: function() {
|
||||
Functions.handleLink(modelData.type.url);
|
||||
},
|
||||
inlineKeyboardButtonTypeSwitchInline: function() {
|
||||
if(modelData.type.in_current_chat) {
|
||||
chatPage.setMessageText("@" + userInformation.username + " "+(modelData.type.query || ""))
|
||||
} else {
|
||||
|
||||
pageStack.push(Qt.resolvedUrl("../pages/ChatSelectionPage.qml"), {
|
||||
myUserId: chatPage.myUserId,
|
||||
payload: { neededPermissions: ["can_send_other_messages"], text:"@" + userInformation.username + " "+(modelData.type.query || "")},
|
||||
state: "fillTextArea"
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
keyboardButtonTypeText: function() {
|
||||
chatPage.setMessageText(modelData.text, true);
|
||||
}
|
||||
})
|
||||
enabled: !!callbacks[modelData.type["@type"]]
|
||||
height: Theme.itemSizeSmall
|
||||
width: (precalculatedValues.textColumnWidth + Theme.paddingSmall) / buttonsRepeater.count - (Theme.paddingSmall)
|
||||
width: (replyMarkupButtons.width + Theme.paddingSmall) / buttonsRepeater.count - (Theme.paddingSmall)
|
||||
onClicked: {
|
||||
callbacks[modelData.type["@type"]]();
|
||||
}
|
||||
|
@ -71,17 +92,18 @@ Column {
|
|||
width: Math.min(parent.width - Theme.paddingSmall*2, contentWidth)
|
||||
truncationMode: TruncationMode.Fade
|
||||
text: Emoji.emojify(modelData.text, Theme.fontSizeSmall)
|
||||
color: parent.pressed ? Theme.highlightColor : Theme.primaryColor
|
||||
color: parent.parent.pressed ? Theme.highlightColor : Theme.primaryColor
|
||||
anchors.centerIn: parent
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
}
|
||||
Icon {
|
||||
property var sources: ({
|
||||
inlineKeyboardButtonTypeUrl: "../../images/icon-s-link.svg",
|
||||
inlineKeyboardButtonTypeSwitchInline: "image://theme/icon-s-repost",
|
||||
inlineKeyboardButtonTypeSwitchInline: !modelData.type.in_current_chat ? "image://theme/icon-s-repost" : "image://theme/icon-s-edit",
|
||||
inlineKeyboardButtonTypeCallbackWithPassword: "image://theme/icon-s-asterisk"
|
||||
})
|
||||
visible: !!sources[modelData.type["@type"]]
|
||||
opacity: 0.6
|
||||
source: sources[modelData.type["@type"]] || ""
|
||||
sourceSize: Qt.size(Theme.iconSizeSmall, Theme.iconSizeSmall)
|
||||
highlighted: parent.pressed
|
||||
|
|
|
@ -232,7 +232,7 @@ SilicaFlickable {
|
|||
MenuItem {
|
||||
visible: chatInformationPage.isPrivateChat
|
||||
onClicked: {
|
||||
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId);
|
||||
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId, "openDirectly");
|
||||
}
|
||||
text: qsTr("New Secret Chat")
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ ChatInformationTabItemBase {
|
|||
}
|
||||
|
||||
onClicked: {
|
||||
tdLibWrapper.createPrivateChat(user_id);
|
||||
tdLibWrapper.createPrivateChat(user_id, "openDirectly");
|
||||
}
|
||||
}
|
||||
footer: Component {
|
||||
|
|
33
qml/components/inlineQueryResults/InlineQueryResult.qml
Normal file
33
qml/components/inlineQueryResults/InlineQueryResult.qml
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
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
|
||||
|
||||
BackgroundItem {
|
||||
id: queryResultItem
|
||||
|
||||
function sendInlineQueryResultMessage() {
|
||||
tdLibWrapper.sendInlineQueryResultMessage(inlineQueryLoader.chatId, 0, 0, inlineQueryComponent.inlineQueryId, model.id);
|
||||
inlineQueryLoader.textField.text = "";
|
||||
}
|
||||
onClicked: {
|
||||
sendInlineQueryResultMessage()
|
||||
}
|
||||
|
||||
}
|
291
qml/components/inlineQueryResults/InlineQueryResultAnimation.qml
Normal file
291
qml/components/inlineQueryResults/InlineQueryResultAnimation.qml
Normal file
|
@ -0,0 +1,291 @@
|
|||
/*
|
||||
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 QtMultimedia 5.6
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
import QtGraphicalEffects 1.0
|
||||
import Nemo.Thumbnailer 1.0
|
||||
import "../"
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
import "../../js/debug.js" as Debug
|
||||
|
||||
InlineQueryResult {
|
||||
id: queryResultItem
|
||||
property bool isAnimation: true
|
||||
property bool loopPreview: isAnimation
|
||||
property bool mutePreview: isAnimation
|
||||
enabled: false // don't send on click
|
||||
layer.enabled: mouseArea.pressed
|
||||
layer.effect: PressEffect { source: queryResultItem }
|
||||
|
||||
property string animationKey: "animation"
|
||||
property bool hasThumbnail: !!model[queryResultItem.animationKey].thumbnail
|
||||
|
||||
property string videoMimeType: "video/mp4"
|
||||
|
||||
TDLibFile {
|
||||
id: file
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: true
|
||||
fileInformation: hasThumbnail ? model[queryResultItem.animationKey].thumbnail.file : (queryResultItem.isAnimation ? model[queryResultItem.animationKey].animation : model[queryResultItem.animationKey].video)
|
||||
}
|
||||
|
||||
Image {
|
||||
id: miniThumbnail
|
||||
asynchronous: true
|
||||
source: model[queryResultItem.animationKey].minithumbnail ? "data:image/jpg;base64,"+model[queryResultItem.animationKey].minithumbnail.data : ""
|
||||
anchors.fill: parent
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
layer.enabled: queryResultItem.pressed
|
||||
layer.effect: PressEffect { source: miniThumbnail }
|
||||
}
|
||||
Component {
|
||||
id: videoThumbnail
|
||||
Thumbnail {
|
||||
id: thumbnail
|
||||
source: file.path
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
mimeType: queryResultItem.videoMimeType
|
||||
layer.enabled: queryResultItem.pressed
|
||||
layer.effect: PressEffect { source: thumbnail }
|
||||
opacity: status === Thumbnail.Ready ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: imageThumbnail
|
||||
Image {
|
||||
id: thumbnail
|
||||
source: file.path
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
layer.enabled: queryResultItem.pressed
|
||||
layer.effect: PressEffect { source: thumbnail }
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
onStatusChanged: {
|
||||
// we don't get many hints what may be wrong, so we guess it may be a webp image ;)
|
||||
if(status === Image.Error) {
|
||||
Debug.log("Inline Query Video: Thumbnail invalid. Blindly trying webp, which might work.")
|
||||
queryResultItem.videoMimeType = "image/webp";
|
||||
thumbnailLoader.sourceComponent = videoThumbnail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
id: thumbnailLoader
|
||||
asynchronous: true
|
||||
active: file.isDownloadingCompleted
|
||||
anchors.fill: parent
|
||||
sourceComponent: queryResultItem.hasThumbnail ? (model[queryResultItem.animationKey].thumbnail.format["@type"] === "thumbnailFormatMpeg4" ? videoThumbnail : imageThumbnail) : model[queryResultItem.animationKey].mime_type === "video/mp4" ? videoThumbnail : imageThumbnail
|
||||
}
|
||||
Column {
|
||||
id: texts
|
||||
anchors {
|
||||
left: parent.left
|
||||
margins: Theme.paddingSmall
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
visible: text.length > 0
|
||||
text: Emoji.emojify(model.title || "", font.pixelSize);
|
||||
}
|
||||
Label {
|
||||
id: descriptionLabel
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.Wrap
|
||||
visible: text.length > 0
|
||||
text: Emoji.emojify(model.description || "", font.pixelSize);
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: texts
|
||||
asynchronous: true
|
||||
active: titleLabel.visible || descriptionLabel.visible
|
||||
sourceComponent: Component {
|
||||
DropShadow {
|
||||
horizontalOffset: 0
|
||||
verticalOffset: 0
|
||||
radius: Theme.paddingSmall
|
||||
spread: 0.5
|
||||
samples: 17
|
||||
color: Theme.overlayBackgroundColor
|
||||
source: texts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
// dialog
|
||||
|
||||
var dialog = pageStack.push(dialogComponent,{})
|
||||
dialog.accepted.connect(function() {
|
||||
queryResultItem.sendInlineQueryResultMessage();
|
||||
})
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: dialogComponent
|
||||
Dialog {
|
||||
|
||||
TDLibFile {
|
||||
id: previewFile
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: model[queryResultItem.animationKey].mime_type !== "text/html"
|
||||
fileInformation: queryResultItem.isAnimation ? model[queryResultItem.animationKey].animation : model[queryResultItem.animationKey].video
|
||||
}
|
||||
|
||||
DialogHeader { id: dialogHeader }
|
||||
|
||||
ProgressCircle {
|
||||
value: previewFile.downloadedSize / previewFile.expectedSize
|
||||
width: Theme.iconSizeMedium
|
||||
height: Theme.iconSizeMedium
|
||||
anchors.centerIn: parent
|
||||
opacity: previewFile.isDownloadingActive ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
Column {
|
||||
visible: !previewFile.autoLoad
|
||||
spacing: Theme.paddingLarge
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Theme.secondaryHighlightColor
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: Emoji.emojify(model.title || "", font.pixelSize);
|
||||
visible: text.length > 1
|
||||
linkColor: Theme.primaryColor
|
||||
}
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Theme.highlightColor
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: '<a href="'+Emoji.emojify(previewFile.fileInformation.remote.id, font.pixelSize)+'">'+Emoji.emojify(previewFile.fileInformation.remote.id, font.pixelSize)+'</a> '
|
||||
linkColor: Theme.primaryColor
|
||||
}
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
color: Theme.secondaryHighlightColor
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: Emoji.emojify(model.description || "", font.pixelSize)
|
||||
visible: text.length > 1
|
||||
linkColor: Theme.secondaryColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loader {
|
||||
id: videoLoader
|
||||
anchors {
|
||||
top: dialogHeader.bottom
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
active: previewFile.isDownloadingCompleted
|
||||
asynchronous: true
|
||||
sourceComponent: Component {
|
||||
Item {
|
||||
Connections {
|
||||
target: resultView
|
||||
onRequestPlayback: {
|
||||
if(previewVideo.playbackState === MediaPlayer.PlayingState && previewVideo.source !== playbackSource) {
|
||||
previewVideo.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
Timer {
|
||||
id: loopTimer
|
||||
interval: 0
|
||||
onTriggered: previewVideo.play()
|
||||
}
|
||||
|
||||
Video {
|
||||
id: previewVideo
|
||||
source: previewFile.path
|
||||
autoPlay: true
|
||||
muted: queryResultItem.mutePreview
|
||||
anchors.fill: parent
|
||||
|
||||
onStatusChanged: {
|
||||
if (status == MediaPlayer.EndOfMedia) {
|
||||
if(queryResultItem.loopPreview) {
|
||||
loopTimer.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
onPlaybackStateChanged: {
|
||||
if(playbackState === MediaPlayer.PlayingState) {
|
||||
resultView.requestPlayback(source);
|
||||
}
|
||||
}
|
||||
layer.enabled: playPauseMouseArea.pressed
|
||||
layer.effect: PressEffect { source: previewVideo }
|
||||
}
|
||||
MouseArea {
|
||||
id: playPauseMouseArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
if(previewVideo.playbackState === MediaPlayer.PlayingState) {
|
||||
previewVideo.pause();
|
||||
} else {
|
||||
previewVideo.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
InlineQueryResultDefaultBase {
|
||||
id: queryResultItem
|
||||
|
||||
title: Emoji.emojify(model.title || "", titleLable.font.pixelSize)
|
||||
description: Emoji.emojify(model.description || "", descriptionLabel.font.pixelSize)
|
||||
descriptionLabel {
|
||||
maximumLineCount: 3
|
||||
wrapMode: extraText.length === 0 ? Text.Wrap : Text.NoWrap
|
||||
}
|
||||
|
||||
extraText: model.url || ""
|
||||
extraTextLabel.visible: !model.hide_url && extraText.length > 0
|
||||
|
||||
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
|
||||
|
||||
icon.source: "image://theme/icon-m-link"
|
||||
icon.visible: thumbnail.visible && thumbnail.opacity === 0
|
||||
|
||||
thumbnail.visible: model.thumbnail || !!model.url
|
||||
}
|
183
qml/components/inlineQueryResults/InlineQueryResultAudio.qml
Normal file
183
qml/components/inlineQueryResults/InlineQueryResultAudio.qml
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
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 QtMultimedia 5.6
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
import "../"
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
InlineQueryResult {
|
||||
id: queryResultItem
|
||||
property var resultData: model.audio || model.voice_note
|
||||
property var audioData: resultData.audio || resultData.voice
|
||||
|
||||
enabled: false // don't send on click
|
||||
|
||||
Connections {
|
||||
target: resultView
|
||||
onRequestPlayback: {
|
||||
if(audioPlayer.playbackState === Audio.PlayingState && audioPlayer.source !== playbackSource) {
|
||||
audioPlayer.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TDLibFile {
|
||||
id: file
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: false
|
||||
fileInformation: queryResultItem.audioData
|
||||
}
|
||||
|
||||
TDLibFile {
|
||||
id: thumbnail
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: true
|
||||
fileInformation: queryResultItem.resultData.album_cover_thumbnail ? queryResultItem.resultData.album_cover_thumbnail.file : {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: thumbnailLoader
|
||||
asynchronous: true
|
||||
active: thumbnail.isDownloadingCompleted
|
||||
height: parent.height
|
||||
width: height
|
||||
opacity: item && item.status === Image.Ready ? 0.5 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
sourceComponent: Component {
|
||||
Image {
|
||||
id: thumbnailImage
|
||||
source: thumbnail.path
|
||||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
|
||||
layer.enabled: playPauseButton.pressed
|
||||
layer.effect: PressEffect { source: thumbnailImage }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: playPauseButton
|
||||
anchors.centerIn: thumbnailLoader
|
||||
icon {
|
||||
asynchronous: true
|
||||
source: audioPlayer.playbackState === Audio.PlayingState || (file.isDownloadingActive && audioPlayer.autoPlay) ? "image://theme/icon-m-pause": "image://theme/icon-m-play"
|
||||
}
|
||||
onClicked: {
|
||||
if(!file.isDownloadingCompleted && !file.isDownloadingActive) {
|
||||
file.load();
|
||||
audioPlayer.autoPlay = true
|
||||
} else if(file.isDownloadingActive) {
|
||||
// cancel playback intent?
|
||||
audioPlayer.autoPlay = false
|
||||
} else if(file.isDownloadingCompleted) {
|
||||
//playPause
|
||||
if(audioPlayer.playbackState === Audio.PlayingState) {
|
||||
audioPlayer.pause();
|
||||
} else {
|
||||
audioPlayer.play();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ProgressCircle {
|
||||
value: file.downloadedSize / file.expectedSize
|
||||
width: Theme.iconSizeMedium
|
||||
height: Theme.iconSizeMedium
|
||||
anchors.centerIn: playPauseButton
|
||||
opacity: file.isDownloadingActive ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
Audio {
|
||||
id: audioPlayer
|
||||
source: file.isDownloadingCompleted ? file.path : ""
|
||||
autoPlay: false
|
||||
onPlaybackStateChanged: {
|
||||
if(playbackState === Audio.PlayingState) {
|
||||
resultView.requestPlayback(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors {
|
||||
left: thumbnailLoader.right
|
||||
leftMargin: Theme.paddingSmall
|
||||
right: sendButton.left
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.highlightColor
|
||||
text: Emoji.emojify(queryResultItem.resultData.performer || "", font.pixelSize)
|
||||
visible: text.length > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
Label {
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: Theme.secondaryHighlightColor
|
||||
text: Emoji.emojify(queryResultItem.resultData.title || model.title || "", font.pixelSize)
|
||||
visible: text.length > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
Item {
|
||||
height: sizeLabel.height
|
||||
width: parent.width
|
||||
Label {
|
||||
id: durationLabel
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: Theme.secondaryColor
|
||||
text: (audioPlayer.position > 0 || audioPlayer.playbackState === Audio.PlayingState ? (Format.formatDuration(audioPlayer.position/1000, Formatter.DurationShort)+" / ") : "") + Format.formatDuration(queryResultItem.audioData.duration || (audioPlayer.duration/1000), Formatter.DurationShort)
|
||||
visible: (queryResultItem.audioData.duration || (audioPlayer.duration/1000)) > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
Label {
|
||||
id: sizeLabel
|
||||
anchors.right: parent.right
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: Theme.secondaryColor
|
||||
text: Format.formatFileSize(file.expectedSize)
|
||||
visible: file.expectedSize > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconButton {
|
||||
id: sendButton
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
icon {
|
||||
asynchronous: true
|
||||
source: "image://theme/icon-m-send"
|
||||
}
|
||||
onClicked: {
|
||||
queryResultItem.sendInlineQueryResultMessage();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
InlineQueryResultDefaultBase {
|
||||
id: queryResultItem
|
||||
property string namesSeparator: model.contact.first_name && model.contact.last_name ? " " : ""
|
||||
|
||||
title: Emoji.emojify(model.contact.first_name + namesSeparator + model.contact.last_name || "", titleLable.font.pixelSize)
|
||||
description: Emoji.emojify(model.contact.phone_number || "", descriptionLabel.font.pixelSize)
|
||||
|
||||
extraText: model.url || ""
|
||||
extraTextLabel.visible: !model.hide_url && extraText.length > 0
|
||||
|
||||
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
|
||||
|
||||
icon.source: "image://theme/icon-m-contact"
|
||||
icon.visible: thumbnail.visible && thumbnail.opacity === 0
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../"
|
||||
|
||||
InlineQueryResult {
|
||||
id: queryResultItem
|
||||
|
||||
property alias title: titleLabel.text
|
||||
property alias titleLable: titleLabel
|
||||
|
||||
property alias description: descriptionLabel.text
|
||||
property alias descriptionLabel: descriptionLabel
|
||||
|
||||
property alias extraText: extraTextLabel.text
|
||||
property alias extraTextLabel: extraTextLabel
|
||||
|
||||
property alias thumbnailFileInformation: thumbnailFile.fileInformation
|
||||
property alias thumbnail: thumbnail
|
||||
|
||||
property alias icon: icon
|
||||
|
||||
|
||||
Image {
|
||||
id: thumbnail
|
||||
source: thumbnailFile.isDownloadingCompleted ? thumbnailFile.path : ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
asynchronous: true
|
||||
width: visible ? Theme.itemSizeLarge : 0
|
||||
height: width
|
||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
layer.enabled: queryResultItem.pressed
|
||||
layer.effect: PressEffect { source: thumbnail }
|
||||
|
||||
TDLibFile {
|
||||
id: thumbnailFile
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: true
|
||||
}
|
||||
}
|
||||
Icon {
|
||||
id: icon
|
||||
asynchronous: true
|
||||
anchors.centerIn: thumbnail
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors {
|
||||
left: thumbnail.right
|
||||
leftMargin: thumbnail.visible ? Theme.paddingLarge : Theme.horizontalPageMargin
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: highlighted || !queryResultItem.enabled ? Theme.highlightColor : Theme.primaryColor
|
||||
visible: text.length > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
Label {
|
||||
id: descriptionLabel
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: highlighted || !queryResultItem.enabled ? Theme.secondaryColor : Theme.secondaryHighlightColor
|
||||
visible: text.length > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
|
||||
Label {
|
||||
id: extraTextLabel
|
||||
width: parent.width
|
||||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: highlighted || !queryResultItem.enabled ? Theme.secondaryHighlightColor : Theme.secondaryColor
|
||||
visible: text.length > 0
|
||||
truncationMode: TruncationMode.Fade
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../"
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
Loader {
|
||||
Component {
|
||||
id: documentComponent
|
||||
InlineQueryResultDefaultBase {
|
||||
id: queryResultItem
|
||||
|
||||
title: Emoji.emojify(model.title || model.document.file_name || "", titleLable.font.pixelSize)
|
||||
description: Emoji.emojify(model.description || model.document.file_name || "", descriptionLabel.font.pixelSize)
|
||||
extraText: Format.formatFileSize(model.document.document.expected_size)
|
||||
|
||||
thumbnailFileInformation: model.thumbnail ? model.thumbnail.file : {}
|
||||
|
||||
icon.source: Theme.iconForMimeType(model.document.mime_type)
|
||||
icon.visible: thumbnail.visible && thumbnail.opacity === 0
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: voiceNoteDocumentComponent
|
||||
InlineQueryResultVoiceNote {
|
||||
resultData: model.document
|
||||
audioData: model.document.document
|
||||
}
|
||||
}
|
||||
sourceComponent: model.document.mime_type === "audio/ogg" ? voiceNoteDocumentComponent : documentComponent
|
||||
}
|
53
qml/components/inlineQueryResults/InlineQueryResultGame.qml
Normal file
53
qml/components/inlineQueryResults/InlineQueryResultGame.qml
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
InlineQueryResultDefaultBase {
|
||||
id: queryResultItem
|
||||
|
||||
title: Emoji.emojify(model.game.title || "", titleLable.font.pixelSize)
|
||||
description: Emoji.emojify(model.game.description || "", descriptionLabel.font.pixelSize)
|
||||
descriptionLabel {
|
||||
maximumLineCount: 3
|
||||
wrapMode: Text.Wrap
|
||||
}
|
||||
|
||||
icon.source: "image://theme/icon-m-game-controller"
|
||||
icon.visible: thumbnail.opacity === 0
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
if (model.game.photo) {
|
||||
// Check first which size fits best...
|
||||
var photo
|
||||
for (var i = 0; i < model.game.photo.sizes.length; i++) {
|
||||
photo = model.game.photo.sizes[i].photo
|
||||
if (model.game.photo.sizes[i].width >= queryResultItem.width) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (photo) {
|
||||
thumbnailFileInformation = photo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
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
|
||||
|
||||
InlineQueryResultVenue {
|
||||
resultData: model
|
||||
}
|
67
qml/components/inlineQueryResults/InlineQueryResultPhoto.qml
Normal file
67
qml/components/inlineQueryResults/InlineQueryResultPhoto.qml
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
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 QtMultimedia 5.6
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
|
||||
InlineQueryResult {
|
||||
id: queryResultItem
|
||||
|
||||
|
||||
TDLibFile {
|
||||
id: file
|
||||
tdlib: tdLibWrapper
|
||||
autoLoad: true
|
||||
}
|
||||
|
||||
Loader {
|
||||
asynchronous: true
|
||||
active: file.isDownloadingCompleted
|
||||
anchors.fill: parent
|
||||
opacity: item && item.status === Image.Ready ? 1.0 : 0.0
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
qml/components/inlineQueryResults/InlineQueryResultSticker.qml
Normal file
106
qml/components/inlineQueryResults/InlineQueryResultSticker.qml
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import Nemo.Thumbnailer 1.0
|
||||
import "../"
|
||||
|
||||
InlineQueryResult {
|
||||
id: queryResultItem
|
||||
|
||||
property bool animate
|
||||
property bool animating: animate && model.sticker.is_animated
|
||||
property url stickerId: "http://sticker/" + model.sticker.sticker.remote.id
|
||||
onAnimatingChanged: {
|
||||
if(animating) {
|
||||
resultView.requestPlayback(stickerId);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: resultView
|
||||
onRequestPlayback: {
|
||||
if(queryResultItem.animating && queryResultItem.stickerId !== playbackSource) {
|
||||
animate = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPressAndHold: {
|
||||
animate = !animate
|
||||
}
|
||||
|
||||
TDLibFile {
|
||||
id: file
|
||||
tdlib: tdLibWrapper
|
||||
fileInformation: model.sticker.sticker
|
||||
autoLoad: true
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: animatedStickerLoader
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: Theme.paddingLarge
|
||||
}
|
||||
active: queryResultItem.animating
|
||||
sourceComponent: Component {
|
||||
AnimatedImage {
|
||||
id: animatedSticker
|
||||
anchors.fill: parent
|
||||
source: file.path
|
||||
asynchronous: true
|
||||
paused: !Qt.application.active
|
||||
cache: false
|
||||
layer.enabled: highlighted
|
||||
layer.effect: PressEffect { source: animatedSticker }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: staticSticker
|
||||
anchors {
|
||||
fill: parent
|
||||
margins: Theme.paddingLarge
|
||||
}
|
||||
source: file.path
|
||||
fillMode: Image.PreserveAspectFit
|
||||
autoTransform: true
|
||||
asynchronous: true
|
||||
visible: !queryResultItem.animating && opacity > 0
|
||||
opacity: status === Image.Ready ? 1 : 0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
layer.enabled: queryResultItem.highlighted
|
||||
layer.effect: PressEffect { source: staticSticker }
|
||||
}
|
||||
|
||||
Icon {
|
||||
source: "image://theme/icon-m-video"
|
||||
width: Theme.iconSizeExtraSmall
|
||||
height: width
|
||||
visible: model.sticker.is_animated
|
||||
highlighted: queryResultItem.highlighted || queryResultItem.animating
|
||||
anchors {
|
||||
right: parent.right
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
}
|
51
qml/components/inlineQueryResults/InlineQueryResultVenue.qml
Normal file
51
qml/components/inlineQueryResults/InlineQueryResultVenue.qml
Normal file
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
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 WerkWolf.Fernschreiber 1.0
|
||||
import "../../js/twemoji.js" as Emoji
|
||||
|
||||
InlineQueryResultDefaultBase {
|
||||
id: queryResultItem
|
||||
property string locationId
|
||||
property var resultData: model.venue
|
||||
|
||||
title: Emoji.emojify(queryResultItem.resultData.title || (queryResultItem.resultData.location.latitude + ":" + queryResultItem.resultData.location.longitude), titleLable.font.pixelSize)
|
||||
description: Emoji.emojify(queryResultItem.resultData.address || "", descriptionLabel.font.pixelSize)
|
||||
extraText: Emoji.emojify(queryResultItem.resultData.type || "", extraTextLabel.font.pixelSize)
|
||||
|
||||
|
||||
Connections {
|
||||
target: tdLibWrapper
|
||||
onFileUpdated: {
|
||||
if(fileInformation["@extra"] === queryResultItem.locationId) {
|
||||
thumbnailFileInformation = fileInformation
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var dimensions = [ Math.round(thumbnail.width), Math.round(thumbnail.height)];
|
||||
|
||||
locationId = "location:" + resultData.location.latitude + ":" + resultData.location.longitude + ":" + dimensions[0] + ":" + dimensions[1];
|
||||
|
||||
tdLibWrapper.getMapThumbnailFile(chatId, resultData.location.latitude, resultData.location.longitude, dimensions[0], dimensions[1], locationId);
|
||||
}
|
||||
}
|
25
qml/components/inlineQueryResults/InlineQueryResultVideo.qml
Normal file
25
qml/components/inlineQueryResults/InlineQueryResultVideo.qml
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
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
|
||||
|
||||
InlineQueryResultAnimation {
|
||||
isAnimation: false
|
||||
animationKey: "video"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
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
|
||||
|
||||
InlineQueryResultAudio {
|
||||
|
||||
}
|
|
@ -145,6 +145,10 @@ function getMessageText(message, simple, currentUserId, ignoreEntities) {
|
|||
return myself ? qsTr("sent a self-destructing video that is expired", "myself") : qsTr("sent a self-destructing video that is expired");
|
||||
case 'messageScreenshotTaken':
|
||||
return myself ? qsTr("created a screenshot in this chat", "myself") : qsTr("created a screenshot in this chat");
|
||||
case 'messageGame':
|
||||
return simple ? (myself ? qsTr("sent a game", "myself") : qsTr("sent a game")) : "";
|
||||
case 'messageGameScore':
|
||||
return myself ? qsTr("scored %Ln points", "myself", message.content.score) : qsTr("scored %Ln points", "myself", message.content.score);
|
||||
case 'messageUnsupported':
|
||||
return myself ? qsTr("sent an unsupported message", "myself") : qsTr("sent an unsupported message");
|
||||
default:
|
||||
|
@ -361,16 +365,16 @@ function handleLink(link) {
|
|||
if (typeof userInformation.id === "undefined") {
|
||||
appNotification.show(qsTr("Unable to find user %1").arg(userName));
|
||||
} else {
|
||||
tdLibWrapper.createPrivateChat(userInformation.id);
|
||||
tdLibWrapper.createPrivateChat(userInformation.id, "openDirectly");
|
||||
}
|
||||
} else if (link.indexOf("userId://") === 0) {
|
||||
tdLibWrapper.createPrivateChat(link.substring(9));
|
||||
tdLibWrapper.createPrivateChat(link.substring(9), "openDirectly");
|
||||
} else if (link.indexOf("tg://") === 0) {
|
||||
Debug.log("Special TG link: ", link);
|
||||
if (link.indexOf("tg://join?invite=") === 0) {
|
||||
tdLibWrapper.joinChatByInviteLink(tMePrefix + "joinchat/" + link.substring(17));
|
||||
} else if (link.indexOf("tg://resolve?domain=") === 0) {
|
||||
tdLibWrapper.searchPublicChat(link.substring(20));
|
||||
tdLibWrapper.searchPublicChat(link.substring(20), true);
|
||||
}
|
||||
} else if (link.indexOf("botCommand://") === 0) { // this gets returned to send on ChatPage
|
||||
return link.substring(13);
|
||||
|
@ -383,7 +387,7 @@ function handleLink(link) {
|
|||
// Fail with nice error message if it doesn't work
|
||||
} else {
|
||||
Debug.log("Search public chat: ", link.substring(tMePrefix.length));
|
||||
tdLibWrapper.searchPublicChat(link.substring(tMePrefix.length));
|
||||
tdLibWrapper.searchPublicChat(link.substring(tMePrefix.length), true);
|
||||
// Check responses for updateBasicGroup or updateSupergroup
|
||||
// Fire createBasicGroupChat or createSupergroupChat
|
||||
// Do the necessary stuff to open the chat
|
||||
|
|
|
@ -45,6 +45,7 @@ Page {
|
|||
property bool isSuperGroup: false;
|
||||
property bool isChannel: false;
|
||||
property var chatPartnerInformation;
|
||||
property var botInformation;
|
||||
property var chatGroupInformation;
|
||||
property int chatOnlineMemberCount: 0;
|
||||
property var emojiProposals;
|
||||
|
@ -59,6 +60,8 @@ Page {
|
|||
property var selectedMessages: []
|
||||
readonly property bool isSelecting: selectedMessages.length > 0
|
||||
readonly property bool canSendMessages: hasSendPrivilege("can_send_messages")
|
||||
property bool doSendBotStartMessage
|
||||
property string sendBotStartMessageParameter
|
||||
|
||||
states: [
|
||||
State {
|
||||
|
@ -154,6 +157,9 @@ Page {
|
|||
if (isSecretChat) {
|
||||
tdLibWrapper.getSecretChat(chatInformation.type.secret_chat_id);
|
||||
}
|
||||
if(chatPartnerInformation.type["@type"] === "userTypeBot") {
|
||||
tdLibWrapper.getUserFullInfo(chatPartnerInformation.id)
|
||||
}
|
||||
}
|
||||
else if (isBasicGroup) {
|
||||
chatGroupInformation = tdLibWrapper.getBasicGroup(chatInformation.type.basic_group_id);
|
||||
|
@ -172,6 +178,7 @@ Page {
|
|||
}
|
||||
tdLibWrapper.getChatPinnedMessage(chatInformation.id);
|
||||
tdLibWrapper.toggleChatIsMarkedAsUnread(chatInformation.id, false);
|
||||
|
||||
}
|
||||
|
||||
function getMessageStatusText(message, listItemIndex, lastReadSentIndex, useElapsed) {
|
||||
|
@ -207,14 +214,13 @@ Page {
|
|||
}
|
||||
|
||||
function clearAttachmentPreviewRow() {
|
||||
attachmentPreviewRow.visible = false;
|
||||
attachmentPreviewRow.isPicture = false;
|
||||
attachmentPreviewRow.isVideo = false;
|
||||
attachmentPreviewRow.isDocument = false;
|
||||
attachmentPreviewRow.isVoiceNote = false;
|
||||
attachmentPreviewRow.isLocation = false;
|
||||
attachmentPreviewRow.fileProperties = {};
|
||||
attachmentPreviewRow.locationData = {};
|
||||
attachmentPreviewRow.fileProperties = null;
|
||||
attachmentPreviewRow.locationData = null;
|
||||
attachmentPreviewRow.attachmentDescription = "";
|
||||
fernschreiberUtils.stopGeoLocationUpdates();
|
||||
}
|
||||
|
@ -286,6 +292,10 @@ Page {
|
|||
}
|
||||
|
||||
function handleMessageTextReplacement(text, cursorPosition) {
|
||||
if(!newMessageTextField.focus) {
|
||||
return;
|
||||
}
|
||||
|
||||
var wordBoundaries = getWordBoundaries(text, cursorPosition);
|
||||
|
||||
var currentWord = text.substring(wordBoundaries.beginIndex, wordBoundaries.endIndex);
|
||||
|
@ -300,6 +310,7 @@ Page {
|
|||
} else {
|
||||
knownUsersRepeater.model = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function replaceMessageText(text, cursorPosition, newText) {
|
||||
|
@ -310,6 +321,19 @@ Page {
|
|||
newMessageTextField.cursorPosition = newIndex;
|
||||
lostFocusTimer.start();
|
||||
}
|
||||
|
||||
function setMessageText(text, doSend) {
|
||||
if(doSend) {
|
||||
tdLibWrapper.sendTextMessage(chatInformation.id, text, "0");
|
||||
}
|
||||
else {
|
||||
newMessageTextField.text = text
|
||||
newMessageTextField.cursorPosition = text.length
|
||||
lostFocusTimer.start();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function forwardMessages(fromChatId, messageIds) {
|
||||
forwardMessagesTimer.fromChatId = fromChatId;
|
||||
forwardMessagesTimer.messageIds = messageIds;
|
||||
|
@ -402,6 +426,17 @@ Page {
|
|||
switch(status) {
|
||||
case PageStatus.Activating:
|
||||
tdLibWrapper.openChat(chatInformation.id);
|
||||
if(!chatPage.isInitialized) {
|
||||
if(chatInformation.draft_message) {
|
||||
if(chatInformation.draft_message && chatInformation.draft_message.input_message_text) {
|
||||
newMessageTextField.text = chatInformation.draft_message.input_message_text.text.text;
|
||||
if(chatInformation.draft_message.reply_to_message_id) {
|
||||
tdLibWrapper.getMessage(chatInformation.id, chatInformation.draft_message.reply_to_message_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case PageStatus.Active:
|
||||
if (!chatPage.isInitialized) {
|
||||
|
@ -410,13 +445,8 @@ Page {
|
|||
pageStack.pushAttached(Qt.resolvedUrl("ChatInformationPage.qml"), { "chatInformation" : chatInformation, "privateChatUserInformation": chatPartnerInformation, "groupInformation": chatGroupInformation, "chatOnlineMemberCount": chatOnlineMemberCount});
|
||||
chatPage.isInitialized = true;
|
||||
|
||||
if(chatInformation.draft_message) {
|
||||
if(chatInformation.draft_message && chatInformation.draft_message.input_message_text) {
|
||||
newMessageTextField.text = chatInformation.draft_message.input_message_text.text.text;
|
||||
if(chatInformation.draft_message.reply_to_message_id) {
|
||||
tdLibWrapper.getMessage(chatInformation.id, chatInformation.draft_message.reply_to_message_id);
|
||||
}
|
||||
}
|
||||
if(doSendBotStartMessage) {
|
||||
tdLibWrapper.sendBotStartMessage(chatInformation.id, chatInformation.id, sendBotStartMessageParameter, "")
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -494,6 +524,25 @@ Page {
|
|||
chatPage.isSecretChatReady = chatPage.secretChatDetails.state["@type"] === "secretChatStateReady";
|
||||
}
|
||||
}
|
||||
onCallbackQueryAnswer: {
|
||||
if(text.length > 0) { // ignore bool "alert", just show as notification:
|
||||
appNotification.show(Emoji.emojify(text, Theme.fontSizeSmall));
|
||||
}
|
||||
if(url.length > 0) {
|
||||
Functions.handleLink(url);
|
||||
}
|
||||
}
|
||||
onUserFullInfoReceived: {
|
||||
if(userFullInfo["@extra"] === chatPartnerInformation.id.toString()) {
|
||||
chatPage.botInformation = userFullInfo;
|
||||
}
|
||||
}
|
||||
onUserFullInfoUpdated: {
|
||||
|
||||
if(userId === chatPartnerInformation.id) {
|
||||
chatPage.botInformation = userFullInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
@ -895,7 +944,7 @@ Page {
|
|||
id: chatView
|
||||
|
||||
visible: !blurred
|
||||
property bool blurred: messageOverlayLoader.item || stickerPickerLoader.item || voiceNoteOverlayLoader.item
|
||||
property bool blurred: messageOverlayLoader.item || stickerPickerLoader.item || voiceNoteOverlayLoader.item || inlineQuery.hasOverlay
|
||||
|
||||
anchors.fill: parent
|
||||
opacity: chatPage.loading ? 0 : 1
|
||||
|
@ -975,6 +1024,38 @@ Page {
|
|||
}
|
||||
|
||||
model: chatModel
|
||||
header: Component {
|
||||
Loader {
|
||||
active: !!chatPage.botInformation
|
||||
&& !!chatPage.botInformation.bot_info && chatPage.botInformation.bot_info.description.length > 0
|
||||
asynchronous: true
|
||||
width: chatView.width
|
||||
sourceComponent: Component {
|
||||
Label {
|
||||
id: botInfoLabel
|
||||
topPadding: Theme.paddingLarge
|
||||
bottomPadding: Theme.paddingLarge
|
||||
leftPadding: Theme.horizontalPageMargin
|
||||
rightPadding: Theme.horizontalPageMargin
|
||||
text: Emoji.emojify(chatPage.botInformation.bot_info.description, font.pixelSize)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.highlightColor
|
||||
wrapMode: Text.Wrap
|
||||
textFormat: Text.StyledText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
onLinkActivated: {
|
||||
var chatCommand = Functions.handleLink(link);
|
||||
if(chatCommand) {
|
||||
tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand);
|
||||
}
|
||||
}
|
||||
linkColor: Theme.primaryColor
|
||||
visible: (text !== "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var contentComponentNames: ({
|
||||
messageSticker: "StickerPreview",
|
||||
messagePhoto: "ImagePreview",
|
||||
|
@ -986,7 +1067,8 @@ Page {
|
|||
messageDocument: "DocumentPreview",
|
||||
messageLocation: "LocationPreview",
|
||||
messageVenue: "LocationPreview",
|
||||
messagePoll: "PollPreview"
|
||||
messagePoll: "PollPreview",
|
||||
messageGame: "GamePreview"
|
||||
})
|
||||
function getContentComponentHeight(componentName, content, parentWidth) {
|
||||
switch(componentName) {
|
||||
|
@ -1002,6 +1084,8 @@ Page {
|
|||
return Theme.itemSizeSmall;
|
||||
case "PollPreview":
|
||||
return Theme.itemSizeSmall * (4 + content.poll.options);
|
||||
case "GamePreview":
|
||||
return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1014,6 +1098,7 @@ Page {
|
|||
"messageChatJoinByLink",
|
||||
"messageChatSetTtl",
|
||||
"messageChatUpgradeFrom",
|
||||
"messageGameScore",
|
||||
"messageChatUpgradeTo",
|
||||
"messageCustomServiceAction",
|
||||
"messagePinMessage",
|
||||
|
@ -1168,12 +1253,17 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
InlineQuery {
|
||||
id: inlineQuery
|
||||
textField: newMessageTextField
|
||||
chatId: chatInformation.id
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
id: newMessageColumn
|
||||
spacing: Theme.paddingSmall
|
||||
topPadding: Theme.paddingSmall
|
||||
topPadding: Theme.paddingSmall + inlineQuery.buttonPadding
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: height > 0
|
||||
width: parent.width - ( 2 * Theme.horizontalPageMargin )
|
||||
|
@ -1212,8 +1302,8 @@ Page {
|
|||
property bool isNeeded: false
|
||||
width: chatPage.width
|
||||
x: -Theme.horizontalPageMargin
|
||||
height: isNeeded ? attachmentOptionsRow.height : 0
|
||||
Behavior on height { SmoothedAnimation { duration: 200 } }
|
||||
height: isNeeded && !inlineQuery.active ? attachmentOptionsRow.height : 0
|
||||
Behavior on height { SmoothedAnimation { duration: 200 } }
|
||||
visible: height > 0
|
||||
contentHeight: attachmentOptionsRow.height
|
||||
contentWidth: Math.max(width, attachmentOptionsRow.width)
|
||||
|
@ -1252,7 +1342,6 @@ Page {
|
|||
Debug.log("Selected document: ", picker.selectedContentProperties.filePath );
|
||||
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
|
||||
attachmentPreviewRow.isPicture = true;
|
||||
attachmentPreviewRow.visible = true;
|
||||
controlSendButton();
|
||||
})
|
||||
}
|
||||
|
@ -1269,7 +1358,6 @@ Page {
|
|||
Debug.log("Selected video: ", picker.selectedContentProperties.filePath );
|
||||
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
|
||||
attachmentPreviewRow.isVideo = true;
|
||||
attachmentPreviewRow.visible = true;
|
||||
controlSendButton();
|
||||
})
|
||||
}
|
||||
|
@ -1299,7 +1387,6 @@ Page {
|
|||
Debug.log("Selected document: ", picker.selectedContentProperties.filePath );
|
||||
attachmentPreviewRow.fileProperties = picker.selectedContentProperties;
|
||||
attachmentPreviewRow.isDocument = true;
|
||||
attachmentPreviewRow.visible = true;
|
||||
controlSendButton();
|
||||
})
|
||||
}
|
||||
|
@ -1337,7 +1424,6 @@ Page {
|
|||
attachmentOptionsFlickable.isNeeded = false;
|
||||
attachmentPreviewRow.isLocation = true;
|
||||
attachmentPreviewRow.attachmentDescription = qsTr("Location: Obtaining position...");
|
||||
attachmentPreviewRow.visible = true;
|
||||
controlSendButton();
|
||||
}
|
||||
}
|
||||
|
@ -1348,7 +1434,7 @@ Page {
|
|||
|
||||
Row {
|
||||
id: attachmentPreviewRow
|
||||
visible: false
|
||||
visible: (!!locationData || !!fileProperties) && !inlineQuery.active
|
||||
spacing: Theme.paddingMedium
|
||||
width: parent.width
|
||||
layoutDirection: Qt.RightToLeft
|
||||
|
@ -1359,8 +1445,8 @@ Page {
|
|||
property bool isDocument: false;
|
||||
property bool isVoiceNote: false;
|
||||
property bool isLocation: false;
|
||||
property var locationData: ({});
|
||||
property var fileProperties:({});
|
||||
property var locationData: null;
|
||||
property var fileProperties: null;
|
||||
property string attachmentDescription: "";
|
||||
|
||||
Connections {
|
||||
|
@ -1390,15 +1476,15 @@ Page {
|
|||
sourceSize.height: height
|
||||
|
||||
fillMode: Thumbnail.PreserveAspectCrop
|
||||
mimeType: typeof attachmentPreviewRow.fileProperties !== "undefined" ? attachmentPreviewRow.fileProperties.mimeType || "" : ""
|
||||
source: typeof attachmentPreviewRow.fileProperties !== "undefined" ? attachmentPreviewRow.fileProperties.url || "" : ""
|
||||
mimeType: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.mimeType || "" : ""
|
||||
source: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.url || "" : ""
|
||||
visible: attachmentPreviewRow.isPicture || attachmentPreviewRow.isVideo
|
||||
}
|
||||
|
||||
Label {
|
||||
id: attachmentPreviewText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
text: ( attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation ) ? attachmentPreviewRow.attachmentDescription : ( typeof attachmentPreviewRow.fileProperties !== "undefined" ? attachmentPreviewRow.fileProperties.fileName || "" : "" );
|
||||
text: ( attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation ) ? attachmentPreviewRow.attachmentDescription : ( !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.fileName || "" : "" );
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
maximumLineCount: 1
|
||||
|
@ -1491,9 +1577,11 @@ Page {
|
|||
id: atMentionColumn
|
||||
width: parent.width
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: knownUsersRepeater.count > 0 ? true : false
|
||||
visible: opacity > 0
|
||||
opacity: knownUsersRepeater.count > 0 ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation {} }
|
||||
height: knownUsersRepeater.count > 0 ? childrenRect.height : 0
|
||||
Behavior on height { SmoothedAnimation { duration: 200 } }
|
||||
spacing: Theme.paddingMedium
|
||||
|
||||
Flickable {
|
||||
|
@ -1598,7 +1686,7 @@ Page {
|
|||
|
||||
TextArea {
|
||||
id: newMessageTextField
|
||||
width: parent.width - attachmentIconButton.width - (newMessageSendButton.visible ? newMessageSendButton.width : 0)
|
||||
width: parent.width - (attachmentIconButton.visible ? attachmentIconButton.width : 0) - (newMessageSendButton.visible ? newMessageSendButton.width : 0) - (cancelInlineQueryButton.visible ? cancelInlineQueryButton.width : 0)
|
||||
height: Math.min(chatContainer.height / 3, implicitHeight)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
|
@ -1617,7 +1705,7 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
EnterKey.enabled: !appSettings.sendByEnter || text.length
|
||||
EnterKey.enabled: !inlineQuery.active && (!appSettings.sendByEnter || text.length)
|
||||
EnterKey.iconSource: appSettings.sendByEnter ? "image://theme/icon-m-chat" : "image://theme/icon-m-enter"
|
||||
|
||||
onTextChanged: {
|
||||
|
@ -1632,6 +1720,7 @@ Page {
|
|||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.paddingSmall
|
||||
enabled: !attachmentPreviewRow.visible
|
||||
visible: !inlineQuery.active
|
||||
onClicked: {
|
||||
if (attachmentOptionsFlickable.isNeeded) {
|
||||
attachmentOptionsFlickable.isNeeded = false;
|
||||
|
@ -1648,7 +1737,7 @@ Page {
|
|||
icon.source: "image://theme/icon-m-chat"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.paddingSmall
|
||||
visible: !appSettings.sendByEnter || attachmentPreviewRow.visible
|
||||
visible: !inlineQuery.active && (!appSettings.sendByEnter || attachmentPreviewRow.visible)
|
||||
enabled: false
|
||||
onClicked: {
|
||||
sendMessage();
|
||||
|
@ -1658,6 +1747,42 @@ Page {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: cancelInlineQueryButton.width
|
||||
height: cancelInlineQueryButton.height
|
||||
visible: inlineQuery.active
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Theme.paddingSmall
|
||||
|
||||
IconButton {
|
||||
id: cancelInlineQueryButton
|
||||
icon.source: "image://theme/icon-m-cancel"
|
||||
visible: parent.visible
|
||||
opacity: inlineQuery.isLoading ? 0.2 : 1
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
onClicked: {
|
||||
if(inlineQuery.query !== "") {
|
||||
newMessageTextField.text = "@" + inlineQuery.userName + " "
|
||||
newMessageTextField.cursorPosition = newMessageTextField.text.length
|
||||
lostFocusTimer.start();
|
||||
} else {
|
||||
newMessageTextField.text = ""
|
||||
}
|
||||
}
|
||||
onPressAndHold: {
|
||||
newMessageTextField.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
BusyIndicator {
|
||||
size: BusyIndicatorSize.Small
|
||||
anchors.centerIn: parent
|
||||
running: inlineQuery.isLoading
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,9 @@ Dialog {
|
|||
case "forwardMessages":
|
||||
acceptDestinationInstance.forwardMessages(payload.fromChatId, payload.messageIds)
|
||||
break;
|
||||
case "fillTextArea": // ReplyMarkupButtons: inlineKeyboardButtonTypeSwitchInline
|
||||
acceptDestinationInstance.setMessageText(payload.text)
|
||||
break;
|
||||
// future uses of chat selection can be processed here
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +78,7 @@ Dialog {
|
|||
QtObject {
|
||||
property bool visible: false
|
||||
Component.onCompleted: {
|
||||
if(chatSelectionPage.state === "forwardMessages") {
|
||||
if(chatSelectionPage.state === "forwardMessages" || chatSelectionPage.state === "fillTextArea" ) {
|
||||
var chatType = display.type['@type']
|
||||
var chatGroupInformation
|
||||
if(chatType === "chatTypePrivate" || chatType === "chatTypeSecret") {
|
||||
|
@ -126,6 +129,7 @@ Dialog {
|
|||
var chat = tdLibWrapper.getChat(display.id);
|
||||
switch(chatSelectionPage.state) {
|
||||
case "forwardMessages":
|
||||
case "fillTextArea":
|
||||
chatSelectionPage.acceptDestinationProperties = { "chatInformation" : chat};
|
||||
chatSelectionPage.acceptDestination = Qt.resolvedUrl("../pages/ChatPage.qml");
|
||||
break;
|
||||
|
|
|
@ -220,7 +220,7 @@ Page {
|
|||
icon.source: "image://theme/icon-m-chat"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
tdLibWrapper.createPrivateChat(display.id);
|
||||
tdLibWrapper.createPrivateChat(display.id, "openDirectly");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,7 @@ Page {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
tdLibWrapper.createPrivateChat(display.id);
|
||||
tdLibWrapper.createPrivateChat(display.id, "openDirectly");
|
||||
}
|
||||
onPressed: {
|
||||
privateChatHighlightBackground.visible = true;
|
||||
|
@ -295,7 +295,7 @@ Page {
|
|||
icon.source: "image://theme/icon-m-device-lock"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
tdLibWrapper.createNewSecretChat(display.id);
|
||||
tdLibWrapper.createNewSecretChat(display.id, "openDirectly");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ Page {
|
|||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
tdLibWrapper.createNewSecretChat(display.id);
|
||||
tdLibWrapper.createNewSecretChat(display.id, "openDirectly");
|
||||
}
|
||||
onPressed: {
|
||||
secretChatHighlightBackground.visible = true;
|
||||
|
|
|
@ -210,10 +210,17 @@ Page {
|
|||
}
|
||||
}
|
||||
onChatReceived: {
|
||||
if(chat["@extra"] === "openDirectly") {
|
||||
var openAndSendStartToBot = chat["@extra"].indexOf("openAndSendStartToBot:") === 0
|
||||
if(chat["@extra"] === "openDirectly" || openAndSendStartToBot && chat.type["@type"] === "chatTypePrivate") {
|
||||
pageStack.pop(overviewPage, PageStackAction.Immediate)
|
||||
// if we get a new chat (no messages?), we can not use the provided data
|
||||
pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : tdLibWrapper.getChat(chat.id) });
|
||||
var chatinfo = tdLibWrapper.getChat(chat.id);
|
||||
var options = { "chatInformation" : chatinfo }
|
||||
if(openAndSendStartToBot) {
|
||||
options.doSendBotStartMessage = true;
|
||||
options.sendBotStartMessageParameter = chat["@extra"].substring(22);
|
||||
}
|
||||
pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), options);
|
||||
}
|
||||
}
|
||||
onErrorReceived: {
|
||||
|
|
|
@ -159,6 +159,20 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
SectionHeader {
|
||||
text: qsTr("Privacy")
|
||||
}
|
||||
|
||||
TextSwitch {
|
||||
checked: appSettings.allowInlineBotLocationAccess
|
||||
text: qsTr("Allow sending Location to inline bots")
|
||||
description: qsTr("Some inline bots request location data when using them")
|
||||
automaticCheck: false
|
||||
onClicked: {
|
||||
appSettings.allowInlineBotLocationAccess = !checked
|
||||
}
|
||||
}
|
||||
|
||||
SectionHeader {
|
||||
text: qsTr("Storage")
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace {
|
|||
const QString KEY_NOTIFICATION_TURNS_DISPLAY_ON("notificationTurnsDisplayOn");
|
||||
const QString KEY_NOTIFICATION_FEEDBACK("notificationFeedback");
|
||||
const QString KEY_STORAGE_OPTIMIZER("storageOptimizer");
|
||||
const QString KEY_INLINEBOT_LOCATION_ACCESS("allowInlineBotLocationAccess");
|
||||
const QString KEY_REMAINING_INTERACTION_HINTS("remainingInteractionHints");
|
||||
const QString KEY_ONLINE_ONLY_MODE("onlineOnlyMode");
|
||||
}
|
||||
|
@ -149,6 +150,21 @@ void AppSettings::setStorageOptimizer(bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
bool AppSettings::allowInlineBotLocationAccess() const
|
||||
{
|
||||
return settings.value(KEY_INLINEBOT_LOCATION_ACCESS, false).toBool();
|
||||
}
|
||||
|
||||
void AppSettings::setAllowInlineBotLocationAccess(bool enable)
|
||||
{
|
||||
|
||||
if (allowInlineBotLocationAccess() != enable) {
|
||||
LOG(KEY_INLINEBOT_LOCATION_ACCESS << enable);
|
||||
settings.setValue(KEY_INLINEBOT_LOCATION_ACCESS, enable);
|
||||
emit allowInlineBotLocationAccessChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int AppSettings::remainingInteractionHints() const
|
||||
{
|
||||
return settings.value(KEY_REMAINING_INTERACTION_HINTS, 3).toInt();
|
||||
|
|
|
@ -31,6 +31,7 @@ class AppSettings : public QObject {
|
|||
Q_PROPERTY(bool notificationTurnsDisplayOn READ notificationTurnsDisplayOn WRITE setNotificationTurnsDisplayOn NOTIFY notificationTurnsDisplayOnChanged)
|
||||
Q_PROPERTY(NotificationFeedback notificationFeedback READ notificationFeedback WRITE setNotificationFeedback NOTIFY notificationFeedbackChanged)
|
||||
Q_PROPERTY(bool storageOptimizer READ storageOptimizer WRITE setStorageOptimizer NOTIFY storageOptimizerChanged)
|
||||
Q_PROPERTY(bool allowInlineBotLocationAccess READ allowInlineBotLocationAccess WRITE setAllowInlineBotLocationAccess NOTIFY allowInlineBotLocationAccessChanged)
|
||||
Q_PROPERTY(int remainingInteractionHints READ remainingInteractionHints WRITE setRemainingInteractionHints NOTIFY remainingInteractionHintsChanged)
|
||||
Q_PROPERTY(bool onlineOnlyMode READ onlineOnlyMode WRITE setOnlineOnlyMode NOTIFY onlineOnlyModeChanged)
|
||||
|
||||
|
@ -69,6 +70,9 @@ public:
|
|||
bool storageOptimizer() const;
|
||||
void setStorageOptimizer(bool enable);
|
||||
|
||||
bool allowInlineBotLocationAccess() const;
|
||||
void setAllowInlineBotLocationAccess(bool enable);
|
||||
|
||||
int remainingInteractionHints() const;
|
||||
void setRemainingInteractionHints(int remainingHints);
|
||||
|
||||
|
@ -84,6 +88,7 @@ signals:
|
|||
void notificationTurnsDisplayOnChanged();
|
||||
void notificationFeedbackChanged();
|
||||
void storageOptimizerChanged();
|
||||
void allowInlineBotLocationAccessChanged();
|
||||
void remainingInteractionHintsChanged();
|
||||
void onlineOnlyModeChanged();
|
||||
|
||||
|
|
|
@ -178,6 +178,13 @@ QString FernschreiberUtils::getMessageShortText(TDLibWrapper *tdLibWrapper, cons
|
|||
if (contentType == "messageScreenshotTaken") {
|
||||
return myself ? tr("created a screenshot in this chat", "myself") : tr("created a screenshot in this chat");
|
||||
}
|
||||
if (contentType == "messageGameScore") {
|
||||
qint32 score = messageContent.value("score").toInt();
|
||||
return myself ? tr("scored %Ln points", "myself", score) : tr("scored %Ln points", "", score);
|
||||
}
|
||||
if (contentType == "messageGame") {
|
||||
return myself ? tr("sent a game", "myself") : tr("sent a game");
|
||||
}
|
||||
if (contentType == "messageUnsupported") {
|
||||
return myself ? tr("sent an unsupported message", "myself") : tr("sent an unsupported message");
|
||||
}
|
||||
|
|
|
@ -137,6 +137,8 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren
|
|||
handlers.insert("updateMessageEdited", &TDLibReceiver::processUpdateMessageEdited);
|
||||
handlers.insert("updateChatIsMarkedAsUnread", &TDLibReceiver::processUpdateChatIsMarkedAsUnread);
|
||||
handlers.insert("updateChatDraftMessage", &TDLibReceiver::processUpdateChatDraftMessage);
|
||||
handlers.insert("inlineQueryResults", &TDLibReceiver::processInlineQueryResults);
|
||||
handlers.insert("callbackQueryAnswer", &TDLibReceiver::processCallbackQueryAnswer);
|
||||
}
|
||||
|
||||
void TDLibReceiver::setActive(bool active)
|
||||
|
@ -596,3 +598,16 @@ void TDLibReceiver::processUpdateChatDraftMessage(const QVariantMap &receivedInf
|
|||
LOG("Draft message was updated");
|
||||
emit chatDraftMessageUpdated(receivedInformation.value(CHAT_ID).toLongLong(), receivedInformation.value("draft_message").toMap(), findChatPositionOrder(receivedInformation.value(POSITIONS).toList()));
|
||||
}
|
||||
|
||||
void TDLibReceiver::processInlineQueryResults(const QVariantMap &receivedInformation)
|
||||
{
|
||||
LOG("Inline Query results");
|
||||
emit inlineQueryResults(receivedInformation.value("inline_query_id").toString(), receivedInformation.value("next_offset").toString(), receivedInformation.value("results").toList(), receivedInformation.value("switch_pm_text").toString(), receivedInformation.value("switch_pm_parameter").toString(), receivedInformation.value(EXTRA).toString());
|
||||
}
|
||||
|
||||
void TDLibReceiver::processCallbackQueryAnswer(const QVariantMap &receivedInformation)
|
||||
{
|
||||
|
||||
LOG("Callback Query answer");
|
||||
emit callbackQueryAnswer(receivedInformation.value(TEXT).toString(), receivedInformation.value("alert").toBool(), receivedInformation.value("url").toString());
|
||||
}
|
||||
|
|
|
@ -93,6 +93,8 @@ signals:
|
|||
void contactsImported(const QVariantList &importerCount, const QVariantList &userIds);
|
||||
void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread);
|
||||
void chatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
|
||||
void inlineQueryResults(const QString &inlineQueryId, const QString &nextOffset, const QVariantList &results, const QString &switchPmText, const QString &switchPmParameter, const QString &extra);
|
||||
void callbackQueryAnswer(const QString &text, bool alert, const QString &url);
|
||||
|
||||
private:
|
||||
typedef void (TDLibReceiver::*Handler)(const QVariantMap &);
|
||||
|
@ -160,6 +162,8 @@ private:
|
|||
void processImportedContacts(const QVariantMap &receivedInformation);
|
||||
void processUpdateChatIsMarkedAsUnread(const QVariantMap &receivedInformation);
|
||||
void processUpdateChatDraftMessage(const QVariantMap &receivedInformation);
|
||||
void processInlineQueryResults(const QVariantMap &receivedInformation);
|
||||
void processCallbackQueryAnswer(const QVariantMap &receivedInformation);
|
||||
};
|
||||
|
||||
#endif // TDLIBRECEIVER_H
|
||||
|
|
|
@ -131,6 +131,8 @@ TDLibWrapper::TDLibWrapper(AppSettings *appSettings, MceInterface *mceInterface,
|
|||
connect(this->tdLibReceiver, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)), this, SIGNAL(messageEditedUpdated(qlonglong, qlonglong, QVariantMap)));
|
||||
connect(this->tdLibReceiver, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)), this, SIGNAL(chatIsMarkedAsUnreadUpdated(qlonglong, bool)));
|
||||
connect(this->tdLibReceiver, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)), this, SIGNAL(chatDraftMessageUpdated(qlonglong, QVariantMap, QString)));
|
||||
connect(this->tdLibReceiver, SIGNAL(inlineQueryResults(QString, QString, QVariantList, QString, QString, QString)), this, SIGNAL(inlineQueryResults(QString, QString, QVariantList, QString, QString, QString)));
|
||||
connect(this->tdLibReceiver, SIGNAL(callbackQueryAnswer(QString, bool, QString)), this, SIGNAL(callbackQueryAnswer(QString, bool, QString)));
|
||||
|
||||
connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList)));
|
||||
|
||||
|
@ -685,13 +687,12 @@ void TDLibWrapper::deleteMessages(const QString &chatId, const QVariantList mess
|
|||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::getMapThumbnailFile(const QString &chatId, double latitude, double longitude, int width, int height)
|
||||
void TDLibWrapper::getMapThumbnailFile(const QString &chatId, double latitude, double longitude, int width, int height, const QString &extra)
|
||||
{
|
||||
LOG("Getting Map Thumbnail File" << chatId);
|
||||
QVariantMap location;
|
||||
location.insert("latitude", latitude);
|
||||
location.insert("longitude", longitude);
|
||||
|
||||
// ensure dimensions are in bounds (16 - 1024)
|
||||
int boundsWidth = std::min(std::max(width, 16), 1024);
|
||||
int boundsHeight = std::min(std::max(height, 16), 1024);
|
||||
|
@ -704,6 +705,7 @@ void TDLibWrapper::getMapThumbnailFile(const QString &chatId, double latitude, d
|
|||
requestObject.insert("height", boundsHeight);
|
||||
requestObject.insert("scale", 1); // 1-3
|
||||
requestObject.insert(CHAT_ID, chatId);
|
||||
requestObject.insert(_EXTRA, extra);
|
||||
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
@ -769,43 +771,43 @@ void TDLibWrapper::getUserFullInfo(const QString &userId)
|
|||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::createPrivateChat(const QString &userId)
|
||||
void TDLibWrapper::createPrivateChat(const QString &userId, const QString &extra)
|
||||
{
|
||||
LOG("Creating Private Chat");
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "createPrivateChat");
|
||||
requestObject.insert("user_id", userId);
|
||||
requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml
|
||||
requestObject.insert(_EXTRA, extra); //"openDirectly"/"openAndSendStartToBot:[optional parameter]" gets matched in qml
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::createNewSecretChat(const QString &userId)
|
||||
void TDLibWrapper::createNewSecretChat(const QString &userId, const QString &extra)
|
||||
{
|
||||
LOG("Creating new secret chat");
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "createNewSecretChat");
|
||||
requestObject.insert("user_id", userId);
|
||||
requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml
|
||||
requestObject.insert(_EXTRA, extra); //"openDirectly" gets matched in qml
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::createSupergroupChat(const QString &supergroupId)
|
||||
void TDLibWrapper::createSupergroupChat(const QString &supergroupId, const QString &extra)
|
||||
{
|
||||
LOG("Creating Supergroup Chat");
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "createSupergroupChat");
|
||||
requestObject.insert("supergroup_id", supergroupId);
|
||||
requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml
|
||||
requestObject.insert(_EXTRA, extra); //"openDirectly" gets matched in qml
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::createBasicGroupChat(const QString &basicGroupId)
|
||||
void TDLibWrapper::createBasicGroupChat(const QString &basicGroupId, const QString &extra)
|
||||
{
|
||||
LOG("Creating Basic Group Chat");
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "createBasicGroupChat");
|
||||
requestObject.insert("basic_group_id", basicGroupId);
|
||||
requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml
|
||||
requestObject.insert(_EXTRA, extra); //"openDirectly"/"openAndSend:*" gets matched in qml
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
|
@ -929,12 +931,15 @@ void TDLibWrapper::getPollVoters(const QString &chatId, qlonglong messageId, int
|
|||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::searchPublicChat(const QString &userName)
|
||||
void TDLibWrapper::searchPublicChat(const QString &userName, bool doOpenOnFound)
|
||||
{
|
||||
LOG("Search public chat" << userName);
|
||||
this->activeChatSearchName = userName;
|
||||
if(doOpenOnFound) {
|
||||
this->activeChatSearchName = userName;
|
||||
}
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "searchPublicChat");
|
||||
requestObject.insert(_EXTRA, "searchPublicChat:"+userName);
|
||||
requestObject.insert(USERNAME, userName);
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
@ -1075,6 +1080,53 @@ void TDLibWrapper::setChatDraftMessage(qlonglong chatId, qlonglong threadId, qlo
|
|||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::getInlineQueryResults(qlonglong botUserId, qlonglong chatId, const QVariantMap &userLocation, const QString &query, const QString &offset, const QString &extra)
|
||||
{
|
||||
|
||||
LOG("Get Inline Query Results" << chatId << query);
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "getInlineQueryResults");
|
||||
requestObject.insert(CHAT_ID, chatId);
|
||||
requestObject.insert("bot_user_id", botUserId);
|
||||
if(!userLocation.isEmpty()) {
|
||||
requestObject.insert("user_location", userLocation);
|
||||
}
|
||||
requestObject.insert("query", query);
|
||||
requestObject.insert("offset", offset);
|
||||
requestObject.insert(_EXTRA, extra);
|
||||
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::sendInlineQueryResultMessage(qlonglong chatId, qlonglong threadId, qlonglong replyToMessageId, const QString &queryId, const QString &resultId)
|
||||
{
|
||||
|
||||
LOG("Send Inline Query Result Message" << chatId);
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "sendInlineQueryResultMessage");
|
||||
requestObject.insert(CHAT_ID, chatId);
|
||||
requestObject.insert("message_thread_id", threadId);
|
||||
requestObject.insert("reply_to_message_id", replyToMessageId);
|
||||
requestObject.insert("query_id", queryId);
|
||||
requestObject.insert("result_id", resultId);
|
||||
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::sendBotStartMessage(qlonglong botUserId, qlonglong chatId, const QString ¶meter, const QString &extra)
|
||||
{
|
||||
|
||||
LOG("Send Bot Start Message" << botUserId << chatId << parameter << extra);
|
||||
QVariantMap requestObject;
|
||||
requestObject.insert(_TYPE, "sendBotStartMessage");
|
||||
requestObject.insert("bot_user_id", botUserId);
|
||||
requestObject.insert(CHAT_ID, chatId);
|
||||
requestObject.insert("parameter", parameter);
|
||||
requestObject.insert(_EXTRA, extra);
|
||||
|
||||
this->sendRequest(requestObject);
|
||||
}
|
||||
|
||||
void TDLibWrapper::searchEmoji(const QString &queryString)
|
||||
{
|
||||
LOG("Searching emoji" << queryString);
|
||||
|
@ -1349,12 +1401,12 @@ void TDLibWrapper::handleChatReceived(const QVariantMap &chatInformation)
|
|||
if (receivedChatType == ChatTypeBasicGroup) {
|
||||
LOG("Found basic group for active search" << this->activeChatSearchName);
|
||||
this->activeChatSearchName.clear();
|
||||
this->createBasicGroupChat(chatType.value("basic_group_id").toString());
|
||||
this->createBasicGroupChat(chatType.value("basic_group_id").toString(), "openDirectly");
|
||||
}
|
||||
if (receivedChatType == ChatTypeSupergroup) {
|
||||
LOG("Found supergroup for active search" << this->activeChatSearchName);
|
||||
this->activeChatSearchName.clear();
|
||||
this->createSupergroupChat(chatType.value("supergroup_id").toString());
|
||||
this->createSupergroupChat(chatType.value("supergroup_id").toString(), "openDirectly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1381,7 +1433,7 @@ void TDLibWrapper::handleBasicGroupUpdated(qlonglong groupId, const QVariantMap
|
|||
if (!this->activeChatSearchName.isEmpty() && this->activeChatSearchName == groupInformation.value(USERNAME).toString()) {
|
||||
LOG("Found basic group for active search" << this->activeChatSearchName);
|
||||
this->activeChatSearchName.clear();
|
||||
this->createBasicGroupChat(groupInformation.value(ID).toString());
|
||||
this->createBasicGroupChat(groupInformation.value(ID).toString(), "openDirectly");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1391,7 +1443,7 @@ void TDLibWrapper::handleSuperGroupUpdated(qlonglong groupId, const QVariantMap
|
|||
if (!this->activeChatSearchName.isEmpty() && this->activeChatSearchName == groupInformation.value(USERNAME).toString()) {
|
||||
LOG("Found supergroup for active search" << this->activeChatSearchName);
|
||||
this->activeChatSearchName.clear();
|
||||
this->createSupergroupChat(groupInformation.value(ID).toString());
|
||||
this->createSupergroupChat(groupInformation.value(ID).toString(), "openDirectly");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -152,17 +152,17 @@ public:
|
|||
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, double latitude, double longitude, int width, int height);
|
||||
Q_INVOKABLE void getMapThumbnailFile(const QString &chatId, double latitude, double longitude, int width, int height, const QString &extra);
|
||||
Q_INVOKABLE void getRecentStickers();
|
||||
Q_INVOKABLE void getInstalledStickerSets();
|
||||
Q_INVOKABLE void getStickerSet(const QString &setId);
|
||||
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 createNewSecretChat(const QString &userId);
|
||||
Q_INVOKABLE void createSupergroupChat(const QString &supergroupId);
|
||||
Q_INVOKABLE void createBasicGroupChat(const QString &basicGroupId);
|
||||
Q_INVOKABLE void createPrivateChat(const QString &userId, const QString &extra);
|
||||
Q_INVOKABLE void createNewSecretChat(const QString &userId, const QString &extra);
|
||||
Q_INVOKABLE void createSupergroupChat(const QString &supergroupId, const QString &extra);
|
||||
Q_INVOKABLE void createBasicGroupChat(const QString &basicGroupId, const QString &extra);
|
||||
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);
|
||||
|
@ -174,7 +174,7 @@ public:
|
|||
Q_INVOKABLE void setPollAnswer(const QString &chatId, qlonglong messageId, QVariantList optionIds);
|
||||
Q_INVOKABLE void stopPoll(const QString &chatId, qlonglong messageId);
|
||||
Q_INVOKABLE void getPollVoters(const QString &chatId, qlonglong messageId, int optionId, int limit, int offset, const QString &extra);
|
||||
Q_INVOKABLE void searchPublicChat(const QString &userName);
|
||||
Q_INVOKABLE void searchPublicChat(const QString &userName, bool doOpenOnFound);
|
||||
Q_INVOKABLE void joinChatByInviteLink(const QString &inviteLink);
|
||||
Q_INVOKABLE void getDeepLinkInfo(const QString &link);
|
||||
Q_INVOKABLE void getContacts();
|
||||
|
@ -187,6 +187,9 @@ public:
|
|||
Q_INVOKABLE void toggleChatIsMarkedAsUnread(qlonglong chatId, bool isMarkedAsUnread);
|
||||
Q_INVOKABLE void toggleChatIsPinned(qlonglong chatId, bool isPinned);
|
||||
Q_INVOKABLE void setChatDraftMessage(qlonglong chatId, qlonglong threadId, qlonglong replyToMessageId, const QString &draft);
|
||||
Q_INVOKABLE void getInlineQueryResults(qlonglong botUserId, qlonglong chatId, const QVariantMap &userLocation, const QString &query, const QString &offset, const QString &extra);
|
||||
Q_INVOKABLE void sendInlineQueryResultMessage(qlonglong chatId, qlonglong threadId, qlonglong replyToMessageId, const QString &queryId, const QString &resultId);
|
||||
Q_INVOKABLE void sendBotStartMessage(qlonglong botUserId, qlonglong chatId, const QString ¶meter, const QString &extra);
|
||||
|
||||
// Others (candidates for extraction ;))
|
||||
Q_INVOKABLE void searchEmoji(const QString &queryString);
|
||||
|
@ -259,6 +262,8 @@ signals:
|
|||
void messageNotFound(qlonglong chatId, qlonglong messageId);
|
||||
void chatIsMarkedAsUnreadUpdated(qlonglong chatId, bool chatIsMarkedAsUnread);
|
||||
void chatDraftMessageUpdated(qlonglong chatId, const QVariantMap &draftMessage, const QString &order);
|
||||
void inlineQueryResults(const QString &inlineQueryId, const QString &nextOffset, const QVariantList &results, const QString &switchPmText, const QString &switchPmParameter, const QString &extra);
|
||||
void callbackQueryAnswer(const QString &text, bool alert, const QString &url);
|
||||
|
||||
public slots:
|
||||
void handleVersionDetected(const QString &version);
|
||||
|
|
|
@ -823,6 +823,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation>haben %1 vom Chat entfernt</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation>
|
||||
<numerusform>haben %Ln Punkt erziehlt</numerusform>
|
||||
<numerusform>haben %Ln Punkte erziehlt</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform>hat %Ln Punkt erziehlt</numerusform>
|
||||
<numerusform>hat %Ln Punkte erziehlt</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation>haben ein Spiel gesendet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation>hat ein Spiel gesendet</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -973,6 +997,21 @@
|
|||
<source>You</source>
|
||||
<translation>Sie</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform>haben %Ln Punkt bei %2 erziehlt</numerusform>
|
||||
<numerusform>haben %Ln Punkte bei %2 erziehlt</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform>hat %Ln Punkt bei %2 erziehlt</numerusform>
|
||||
<numerusform>hat %Ln Punkte bei %2 erziehlt</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -985,6 +1024,14 @@
|
|||
<translation>Diese Nachricht wurde weitergeleitet. Ursprünglicher Autor: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished">via %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1445,6 +1492,18 @@
|
|||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation>Schaltet das Offline-Caching aus. Bestimmte Features können in diesem Modus eingeschränkt sein oder fehlen. Änderungen erfordern einen Neustart von Fernschreiber, um in Kraft zu treten.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation>Privatsphäre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation>Erlaubt Standortsendung an Inline-Bots</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation>Einige Inline-Bots fragen bei Nutzung Standortdaten an</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StickerPicker</name>
|
||||
|
@ -1912,5 +1971,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation>haben %1 vom Chat entfernt</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform>haben %Ln Punkt erziehlt</numerusform>
|
||||
<numerusform>haben %Ln Punkte erziehlt</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation>haben ein Spiel gesendet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation>hat ein Spiel gesendet</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -823,6 +823,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation>have removed %1 from the chat</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation>
|
||||
<numerusform>scored %Ln point</numerusform>
|
||||
<numerusform>scored %Ln points</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation>
|
||||
<numerusform>scored %Ln point</numerusform>
|
||||
<numerusform>scored %Ln points</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation>sent a game</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation>sent a game</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -973,6 +997,21 @@
|
|||
<source>You</source>
|
||||
<translation>You</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation>
|
||||
<numerusform>scored %Ln point in %2</numerusform>
|
||||
<numerusform>scored %Ln points in %2</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation>
|
||||
<numerusform>scored %Ln point in %2</numerusform>
|
||||
<numerusform>scored %Ln points in %2</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -985,6 +1024,14 @@
|
|||
<translation>This message was forwarded. Original author: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished">via %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1445,6 +1492,18 @@
|
|||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation>Privacy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation>Allow sending Location to inline bots</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation>Some inline bots request location data when using them</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StickerPicker</name>
|
||||
|
@ -1912,5 +1971,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation>have removed %1 from the chat</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation>
|
||||
<numerusform>scored %Ln point</numerusform>
|
||||
<numerusform>scored %Ln points</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation>sent a game</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation>sent a game</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -813,6 +813,28 @@
|
|||
<comment>myself</comment>
|
||||
<translation>ha quitado %1 de charla</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -963,6 +985,19 @@
|
|||
<source>You</source>
|
||||
<translation>Usted</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -975,6 +1010,14 @@
|
|||
<translation>Este mensaje fue reenviado. Autor original: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1424,6 +1467,18 @@
|
|||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StickerPicker</name>
|
||||
|
@ -1891,5 +1946,21 @@
|
|||
<comment>myself</comment>
|
||||
<translation>ha añadido %1 de la charla</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -824,6 +824,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation>poistit käyttäjän %1 keskustelusta</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -974,6 +998,21 @@
|
|||
<source>You</source>
|
||||
<translation>Sinä</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -986,6 +1025,14 @@
|
|||
<translation>Välitetty viesti. Alkuperäinen lähettäjä: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1444,6 +1491,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1913,5 +1972,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation>poistit käyttäjän %1 keskustelusta</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -813,6 +813,28 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -963,6 +985,19 @@
|
|||
<source>You</source>
|
||||
<translation type="unfinished">Te</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -975,6 +1010,14 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1422,6 +1465,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1891,5 +1946,21 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -823,6 +823,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation>hai rimosso %1 dalla chat</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -973,6 +997,21 @@
|
|||
<source>You</source>
|
||||
<translation>Tu</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -985,6 +1024,14 @@
|
|||
<translation>Questo è un messaggio inoltrato. Autore originale: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1445,6 +1492,18 @@
|
|||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StickerPicker</name>
|
||||
|
@ -1912,5 +1971,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation>hai rimosso %1 dalla chat</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -833,6 +833,32 @@
|
|||
<comment>myself</comment>
|
||||
<translation>usunąłem %1 z czatu</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -983,6 +1009,23 @@
|
|||
<source>You</source>
|
||||
<translation>Ty</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -995,6 +1038,14 @@
|
|||
<translation>Ta wiadomość została przekazana. Oryginalny autor: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1466,6 +1517,18 @@
|
|||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StickerPicker</name>
|
||||
|
@ -1933,5 +1996,23 @@
|
|||
<comment>myself</comment>
|
||||
<translation>usunąłem %1 z czatu</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -833,6 +833,32 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished">%1 удалены из чата</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -983,6 +1009,23 @@
|
|||
<source>You</source>
|
||||
<translation>Вы</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -995,6 +1038,14 @@
|
|||
<translation>Это сообщение было переадресовано. Первоначальный автор: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1464,6 +1515,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1933,5 +1996,23 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished">%1 удалены из чата</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -823,6 +823,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation>har tagit bort %1 från chatten</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -973,6 +997,21 @@
|
|||
<source>You</source>
|
||||
<translation>Du</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -985,6 +1024,14 @@
|
|||
<translation>Detta meddelande är vidarebefordrat. Ursprunglig avsändare: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1443,6 +1490,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1912,5 +1971,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation>har tagit bort %1 från chatten</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -814,6 +814,28 @@
|
|||
<comment>myself</comment>
|
||||
<translation>已从此对话移除 %1</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -964,6 +986,19 @@
|
|||
<source>You</source>
|
||||
<translation>你</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -976,6 +1011,14 @@
|
|||
<translation>此消息为转发消息,原作者: %1</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1423,6 +1466,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1892,5 +1947,21 @@
|
|||
<comment>myself</comment>
|
||||
<translation>已从此对话移除 %1</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
|
@ -823,6 +823,30 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
|
@ -973,6 +997,21 @@
|
|||
<source>You</source>
|
||||
<translation>You</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points in %2</source>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageOverlayFlickable</name>
|
||||
|
@ -985,6 +1024,14 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageViaLabel</name>
|
||||
<message>
|
||||
<source>via %1</source>
|
||||
<comment>message posted via bot user</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>NewChatPage</name>
|
||||
<message>
|
||||
|
@ -1443,6 +1490,18 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Disables offline caching. Certain features may be limited or missing in this mode. Changes require a restart of Fernschreiber to take effect.</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Privacy</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Allow sending Location to inline bots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Some inline bots request location data when using them</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
|
@ -1912,5 +1971,22 @@
|
|||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>scored %Ln points</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<comment>myself</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>sent a game</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
Loading…
Reference in a new issue