Merge pull request #327 from jgibbon/feature/messageContent_fileinfo_items
Add TDLibImage/TDLibThumbnail; rework Audio/VoiceNote/Document
This commit is contained in:
commit
32f884e547
26 changed files with 666 additions and 697 deletions
|
@ -61,6 +61,8 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
||||||
qml/components/ReplyMarkupButtons.qml \
|
qml/components/ReplyMarkupButtons.qml \
|
||||||
qml/components/StickerPicker.qml \
|
qml/components/StickerPicker.qml \
|
||||||
qml/components/PhotoTextsListItem.qml \
|
qml/components/PhotoTextsListItem.qml \
|
||||||
|
qml/components/TDLibImage.qml \
|
||||||
|
qml/components/TDLibThumbnail.qml \
|
||||||
qml/components/VoiceNoteOverlay.qml \
|
qml/components/VoiceNoteOverlay.qml \
|
||||||
qml/components/chatInformationPage/ChatInformationEditArea.qml \
|
qml/components/chatInformationPage/ChatInformationEditArea.qml \
|
||||||
qml/components/chatInformationPage/ChatInformationPageContent.qml \
|
qml/components/chatInformationPage/ChatInformationPageContent.qml \
|
||||||
|
@ -91,6 +93,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
||||||
qml/components/messageContent/MessageAnimation.qml \
|
qml/components/messageContent/MessageAnimation.qml \
|
||||||
qml/components/messageContent/MessageAudio.qml \
|
qml/components/messageContent/MessageAudio.qml \
|
||||||
qml/components/messageContent/MessageContentBase.qml \
|
qml/components/messageContent/MessageContentBase.qml \
|
||||||
|
qml/components/messageContent/MessageContentFileInfoBase.qml \
|
||||||
qml/components/messageContent/MessageDocument.qml \
|
qml/components/messageContent/MessageDocument.qml \
|
||||||
qml/components/messageContent/MessageGame.qml \
|
qml/components/messageContent/MessageGame.qml \
|
||||||
qml/components/messageContent/MessageLocation.qml \
|
qml/components/messageContent/MessageLocation.qml \
|
||||||
|
|
39
images/icon-m-copy-to-folder.svg
Normal file
39
images/icon-m-copy-to-folder.svg
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xml:space="preserve"
|
||||||
|
style="enable-background:new 0 0 64 64;"
|
||||||
|
viewBox="0 0 64 64"
|
||||||
|
y="0px"
|
||||||
|
x="0px"
|
||||||
|
id="Layer_1"
|
||||||
|
version="1.1"><metadata
|
||||||
|
id="metadata17"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs15">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff"
|
||||||
|
d="m 37.855477,15.759299 c -1.73926,0.0029 -4.47725,1.553014 -6.64098,2.8829 -1.6826,1.034172 -3.75291,1.108852 -5.69886,1.124912 h -8.64063 c -1.034,0 -1.875,0.841 -1.875,1.875 v 8.070312 l 2,1.359376 v -9.304688 h 8.51563 c 2.75742,-0.06081 4.84074,-0.2051 6.5836,-1.513027 2.1377,-1.604239 4.80361,-2.501457 7.17616,-2.486973 h 18.51758 c 0.666,0 1.20703,0.541031 1.20703,1.207031 v 31.542969 c 0,0.689 -0.561,1.25 -1.25,1.25 h -39.5 c -0.689,0 -1.25,-0.561 -1.25,-1.25 V 42.08547 l -2,1.359375 v 7.072266 c 0,1.792 1.458,3.25 3.25,3.25 h 39.5 c 1.792,0 3.25,-1.458 3.25,-3.25 V 18.974142 c 0,-1.769 -1.43803,-3.207984 -3.20703,-3.208984 h -18.51758 c -0.4765,0 -0.94899,-0.01047 -1.41992,-0.0059 z"
|
||||||
|
id="path6-9" /><path
|
||||||
|
id="path11-6"
|
||||||
|
d="m 12.995027,29.476688 10.626,7.222 -10.626,7.222 v -14.444 m -2,-1.778 v 18 c 0,1.1 0.744,1.494 1.654,0.876 l 12.875,-8.752 c 0.455,-0.309 0.682,-0.717 0.682,-1.124 0,-0.408 -0.227,-0.815 -0.682,-1.124 l -12.875,-8.751 c -0.91,-0.619 -1.654,-0.225 -1.654,0.875 z"
|
||||||
|
style="fill:#ffffff" /><path
|
||||||
|
id="path5-0"
|
||||||
|
d="m 15.000437,21.683979 v -6.5 c 0,-1.832003 1.6,-3.500003 3.357,-3.500003 h 10.636 c 1.967,0 3.809,0.854 4.848,2.238003 l 3.457,2.756 c -2.99546,1.819905 -4.21018,2.916329 -6.43718,3.672261 -5.13259,1.742208 -10.47736,1.018549 -15.86082,1.333739 z"
|
||||||
|
style="opacity:0.6;fill:#ffffff" /><path
|
||||||
|
id="path9-3-6"
|
||||||
|
d="m 3.3670166,11.247132 c -0.004,1.278302 0.0179,17.502612 0.0179,17.502612 v 0.0059 0.0059 c 0.0626,4.141039 2.28159,6.407836 4.41211,7.382812 2.13052,0.974976 4.2070304,0.853516 4.2070304,0.853516"
|
||||||
|
style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none" /></svg>
|
After Width: | Height: | Size: 2.4 KiB |
55
qml/components/TDLibImage.qml
Normal file
55
qml/components/TDLibImage.qml
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Sebastian J. Wolf and other contributors
|
||||||
|
|
||||||
|
This file is part of Fernschreiber.
|
||||||
|
|
||||||
|
Fernschreiber is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Fernschreiber is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
import QtQuick 2.6
|
||||||
|
import WerkWolf.Fernschreiber 1.0
|
||||||
|
import Sailfish.Silica 1.0
|
||||||
|
|
||||||
|
import "../js/debug.js" as Debug
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: tdLibImage
|
||||||
|
property alias fileInformation: file.fileInformation
|
||||||
|
readonly property alias file: file
|
||||||
|
property bool highlighted
|
||||||
|
|
||||||
|
asynchronous: true
|
||||||
|
enabled: !!file.fileId
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
clip: true
|
||||||
|
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||||
|
source: enabled && file.isDownloadingCompleted ? file.path : ""
|
||||||
|
visible: opacity > 0
|
||||||
|
sourceSize {
|
||||||
|
width: width
|
||||||
|
height: height
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
|
||||||
|
layer {
|
||||||
|
enabled: tdLibImage.enabled && tdLibImage.highlighted
|
||||||
|
effect: PressEffect { source: tdLibImage }
|
||||||
|
}
|
||||||
|
|
||||||
|
TDLibFile {
|
||||||
|
id: file
|
||||||
|
autoLoad: true
|
||||||
|
tdlib: tdLibWrapper
|
||||||
|
}
|
||||||
|
}
|
129
qml/components/TDLibThumbnail.qml
Normal file
129
qml/components/TDLibThumbnail.qml
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
/*
|
||||||
|
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 Nemo.Thumbnailer 1.0
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: tdlibThumbnail
|
||||||
|
/*
|
||||||
|
Optional thumbnail, usually as property "thumbnail".
|
||||||
|
The following TDLib objects can have it:
|
||||||
|
- animation
|
||||||
|
- audio (as "album_cover_thumbnail")
|
||||||
|
- document
|
||||||
|
- sticker (no minithumbnail)
|
||||||
|
- video
|
||||||
|
- videoNote
|
||||||
|
- stickerSet (no minithumbnail)
|
||||||
|
- stickerSetInfo (no minithumbnail)
|
||||||
|
- inlineQueryResultArticle (no minithumbnail)
|
||||||
|
- inlineQueryResultContact (no minithumbnail)
|
||||||
|
- inlineQueryResultLocation (no minithumbnail)
|
||||||
|
- inlineQueryResultVenue (no minithumbnail)
|
||||||
|
*/
|
||||||
|
property var thumbnail
|
||||||
|
/*
|
||||||
|
Optional minithumbnail, usually as property "minithumbnail".
|
||||||
|
Has data inline: If present, it doesn't need another request.
|
||||||
|
The following TDLib objects can have it:
|
||||||
|
- animation
|
||||||
|
- audio (as "album_cover_minithumbnail")
|
||||||
|
- document
|
||||||
|
- photo / chatPhoto (Note: No thumbnail, so not applicable here)
|
||||||
|
- video
|
||||||
|
- videoNote
|
||||||
|
*/
|
||||||
|
property var minithumbnail
|
||||||
|
property bool useBackgroundImage: true
|
||||||
|
property bool highlighted
|
||||||
|
|
||||||
|
property bool isVideo: !!thumbnail && thumbnail.format["@type"] === "thumbnailFormatMpeg4"
|
||||||
|
property string videoMimeType: "video/mp4"
|
||||||
|
|
||||||
|
readonly property bool hasVisibleThumbnail: thumbnailImage.opacity !== 1.0
|
||||||
|
&& !(videoThumbnailLoader.item && videoThumbnailLoader.item.opacity === 1.0)
|
||||||
|
|
||||||
|
layer {
|
||||||
|
enabled: highlighted
|
||||||
|
effect: PressEffect { source: tdlibThumbnail }
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: backgroundLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
active: !parent.hasVisibleThumbnail
|
||||||
|
asynchronous: true
|
||||||
|
sourceComponent: !!parent.minithumbnail ? miniThumbnailComponent : parent.useBackgroundImage ? backgroundImageComponent : ""
|
||||||
|
Component {
|
||||||
|
id: backgroundImageComponent
|
||||||
|
BackgroundImage {}
|
||||||
|
}
|
||||||
|
Component {
|
||||||
|
id: miniThumbnailComponent
|
||||||
|
Image {
|
||||||
|
clip: true
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||||
|
smooth: false
|
||||||
|
source: "data:image/jpg;base64," + tdlibThumbnail.miniThumbnail.data
|
||||||
|
visible: opacity > 0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// image thumbnail
|
||||||
|
TDLibImage {
|
||||||
|
id: thumbnailImage
|
||||||
|
anchors.fill: parent
|
||||||
|
enabled: !parent.isVideo
|
||||||
|
fileInformation: tdlibThumbnail.thumbnail ? tdlibThumbnail.thumbnail.file : {}
|
||||||
|
onStatusChanged: { //TODO check if this is really how it is ;)
|
||||||
|
if(status === Image.Error) {
|
||||||
|
// in some cases, webp is used (without correct mime type).
|
||||||
|
// we just try it blindly and cross our fingers:
|
||||||
|
tdlibThumbnail.videoMimeType = "image/webp";
|
||||||
|
tdlibThumbnail.isVideo = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for video thumbnail format: try to use Nemo.Thumbnailer
|
||||||
|
Loader {
|
||||||
|
id: videoThumbnailLoader
|
||||||
|
active: parent.isVideo
|
||||||
|
asynchronous: true
|
||||||
|
anchors.fill: parent
|
||||||
|
sourceComponent: Component {
|
||||||
|
id: videoThumbnail
|
||||||
|
Thumbnail {
|
||||||
|
id: thumbnail
|
||||||
|
source: thumbnailImage.file.path
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: height
|
||||||
|
mimeType: tdlibThumbnail.videoMimeType
|
||||||
|
visible: opacity > 0
|
||||||
|
opacity: status === Thumbnail.Ready ? 1.0 : 0.0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,455 +20,77 @@ import QtQuick 2.6
|
||||||
import Sailfish.Silica 1.0
|
import Sailfish.Silica 1.0
|
||||||
import QtMultimedia 5.6
|
import QtMultimedia 5.6
|
||||||
import "../"
|
import "../"
|
||||||
|
import "../../js/twemoji.js" as Emoji
|
||||||
import "../../js/functions.js" as Functions
|
import "../../js/functions.js" as Functions
|
||||||
import "../../js/debug.js" as Debug
|
import "../../js/debug.js" as Debug
|
||||||
|
|
||||||
|
|
||||||
MessageContentBase {
|
MessageContentFileInfoBase {
|
||||||
id: audioMessageComponent
|
id: contentItem
|
||||||
|
|
||||||
property var audioData: ( rawMessage.content['@type'] === "messageVoiceNote" ) ? rawMessage.content.voice_note : ( ( rawMessage.content['@type'] === "messageAudio" ) ? rawMessage.content.audio : "");
|
fileInformation: rawMessage.content.audio.audio
|
||||||
property string audioUrl;
|
thumbnail: rawMessage.content.audio.album_cover_thumbnail
|
||||||
property int previewFileId;
|
minithumbnail: rawMessage.content.audio.album_cover_minithumbnail
|
||||||
property int audioFileId;
|
|
||||||
property bool onScreen: messageListItem ? messageListItem.page.status === PageStatus.Active : true
|
|
||||||
property string audioType : "voiceNote";
|
|
||||||
|
|
||||||
height: width / 2
|
primaryText: Emoji.emojify(rawMessage.content.audio.performer, primaryLabel.font.pixelSize)
|
||||||
|
secondaryText: Emoji.emojify(rawMessage.content.audio.title, secondaryLabel.font.pixelSize)
|
||||||
|
tertiaryLabel.visible: (duration || (audioPlayer.duration/1000)) > 0
|
||||||
|
tertiaryText: (audioPlayer.position > 0 || audioPlayer.playbackState === Audio.PlayingState ? (Format.formatDuration(audioPlayer.position/1000, Formatter.DurationShort)+" / ") : "") + Format.formatDuration(contentItem.duration > 0 ? contentItem.duration : (audioPlayer.duration/1000), Formatter.DurationShort)
|
||||||
|
|
||||||
function getTimeString(rawSeconds) {
|
leftButton {
|
||||||
var minutes = Math.floor( rawSeconds / 60 );
|
icon.source: audioPlayer.playbackState === Audio.PlayingState || (file.isDownloadingActive && audioPlayer.autoPlay) ? "image://theme/icon-m-pause": "image://theme/icon-m-play"
|
||||||
var seconds = rawSeconds - ( minutes * 60 );
|
|
||||||
|
|
||||||
if ( minutes < 10 ) {
|
|
||||||
minutes = "0" + minutes;
|
|
||||||
}
|
|
||||||
if ( seconds < 10 ) {
|
|
||||||
seconds = "0" + seconds;
|
|
||||||
}
|
|
||||||
return minutes + ":" + seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
updateAudioThumbnail();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateAudioThumbnail() {
|
|
||||||
if (audioData) {
|
|
||||||
audioType = ( audioData['@type'] === "voiceNote" ) ? "voice" : "audio";
|
|
||||||
audioFileId = audioData[audioType].id;
|
|
||||||
if (typeof audioData.album_cover_thumbnail !== "undefined") {
|
|
||||||
previewFileId = audioData.album_cover_thumbnail.file.id;
|
|
||||||
if (audioData.album_cover_thumbnail.file.local.is_downloading_completed) {
|
|
||||||
placeholderImage.source = audioData.album_cover_thumbnail.file.local.path;
|
|
||||||
} else {
|
|
||||||
tdLibWrapper.downloadFile(previewFileId);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
placeholderImage.source = "image://theme/icon-l-music?white";
|
|
||||||
placeholderImage.width = Theme.itemSizeLarge
|
|
||||||
placeholderImage.height = Theme.itemSizeLarge
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePlay() {
|
|
||||||
if (audioData[audioType].local.is_downloading_completed) {
|
|
||||||
audioUrl = audioData[audioType].local.path;
|
|
||||||
audioComponentLoader.active = true;
|
|
||||||
} else {
|
|
||||||
audioDownloadBusyIndicator.running = true;
|
|
||||||
tdLibWrapper.downloadFile(audioFileId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: tdLibWrapper
|
|
||||||
onFileUpdated: {
|
|
||||||
if (typeof audioData === "object") {
|
|
||||||
if (fileInformation.local.is_downloading_completed) {
|
|
||||||
if (fileId === previewFileId) {
|
|
||||||
audioData.album_cover_thumbnail.file = fileInformation;
|
|
||||||
placeholderImage.source = fileInformation.local.path;
|
|
||||||
}
|
|
||||||
if (fileId === audioFileId) {
|
|
||||||
audioDownloadBusyIndicator.running = false;
|
|
||||||
audioData[audioType] = fileInformation;
|
|
||||||
audioUrl = fileInformation.local.path;
|
|
||||||
if (onScreen) {
|
|
||||||
audioComponentLoader.active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fileId === audioFileId) {
|
|
||||||
downloadingProgressBar.maximumValue = fileInformation.size;
|
|
||||||
downloadingProgressBar.value = fileInformation.local.downloaded_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: placeholderImage
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
anchors.centerIn: parent
|
|
||||||
asynchronous: true
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
visible: status === Image.Ready ? true : false
|
|
||||||
layer.enabled: audioMessageComponent.highlighted
|
|
||||||
layer.effect: PressEffect { source: placeholderImage }
|
|
||||||
}
|
|
||||||
|
|
||||||
BackgroundImage {
|
|
||||||
id: backgroundImage
|
|
||||||
visible: placeholderImage.status !== Image.Ready
|
|
||||||
layer.enabled: audioMessageComponent.highlighted
|
|
||||||
layer.effect: PressEffect { source: backgroundImage }
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: placeholderBackground
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.3
|
|
||||||
height: parent.height
|
|
||||||
width: parent.width
|
|
||||||
visible: playButton.visible
|
|
||||||
}
|
|
||||||
Label {
|
|
||||||
visible: !!(audioData.performer || audioData.title)
|
|
||||||
color: placeholderBackground.visible ? "white" : Theme.secondaryHighlightColor
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
anchors {
|
|
||||||
fill: placeholderBackground
|
|
||||||
margins: Theme.paddingSmall
|
|
||||||
}
|
|
||||||
text: audioData.performer + (audioData.performer && audioData.title ? " - " : "") + audioData.title
|
|
||||||
font.pixelSize: Theme.fontSizeTiny
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
width: parent.width
|
|
||||||
height: downloadingProgressBar.height + audioControlRow.height
|
|
||||||
anchors.centerIn: parent
|
|
||||||
Row {
|
|
||||||
id: audioControlRow
|
|
||||||
width: parent.width
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
Item {
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
width: downloadItem.visible ? parent.width / 2 : parent.width
|
|
||||||
IconButton {
|
|
||||||
id: playButton
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Theme.iconSizeLarge
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
icon {
|
|
||||||
source: "image://theme/icon-l-play?white"
|
|
||||||
asynchronous: true
|
|
||||||
}
|
|
||||||
highlighted: audioMessageComponent.highlighted || down
|
|
||||||
visible: placeholderImage.status === Image.Ready ? true : false
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
handlePlay();
|
if(!file.isDownloadingCompleted && !file.isDownloadingActive) {
|
||||||
}
|
file.load();
|
||||||
}
|
audioPlayer.autoPlay = true;
|
||||||
BusyIndicator {
|
} else if(file.isDownloadingActive) {
|
||||||
id: audioDownloadBusyIndicator
|
audioPlayer.autoPlay = false;
|
||||||
running: false
|
file.cancel();
|
||||||
visible: running
|
} else if(file.isDownloadingCompleted) {
|
||||||
anchors.centerIn: parent
|
//playPause
|
||||||
size: BusyIndicatorSize.Large
|
if(audioPlayer.playbackState === Audio.PlayingState) {
|
||||||
}
|
audioPlayer.pause();
|
||||||
}
|
|
||||||
Item {
|
|
||||||
id: downloadItem
|
|
||||||
width: parent.width / 2
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
visible: audioData[audioType].local.is_downloading_completed
|
|
||||||
Rectangle {
|
|
||||||
color: Theme.primaryColor
|
|
||||||
opacity: Theme.opacityFaint
|
|
||||||
width: Theme.iconSizeLarge * 0.9
|
|
||||||
height: Theme.iconSizeLarge * 0.9
|
|
||||||
anchors.centerIn: parent
|
|
||||||
radius: width / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: downloadButton
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Theme.iconSizeLarge
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
icon {
|
|
||||||
source: "image://theme/icon-m-cloud-download?white"
|
|
||||||
asynchronous: true
|
|
||||||
}
|
|
||||||
highlighted: audioMessageComponent.highlighted || down
|
|
||||||
onClicked: {
|
|
||||||
tdLibWrapper.copyFileToDownloads(audioData[audioType].local.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ProgressBar {
|
|
||||||
id: downloadingProgressBar
|
|
||||||
minimumValue: 0
|
|
||||||
maximumValue: 100
|
|
||||||
value: 0
|
|
||||||
visible: audioDownloadBusyIndicator.visible
|
|
||||||
width: parent.width
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: audioErrorShade
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
color: "lightgrey"
|
|
||||||
visible: placeholderImage.status === Image.Error ? true : false
|
|
||||||
opacity: 0.3
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: errorTextOverlay
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.8
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
visible: false
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: errorText
|
|
||||||
visible: false
|
|
||||||
width: parent.width
|
|
||||||
color: Theme.primaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeExtraSmall
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
text: ""
|
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: audioComponentLoader
|
|
||||||
active: false
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
sourceComponent: audioComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
Component {
|
|
||||||
id: audioComponent
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: parent ? parent.width : 0
|
|
||||||
height: parent ? parent.height : 0
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: messageAudio
|
|
||||||
onPlaying: {
|
|
||||||
playButton.visible = false;
|
|
||||||
downloadItem.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: audioMessageComponent
|
|
||||||
onClicked: {
|
|
||||||
if (messageAudio.playbackState === MediaPlayer.PlayingState) {
|
|
||||||
messageAudio.pause();
|
|
||||||
timeLeftItem.visible = true;
|
|
||||||
} else {
|
} else {
|
||||||
messageAudio.play();
|
audioPlayer.play();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
property int duration: rawMessage.content.audio.duration
|
||||||
|
|
||||||
Audio {
|
Audio {
|
||||||
id: messageAudio
|
id: audioPlayer
|
||||||
|
source: file.isDownloadingCompleted ? file.path : ""
|
||||||
Component.onCompleted: {
|
autoPlay: false
|
||||||
if (messageAudio.error === MediaPlayer.NoError) {
|
|
||||||
messageAudio.play();
|
|
||||||
} else {
|
|
||||||
errorText.text = qsTr("Error loading audio! " + messageAudio.errorString)
|
|
||||||
errorTextOverlay.visible = true;
|
|
||||||
errorText.visible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onStatusChanged: {
|
|
||||||
if (status == MediaPlayer.NoMedia) {
|
|
||||||
Debug.log("No Media");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.Loading) {
|
|
||||||
Debug.log("Loading");
|
|
||||||
audioBusyIndicator.visible = true;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.Loaded) {
|
|
||||||
Debug.log("Loaded");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.Buffering) {
|
|
||||||
Debug.log("Buffering");
|
|
||||||
audioBusyIndicator.visible = true;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.Stalled) {
|
|
||||||
Debug.log("Stalled");
|
|
||||||
audioBusyIndicator.visible = true;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.Buffered) {
|
|
||||||
Debug.log("Buffered");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.EndOfMedia) {
|
|
||||||
Debug.log("End of Media");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.InvalidMedia) {
|
|
||||||
Debug.log("Invalid Media");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
if (status == MediaPlayer.UnknownStatus) {
|
|
||||||
Debug.log("Unknown Status");
|
|
||||||
audioBusyIndicator.visible = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
source: audioUrl
|
|
||||||
|
|
||||||
onStopped: {
|
|
||||||
playButton.visible = true;
|
|
||||||
downloadItem.visible = true;
|
|
||||||
audioComponentLoader.active = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
id: audioBusyIndicator
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
visible: false
|
|
||||||
running: visible
|
|
||||||
size: BusyIndicatorSize.Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: timeLeftItem
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
opacity: visible ? 1 : 0
|
|
||||||
Behavior on opacity { NumberAnimation {} }
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: positionTextOverlay
|
|
||||||
color: "black"
|
|
||||||
opacity: 0.3
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
visible: pausedRow.visible
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: pausedRow
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height - ( messageAudioSlider.visible ? messageAudioSlider.height : 0 ) - ( positionText.visible ? positionText.height : 0 )
|
|
||||||
visible: audioComponentLoader.active && messageAudio.playbackState === MediaPlayer.PausedState
|
|
||||||
Item {
|
|
||||||
height: parent.height
|
|
||||||
width: parent.width / 2
|
|
||||||
IconButton {
|
|
||||||
id: pausedPlayButton
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Theme.iconSizeLarge
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
highlighted: audioMessageComponent.highlighted || down
|
|
||||||
icon {
|
|
||||||
asynchronous: true
|
|
||||||
source: "image://theme/icon-l-play?white"
|
|
||||||
}
|
|
||||||
onClicked: {
|
|
||||||
messageAudio.play();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Item {
|
|
||||||
id: pausedDownloadItem
|
|
||||||
width: parent.width / 2
|
|
||||||
height: parent.height
|
|
||||||
Rectangle {
|
|
||||||
color: Theme.primaryColor
|
|
||||||
opacity: Theme.opacityFaint
|
|
||||||
width: Theme.iconSizeLarge * 0.9
|
|
||||||
height: Theme.iconSizeLarge * 0.9
|
|
||||||
anchors.centerIn: parent
|
|
||||||
radius: width / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton {
|
|
||||||
id: pausedDownloadButton
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: Theme.iconSizeLarge
|
|
||||||
height: Theme.iconSizeLarge
|
|
||||||
icon {
|
|
||||||
source: "image://theme/icon-m-cloud-download?white"
|
|
||||||
asynchronous: true
|
|
||||||
}
|
|
||||||
highlighted: audioMessageComponent.highlighted || down
|
|
||||||
onClicked: {
|
|
||||||
tdLibWrapper.copyFileToDownloads(audioData[audioType].local.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider {
|
Slider {
|
||||||
id: messageAudioSlider
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.bottom: positionText.top
|
|
||||||
minimumValue: 0
|
|
||||||
maximumValue: messageAudio.duration ? messageAudio.duration : 0.1
|
|
||||||
stepSize: 1
|
|
||||||
value: messageAudio.position
|
|
||||||
enabled: messageAudio.seekable
|
|
||||||
visible: (messageAudio.duration > 0)
|
|
||||||
highlighted: audioMessageComponent.highlighted || down
|
|
||||||
onReleased: {
|
|
||||||
messageAudio.seek(Math.floor(value));
|
|
||||||
messageAudio.play();
|
|
||||||
}
|
|
||||||
valueText: getTimeString(Math.round((messageAudio.duration - messageAudioSlider.value) / 1000))
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
id: positionText
|
|
||||||
visible: messageAudio.duration === 0
|
|
||||||
color: Theme.primaryColor
|
|
||||||
font.pixelSize: Theme.fontSizeTiny
|
|
||||||
anchors {
|
anchors {
|
||||||
bottom: parent.bottom
|
left: parent.left
|
||||||
bottomMargin: Theme.paddingSmall
|
leftMargin: -Screen.width/16
|
||||||
horizontalCenter: positionTextOverlay.horizontalCenter
|
right: parent.right
|
||||||
}
|
rightMargin: -Screen.width/16
|
||||||
wrapMode: Text.Wrap
|
top: primaryItem.bottom
|
||||||
text: ( messageAudio.duration - messageAudio.position ) > 0 ? getTimeString(Math.round((messageAudio.duration - messageAudio.position) / 1000)) : "-:-"
|
topMargin: -height/3
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
minimumValue: 0
|
||||||
|
maximumValue: audioPlayer.duration ? audioPlayer.duration : 0.1
|
||||||
|
stepSize: 1
|
||||||
|
value: audioPlayer.position
|
||||||
|
enabled: audioPlayer.seekable
|
||||||
|
visible: file.isDownloadingCompleted && audioPlayer.playbackState === Audio.PlayingState || audioPlayer.playbackState === Audio.PausedState
|
||||||
|
opacity: visible ? 1.0 : 0.0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
height: visible ? implicitHeight : 0
|
||||||
|
Behavior on height { NumberAnimation { duration: 200 } }
|
||||||
|
|
||||||
|
highlighted: contentItem.highlighted || down
|
||||||
|
onReleased: {
|
||||||
|
audioPlayer.seek(Math.floor(value));
|
||||||
|
audioPlayer.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
201
qml/components/messageContent/MessageContentFileInfoBase.qml
Normal file
201
qml/components/messageContent/MessageContentFileInfoBase.qml
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
/*
|
||||||
|
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 "../"
|
||||||
|
import "../../js/functions.js" as Functions
|
||||||
|
import "../../js/twemoji.js" as Emoji
|
||||||
|
import "../../js/debug.js" as Debug
|
||||||
|
|
||||||
|
MessageContentBase {
|
||||||
|
id: contentItem
|
||||||
|
height: childrenRect.height
|
||||||
|
property alias fileInformation: file.fileInformation
|
||||||
|
property alias primaryLabel: primaryLabel
|
||||||
|
property alias primaryText: primaryLabel.text
|
||||||
|
property alias secondaryLabel: secondaryLabel
|
||||||
|
property alias secondaryText: secondaryLabel.text
|
||||||
|
property alias tertiaryLabel: tertiaryLabel
|
||||||
|
property alias tertiaryText: tertiaryLabel.text
|
||||||
|
property var thumbnail
|
||||||
|
property var minithumbnail
|
||||||
|
|
||||||
|
readonly property alias file: file
|
||||||
|
readonly property alias primaryItem: primaryItem
|
||||||
|
readonly property alias leftButton: leftButton
|
||||||
|
readonly property alias labelsColumn: labelsColumn
|
||||||
|
readonly property alias copyButton: copyButton
|
||||||
|
// readonly property alias downloadNeededIndicatorIcon: downloadNeededIndicatorIcon
|
||||||
|
|
||||||
|
TDLibFile {
|
||||||
|
id: file
|
||||||
|
tdlib: tdLibWrapper
|
||||||
|
autoLoad: false
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: primaryItem
|
||||||
|
width: parent.width
|
||||||
|
height: Theme.itemSizeLarge
|
||||||
|
Loader {
|
||||||
|
active: contentItem.thumbnail || contentItem.minithumbnail
|
||||||
|
visible: active
|
||||||
|
anchors.fill: leftButton
|
||||||
|
sourceComponent: Component {
|
||||||
|
TDLibThumbnail {
|
||||||
|
opacity: 0.3
|
||||||
|
thumbnail: contentItem.thumbnail
|
||||||
|
minithumbnail: contentItem.minithumbnail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton {
|
||||||
|
id: leftButton
|
||||||
|
highlighted: down || contentItem.highlighted
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
icon {
|
||||||
|
asynchronous: true
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressCircle {
|
||||||
|
value: file.downloadedSize / file.expectedSize
|
||||||
|
progressColor: Theme.highlightColor
|
||||||
|
backgroundColor: Theme.highlightDimmerColor
|
||||||
|
width: Theme.iconSizeMedium
|
||||||
|
height: Theme.iconSizeMedium
|
||||||
|
visible: opacity > 0
|
||||||
|
opacity: file.isDownloadingActive ? 1.0 : 0.0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
}
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: downloadNeededIndicatorIcon
|
||||||
|
width: downloadNeededIndicatorIcon.width + Theme.paddingMedium
|
||||||
|
height: width
|
||||||
|
|
||||||
|
color: Theme.rgba(Theme.overlayBackgroundColor, 0.2)
|
||||||
|
opacity: file.isDownloadingActive ? 1.0 : 0.0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
visible: opacity > 0
|
||||||
|
radius: width/2
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon {
|
||||||
|
id: downloadNeededIndicatorIcon
|
||||||
|
source: file.isDownloadingActive || file.isDownloadingCompleted ? "image://theme/icon-s-clear-opaque-cross" : "image://theme/icon-s-cloud-download"
|
||||||
|
asynchronous: true
|
||||||
|
width: Theme.iconSizeExtraSmall
|
||||||
|
height: width
|
||||||
|
visible: opacity > 0
|
||||||
|
sourceSize.width: width
|
||||||
|
sourceSize.height: height
|
||||||
|
opacity: file.isDownloadingCompleted ? 0.0 : 1.0
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
margins: Theme.paddingSmall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
id: labelsColumn
|
||||||
|
anchors {
|
||||||
|
left: leftButton.right
|
||||||
|
leftMargin: Theme.paddingSmall
|
||||||
|
right: copyButton.left
|
||||||
|
verticalCenter: leftButton.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: primaryLabel
|
||||||
|
width: parent.width
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
fontSizeMode: Text.HorizontalFit
|
||||||
|
minimumPixelSize: Theme.fontSizeTiny
|
||||||
|
color: Theme.highlightColor
|
||||||
|
visible: text.length > 0
|
||||||
|
truncationMode: TruncationMode.Fade
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
id: secondaryLabel
|
||||||
|
width: parent.width
|
||||||
|
font.pixelSize: Theme.fontSizeExtraSmall
|
||||||
|
fontSizeMode: Text.HorizontalFit
|
||||||
|
minimumPixelSize: Theme.fontSizeTiny
|
||||||
|
color: Theme.secondaryHighlightColor
|
||||||
|
visible: text.length > 0
|
||||||
|
truncationMode: TruncationMode.Fade
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
height: sizeLabel.height
|
||||||
|
width: parent.width
|
||||||
|
Label {
|
||||||
|
id: tertiaryLabel
|
||||||
|
font.pixelSize: Theme.fontSizeTiny
|
||||||
|
color: highlighted ? Theme.secondaryHighlightColor : Theme.secondaryColor
|
||||||
|
visible: text.length > 0
|
||||||
|
truncationMode: TruncationMode.Fade
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: sizeLabel
|
||||||
|
anchors.right: parent.right
|
||||||
|
font.pixelSize: Theme.fontSizeTiny
|
||||||
|
color: tertiaryLabel.color
|
||||||
|
text: Format.formatFileSize(file.size || file.expectedSize)
|
||||||
|
visible: (file.size || file.expectedSize) > 0
|
||||||
|
truncationMode: TruncationMode.Fade
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IconButton {
|
||||||
|
id: copyButton
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
opacity: file.isDownloadingCompleted ? 1.0 : 0.0
|
||||||
|
width: file.isDownloadingCompleted ? Theme.itemSizeMedium : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
|
||||||
|
Behavior on opacity { FadeAnimation {} }
|
||||||
|
Behavior on width { NumberAnimation { duration: 200 } }
|
||||||
|
icon {
|
||||||
|
asynchronous: true
|
||||||
|
source: "../../../images/icon-m-copy-to-folder.svg"
|
||||||
|
sourceSize {
|
||||||
|
width: Theme.iconSizeMedium
|
||||||
|
height: Theme.iconSizeMedium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
tdLibWrapper.copyFileToDownloads(file.path);
|
||||||
|
// not persistent:
|
||||||
|
opacity = 0;
|
||||||
|
width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,108 +18,65 @@
|
||||||
*/
|
*/
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
import Sailfish.Silica 1.0
|
import Sailfish.Silica 1.0
|
||||||
|
import "../../js/twemoji.js" as Emoji
|
||||||
|
|
||||||
MessageContentBase {
|
MessageContentFileInfoBase {
|
||||||
|
id: contentItem
|
||||||
|
fileInformation: rawMessage.content.document.document
|
||||||
|
|
||||||
id: documentPreviewItem
|
primaryText: Emoji.emojify(rawMessage.content.document.file_name || "", primaryLabel.font.pixelSize)
|
||||||
height: Theme.itemSizeLarge
|
secondaryText: Emoji.emojify(Functions.enhanceMessageText(rawMessage.content.caption) || "", secondaryLabel.font.pixelSize)
|
||||||
|
|
||||||
property var documentData: rawMessage.content.document
|
minithumbnail: rawMessage.content.document.minithumbnail
|
||||||
property bool openRequested: false;
|
thumbnail: rawMessage.content.document.thumbnail
|
||||||
|
|
||||||
Component.onCompleted: {
|
leftButton {
|
||||||
updateDocument();
|
icon.source: Theme.iconForMimeType(rawMessage.content.document.mime_type)
|
||||||
}
|
onClicked: {
|
||||||
|
if(file.isDownloadingCompleted) {
|
||||||
function updateDocument() {
|
// in this case, the MouseArea should take over
|
||||||
if (documentData) {
|
tdLibWrapper.openFileOnDevice(file.path);
|
||||||
if (documentData.document.local.is_downloading_completed) {
|
} else if(!file.isDownloadingActive) {
|
||||||
downloadDocumentButton.visible = false;
|
file.load();
|
||||||
openDocumentArea.visible = true;
|
|
||||||
} else {
|
} else {
|
||||||
openDocumentArea.visible = false;
|
file.cancel()
|
||||||
downloadDocumentButton.visible = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
states: [
|
||||||
target: tdLibWrapper
|
State {
|
||||||
onFileUpdated: {
|
when: file.isDownloadingCompleted
|
||||||
if (documentData) {
|
PropertyChanges { target: openMouseArea; enabled: true }
|
||||||
if (!fileInformation.remote.is_uploading_active && fileId === documentData.document.id && fileInformation.local.is_downloading_completed) {
|
PropertyChanges {
|
||||||
downloadingProgressBar.visible = false;
|
target: primaryLabel
|
||||||
documentData.document = fileInformation;
|
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.highlightColor : Theme.primaryColor
|
||||||
downloadDocumentButton.visible = false;
|
|
||||||
openDocumentArea.visible = true;
|
|
||||||
if (documentPreviewItem.openRequested) {
|
|
||||||
documentPreviewItem.openRequested = false;
|
|
||||||
tdLibWrapper.openFileOnDevice(documentData.document.local.path);
|
|
||||||
}
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: secondaryLabel
|
||||||
|
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.secondaryHighlightColor : Theme.secondaryColor
|
||||||
}
|
}
|
||||||
if (fileId === documentData.document.id) {
|
PropertyChanges {
|
||||||
downloadingProgressBar.maximumValue = fileInformation.size;
|
target: tertiaryLabel
|
||||||
downloadingProgressBar.value = fileInformation.local.downloaded_size;
|
color: (contentItem.highlighted || openMouseArea.pressed) ? Theme.secondaryHighlightColor : Theme.secondaryColor
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: leftButton
|
||||||
|
highlighted: contentItem.highlighted || openMouseArea.pressed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
]
|
||||||
id: downloadDocumentButton
|
MouseArea {
|
||||||
preferredWidth: Theme.buttonWidthMedium
|
id: openMouseArea
|
||||||
anchors.centerIn: parent
|
enabled: file.isDownloadingCompleted
|
||||||
text: qsTr("Download Document")
|
visible: enabled
|
||||||
visible: false
|
anchors {
|
||||||
highlighted: documentPreviewItem.highlighted || down
|
fill: primaryItem
|
||||||
|
rightMargin: copyButton.width
|
||||||
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
downloadDocumentButton.visible = false;
|
tdLibWrapper.openFileOnDevice(file.path);
|
||||||
downloadingProgressBar.visible = true;
|
|
||||||
tdLibWrapper.downloadFile(documentData.document.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ProgressBar {
|
|
||||||
id: downloadingProgressBar
|
|
||||||
minimumValue: 0
|
|
||||||
maximumValue: 100
|
|
||||||
value: 0
|
|
||||||
visible: false
|
|
||||||
width: parent.width
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: openDocumentArea
|
|
||||||
visible: false
|
|
||||||
spacing: Theme.paddingMedium
|
|
||||||
width: parent.width
|
|
||||||
|
|
||||||
onVisibleChanged: {
|
|
||||||
visible ? (documentPreviewItem.height = openDocumentArea.height) : (documentPreviewItem.height = Theme.itemSizeLarge);
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: openDocumentButton
|
|
||||||
preferredWidth: Theme.buttonWidthMedium
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("Open Document")
|
|
||||||
highlighted: documentPreviewItem.highlighted || down
|
|
||||||
onClicked: {
|
|
||||||
documentPreviewItem.openRequested = true;
|
|
||||||
tdLibWrapper.openFileOnDevice(documentData.document.local.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: copyDocumentButton
|
|
||||||
preferredWidth: Theme.buttonWidthMedium
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
text: qsTr("Copy Document to Downloads")
|
|
||||||
highlighted: documentPreviewItem.highlighted || down
|
|
||||||
onClicked: {
|
|
||||||
tdLibWrapper.copyFileToDownloads(documentData.document.local.path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ MessageContentBase {
|
||||||
|
|
||||||
property string chatId: rawMessage.chat_id
|
property string chatId: rawMessage.chat_id
|
||||||
property var pictureFileInformation;
|
property var pictureFileInformation;
|
||||||
height: width / 2
|
height: width * 0.66666666;
|
||||||
property string fileExtra
|
property string fileExtra
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|
|
@ -18,4 +18,11 @@
|
||||||
*/
|
*/
|
||||||
import QtQuick 2.6
|
import QtQuick 2.6
|
||||||
|
|
||||||
MessageAudio {}
|
MessageAudio {
|
||||||
|
fileInformation: rawMessage.content.voice_note.voice
|
||||||
|
primaryText: qsTr("Voice Note")
|
||||||
|
secondaryText: ""
|
||||||
|
duration: rawMessage.content.voice_note.duration
|
||||||
|
thumbnail: null
|
||||||
|
minithumbnail: null
|
||||||
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ function getMessageText(message, simple, currentUserId, ignoreEntities) {
|
||||||
}
|
}
|
||||||
case 'messageDocument':
|
case 'messageDocument':
|
||||||
if (message.content.document.file_name !== "") {
|
if (message.content.document.file_name !== "") {
|
||||||
return simple ? qsTr("Document: %1").arg(message.content.document.file_name) : (message.content.document.file_name + ( message.content.caption.text !== "" ? ("<br />" + enhanceMessageText(message.content.caption, ignoreEntities) ) : "")).trim();
|
return simple ? qsTr("Document: %1").arg(message.content.document.file_name) : (message.content.caption.text !== "" ? enhanceMessageText(message.content.caption, ignoreEntities) : "").trim();
|
||||||
} else {
|
} else {
|
||||||
return simple ? (myself ? qsTr("sent a document", "myself") : qsTr("sent a document")) : "";
|
return simple ? (myself ? qsTr("sent a document", "myself") : qsTr("sent a document")) : "";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1062,9 +1062,8 @@ Page {
|
||||||
return Functions.getVideoHeight(parentWidth, content.video);
|
return Functions.getVideoHeight(parentWidth, content.video);
|
||||||
case "messageAudio":
|
case "messageAudio":
|
||||||
case "messageVoiceNote":
|
case "messageVoiceNote":
|
||||||
return Theme.itemSizeLarge;
|
|
||||||
case "messageDocument":
|
case "messageDocument":
|
||||||
return Theme.itemSizeSmall;
|
return Theme.itemSizeLarge;
|
||||||
case "messageGame":
|
case "messageGame":
|
||||||
return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3;
|
return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3;
|
||||||
case "messageLocation":
|
case "messageLocation":
|
||||||
|
|
|
@ -194,6 +194,16 @@ void TDLibFile::setAutoLoad(bool enableAutoLoad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TDLibFile::cancel()
|
||||||
|
{
|
||||||
|
if (id && tdLibWrapper && is_downloading_active) {
|
||||||
|
tdLibWrapper->cancelDownloadFile(id);
|
||||||
|
tdLibWrapper->deleteFile(id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool TDLibFile::load()
|
bool TDLibFile::load()
|
||||||
{
|
{
|
||||||
// Manual load ignores hold-off timer
|
// Manual load ignores hold-off timer
|
||||||
|
|
|
@ -78,6 +78,7 @@ public:
|
||||||
bool isUploadingActive() const;
|
bool isUploadingActive() const;
|
||||||
bool isUploadingCompleted() const;
|
bool isUploadingCompleted() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE bool cancel();
|
||||||
Q_INVOKABLE bool load();
|
Q_INVOKABLE bool load();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
|
@ -1146,6 +1146,37 @@ void TDLibWrapper::sendBotStartMessage(qlonglong botUserId, qlonglong chatId, co
|
||||||
this->sendRequest(requestObject);
|
this->sendRequest(requestObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TDLibWrapper::cancelDownloadFile(int fileId)
|
||||||
|
{
|
||||||
|
LOG("Cancel Download File" << fileId);
|
||||||
|
QVariantMap requestObject;
|
||||||
|
requestObject.insert(_TYPE, "cancelDownloadFile");
|
||||||
|
requestObject.insert("file_id", fileId);
|
||||||
|
requestObject.insert("only_if_pending", false);
|
||||||
|
|
||||||
|
this->sendRequest(requestObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDLibWrapper::cancelUploadFile(int fileId)
|
||||||
|
{
|
||||||
|
LOG("Cancel Upload File" << fileId);
|
||||||
|
QVariantMap requestObject;
|
||||||
|
requestObject.insert(_TYPE, "cancelUploadFile");
|
||||||
|
requestObject.insert("file_id", fileId);
|
||||||
|
|
||||||
|
this->sendRequest(requestObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TDLibWrapper::deleteFile(int fileId)
|
||||||
|
{
|
||||||
|
LOG("Delete cached File" << fileId);
|
||||||
|
QVariantMap requestObject;
|
||||||
|
requestObject.insert(_TYPE, "deleteFile");
|
||||||
|
requestObject.insert("file_id", fileId);
|
||||||
|
|
||||||
|
this->sendRequest(requestObject);
|
||||||
|
}
|
||||||
|
|
||||||
void TDLibWrapper::searchEmoji(const QString &queryString)
|
void TDLibWrapper::searchEmoji(const QString &queryString)
|
||||||
{
|
{
|
||||||
LOG("Searching emoji" << queryString);
|
LOG("Searching emoji" << queryString);
|
||||||
|
|
|
@ -193,6 +193,9 @@ public:
|
||||||
Q_INVOKABLE void getInlineQueryResults(qlonglong botUserId, qlonglong chatId, const QVariantMap &userLocation, const QString &query, const QString &offset, const QString &extra);
|
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 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);
|
Q_INVOKABLE void sendBotStartMessage(qlonglong botUserId, qlonglong chatId, const QString ¶meter, const QString &extra);
|
||||||
|
Q_INVOKABLE void cancelDownloadFile(int fileId);
|
||||||
|
Q_INVOKABLE void cancelUploadFile(int fileId);
|
||||||
|
Q_INVOKABLE void deleteFile(int fileId);
|
||||||
|
|
||||||
// Others (candidates for extraction ;))
|
// Others (candidates for extraction ;))
|
||||||
Q_INVOKABLE void searchEmoji(const QString &queryString);
|
Q_INVOKABLE void searchEmoji(const QString &queryString);
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>Über Fernschreiber</translation>
|
<translation>Über Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation>Dokument herunterladen</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation>Dokument öffnen</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation>Dokument zu Downloads kopieren</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation>via %1</translation>
|
<translation>via %1</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>About Fernschreiber</translation>
|
<translation>About Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation>Download Document</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation>Open Document</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation>Copy Document to Downloads</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation>via %1</translation>
|
<translation>via %1</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>Acerca de</translation>
|
<translation>Acerca de</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation>Bajar Documento</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation>Abrir Documento</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation>Copiar documento a Downloads</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1062,7 +1047,7 @@
|
||||||
<source>%Ln vote(s) total</source>
|
<source>%Ln vote(s) total</source>
|
||||||
<comment>number of total votes</comment>
|
<comment>number of total votes</comment>
|
||||||
<translation type="unfinished">
|
<translation type="unfinished">
|
||||||
<numerusform></numerusform>
|
<numerusform>%Ln total de votos</numerusform>
|
||||||
<numerusform></numerusform>
|
<numerusform></numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -931,21 +931,6 @@
|
||||||
<translation>Tietoa Fernschreiberista</translation>
|
<translation>Tietoa Fernschreiberista</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation>Lataa dokumentti</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation>Avaa dokumentti</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1063,8 +1048,8 @@
|
||||||
<source>%Ln vote(s) total</source>
|
<source>%Ln vote(s) total</source>
|
||||||
<comment>number of total votes</comment>
|
<comment>number of total votes</comment>
|
||||||
<translation type="unfinished">
|
<translation type="unfinished">
|
||||||
<numerusform></numerusform>
|
<numerusform>yhteensä %Ln ääni </numerusform>
|
||||||
<numerusform></numerusform>
|
<numerusform>yhteensä %Ln ääntä</numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
@ -1076,6 +1061,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -918,21 +918,6 @@
|
||||||
<translation>A Fernschreiber névjegye</translation>
|
<translation>A Fernschreiber névjegye</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Dokumentum letöltése</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Dokumentum megyitása</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1059,6 +1044,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>Informazioni su Fernschreiber</translation>
|
<translation>Informazioni su Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Scarica documento</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Apri documento</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -942,21 +942,6 @@
|
||||||
<translation>O Fernschreiber</translation>
|
<translation>O Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Pobierz dokument</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Otwórz dokument</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1091,6 +1076,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -942,21 +942,6 @@
|
||||||
<translation>О программе</translation>
|
<translation>О программе</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Скачать документ</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Открыть документ</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished">Сохранить в Загрузках</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1091,6 +1076,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>Om Fernschreiber</translation>
|
<translation>Om Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Ladda ner dokument</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Öppna dokument</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -918,21 +918,6 @@
|
||||||
<translation>关于 Fernschreiber</translation>
|
<translation>关于 Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">下载文档</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">打开文档</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished">复制文档到下载</translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1047,7 +1032,7 @@
|
||||||
<source>%Ln vote(s) total</source>
|
<source>%Ln vote(s) total</source>
|
||||||
<comment>number of total votes</comment>
|
<comment>number of total votes</comment>
|
||||||
<translation type="unfinished">
|
<translation type="unfinished">
|
||||||
<numerusform></numerusform>
|
<numerusform>总计 %Ln 次投票</numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
@ -1059,6 +1044,13 @@
|
||||||
<translation>通过机器用户 %1</translation>
|
<translation>通过机器用户 %1</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
|
@ -930,21 +930,6 @@
|
||||||
<translation>About Fernschreiber</translation>
|
<translation>About Fernschreiber</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
|
||||||
<name>MessageDocument</name>
|
|
||||||
<message>
|
|
||||||
<source>Download Document</source>
|
|
||||||
<translation type="unfinished">Download Document</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Open Document</source>
|
|
||||||
<translation type="unfinished">Open Document</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<source>Copy Document to Downloads</source>
|
|
||||||
<translation type="unfinished"></translation>
|
|
||||||
</message>
|
|
||||||
</context>
|
|
||||||
<context>
|
<context>
|
||||||
<name>MessageListViewItem</name>
|
<name>MessageListViewItem</name>
|
||||||
<message>
|
<message>
|
||||||
|
@ -1075,6 +1060,13 @@
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
|
<context>
|
||||||
|
<name>MessageVoiceNote</name>
|
||||||
|
<message>
|
||||||
|
<source>Voice Note</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewChatPage</name>
|
<name>NewChatPage</name>
|
||||||
<message>
|
<message>
|
||||||
|
|
Loading…
Reference in a new issue