Merge branch 'wunderfitz_master' into mbarashkov_master
BIN
db/emojis.db
|
@ -22,6 +22,7 @@ DEFINES += QT_STATICPLUGIN
|
|||
|
||||
SOURCES += src/harbour-fernschreiber.cpp \
|
||||
src/appsettings.cpp \
|
||||
src/boolfiltermodel.cpp \
|
||||
src/chatpermissionfiltermodel.cpp \
|
||||
src/chatlistmodel.cpp \
|
||||
src/chatmodel.cpp \
|
||||
|
@ -105,14 +106,21 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
|||
qml/components/messageContent/MessageGame.qml \
|
||||
qml/components/messageContent/MessageLocation.qml \
|
||||
qml/components/messageContent/MessagePhoto.qml \
|
||||
qml/components/messageContent/MessagePhotoAlbum.qml \
|
||||
qml/components/messageContent/MessagePoll.qml \
|
||||
qml/components/messageContent/MessageSticker.qml \
|
||||
qml/components/messageContent/MessageVenue.qml \
|
||||
qml/components/messageContent/MessageVideoAlbum.qml \
|
||||
qml/components/messageContent/MessageVideoNote.qml \
|
||||
qml/components/messageContent/MessageVideo.qml \
|
||||
qml/components/messageContent/MessageVoiceNote.qml \
|
||||
qml/components/messageContent/SponsoredMessage.qml \
|
||||
qml/components/messageContent/WebPagePreview.qml \
|
||||
qml/components/messageContent/mediaAlbumPage/FullscreenOverlay.qml \
|
||||
qml/components/messageContent/mediaAlbumPage/PhotoComponent.qml \
|
||||
qml/components/messageContent/mediaAlbumPage/VideoComponent.qml \
|
||||
qml/components/messageContent/mediaAlbumPage/ZoomArea.qml \
|
||||
qml/components/messageContent/mediaAlbumPage/ZoomImage.qml \
|
||||
qml/components/settingsPage/Accordion.qml \
|
||||
qml/components/settingsPage/AccordionItem.qml \
|
||||
qml/components/settingsPage/ResponsiveGrid.qml \
|
||||
|
@ -130,6 +138,7 @@ DISTFILES += qml/harbour-fernschreiber.qml \
|
|||
qml/pages/CoverPage.qml \
|
||||
qml/pages/DebugPage.qml \
|
||||
qml/pages/InitializationPage.qml \
|
||||
qml/pages/MediaAlbumPage.qml \
|
||||
qml/pages/NewChatPage.qml \
|
||||
qml/pages/OverviewPage.qml \
|
||||
qml/pages/AboutPage.qml \
|
||||
|
@ -212,6 +221,7 @@ INSTALLS += telegram 86.png 108.png 128.png 172.png 256.png \
|
|||
|
||||
HEADERS += \
|
||||
src/appsettings.h \
|
||||
src/boolfiltermodel.h \
|
||||
src/chatpermissionfiltermodel.h \
|
||||
src/chatlistmodel.h \
|
||||
src/chatmodel.h \
|
||||
|
|
|
@ -32,6 +32,7 @@ ListItem {
|
|||
property int messageIndex
|
||||
property int messageViewCount
|
||||
property var myMessage
|
||||
property var messageAlbumMessageIds
|
||||
property var reactions
|
||||
property bool canReplyToMessage
|
||||
readonly property bool isAnonymous: myMessage.sender_id["@type"] === "messageSenderChat"
|
||||
|
@ -68,7 +69,7 @@ ListItem {
|
|||
property var chatReactions
|
||||
property var messageReactions
|
||||
|
||||
highlighted: (down || isSelected || additionalOptionsOpened || wasNavigatedTo) && !menuOpen
|
||||
highlighted: (down || (isSelected && messageAlbumMessageIds.length === 0) || additionalOptionsOpened || wasNavigatedTo) && !menuOpen
|
||||
openMenuOnPressAndHold: !messageListItem.precalculatedValues.pageIsSelecting
|
||||
|
||||
signal replyToMessage()
|
||||
|
@ -268,20 +269,20 @@ ListItem {
|
|||
Connections {
|
||||
target: chatModel
|
||||
onMessagesReceived: {
|
||||
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
messageBackground.isUnread = messageIndex > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
}
|
||||
onMessagesIncrementalUpdate: {
|
||||
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
messageBackground.isUnread = messageIndex > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
}
|
||||
onNewMessageReceived: {
|
||||
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
messageBackground.isUnread = messageIndex > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
}
|
||||
onUnreadCountUpdated: {
|
||||
messageBackground.isUnread = index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
messageBackground.isUnread = messageIndex > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage";
|
||||
}
|
||||
onLastReadSentMessageUpdated: {
|
||||
Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (index <= lastReadSentIndex));
|
||||
messageDateText.text = getMessageStatusText(myMessage, index, lastReadSentIndex, messageDateText.useElapsed);
|
||||
Debug.log("[ChatModel] Messages in this chat were read, new last read: ", lastReadSentIndex, ", updating description for index ", index, ", status: ", (messageIndex <= lastReadSentIndex));
|
||||
messageDateText.text = getMessageStatusText(myMessage, messageIndex, lastReadSentIndex, messageDateText.useElapsed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,7 +303,7 @@ ListItem {
|
|||
pageStack.currentPage === chatPage) {
|
||||
Debug.log("Available reactions for this message: " + reactions);
|
||||
messageListItem.messageReactions = reactions;
|
||||
showItemCompletelyTimer.requestedIndex = index;
|
||||
showItemCompletelyTimer.requestedIndex = messageIndex;
|
||||
showItemCompletelyTimer.start();
|
||||
} else {
|
||||
messageListItem.messageReactions = null;
|
||||
|
@ -323,6 +324,13 @@ ListItem {
|
|||
interval: 200
|
||||
triggeredOnStart: false
|
||||
onTriggered: {
|
||||
if (requestedIndex === messageIndex) {
|
||||
chatView.highlightMoveDuration = -1;
|
||||
chatView.highlightResizeDuration = -1;
|
||||
chatView.scrollToIndex(requestedIndex);
|
||||
chatView.highlightMoveDuration = 0;
|
||||
chatView.highlightResizeDuration = 0;
|
||||
}
|
||||
Debug.log("Show item completely timer triggered, requested index: " + requestedIndex + ", current index: " + index)
|
||||
if (requestedIndex === index) {
|
||||
var p = chatView.contentItem.mapFromItem(reactionsColumn, 0, 0)
|
||||
|
@ -376,8 +384,10 @@ ListItem {
|
|||
onTriggered: {
|
||||
if (messageListItem.hasContentComponent) {
|
||||
var type = myMessage.content["@type"];
|
||||
var albumComponentPart = (myMessage.media_album_id !== "0" && ['messagePhoto', 'messageVideo'].indexOf(type) !== -1) ? 'Album' : '';
|
||||
console.log('delegateComponentLoadingTimer', myMessage.media_album_id, albumComponentPart)
|
||||
extraContentLoader.setSource(
|
||||
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + ".qml",
|
||||
"../components/messageContent/" + type.charAt(0).toUpperCase() + type.substring(1) + albumComponentPart + ".qml",
|
||||
{
|
||||
messageListItem: messageListItem
|
||||
})
|
||||
|
@ -441,7 +451,7 @@ ListItem {
|
|||
}
|
||||
height: messageTextColumn.height + precalculatedValues.paddingMediumDouble
|
||||
width: precalculatedValues.backgroundWidth
|
||||
property bool isUnread: index > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"
|
||||
property bool isUnread: messageIndex > chatModel.getLastReadMessageIndex() && myMessage['@type'] !== "sponsoredMessage"
|
||||
color: Theme.colorScheme === Theme.LightOnDark ? (isUnread ? Theme.secondaryHighlightColor : Theme.secondaryColor) : (isUnread ? Theme.backgroundGlowColor : Theme.overlayBackgroundColor)
|
||||
radius: parent.width / 50
|
||||
opacity: isUnread ? 0.5 : 0.2
|
||||
|
@ -463,7 +473,13 @@ ListItem {
|
|||
id: userText
|
||||
|
||||
width: parent.width
|
||||
text: messageListItem.isOwnMessage ? qsTr("You") : Emoji.emojify( myMessage['@type'] === "sponsoredMessage" ? tdLibWrapper.getChat(myMessage.sponsor_chat_id).title : ( messageListItem.isAnonymous ? page.chatInformation.title : Functions.getUserName(messageListItem.userInformation) ), font.pixelSize)
|
||||
text: messageListItem.isOwnMessage
|
||||
? qsTr("You")
|
||||
: Emoji.emojify( myMessage['@type'] === "sponsoredMessage"
|
||||
? tdLibWrapper.getChat(myMessage.sponsor_chat_id).title
|
||||
: ( messageListItem.isAnonymous
|
||||
? page.chatInformation.title
|
||||
: Functions.getUserName(messageListItem.userInformation) ), font.pixelSize)
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
font.weight: Font.ExtraBold
|
||||
color: messageListItem.textColor
|
||||
|
@ -646,7 +662,8 @@ ListItem {
|
|||
id: extraContentLoader
|
||||
width: parent.width * getContentWidthMultiplier()
|
||||
asynchronous: true
|
||||
height: item ? item.height : (messageListItem.hasContentComponent ? chatView.getContentComponentHeight(model.content_type, myMessage.content, width) : 0)
|
||||
readonly property var defaultExtraContentHeight: messageListItem.hasContentComponent ? chatView.getContentComponentHeight(model.content_type, myMessage.content, width, model.album_message_ids.length) : 0
|
||||
height: item ? item.height : defaultExtraContentHeight
|
||||
}
|
||||
|
||||
Binding {
|
||||
|
@ -671,7 +688,7 @@ ListItem {
|
|||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
messageDateText.text = getMessageStatusText(myMessage, index, chatView.lastReadSentIndex, messageDateText.useElapsed);
|
||||
messageDateText.text = getMessageStatusText(myMessage, messageIndex, chatView.lastReadSentIndex, messageDateText.useElapsed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -684,13 +701,13 @@ ListItem {
|
|||
font.pixelSize: Theme.fontSizeTiny
|
||||
color: messageListItem.isOwnMessage ? Theme.secondaryHighlightColor : Theme.secondaryColor
|
||||
horizontalAlignment: messageListItem.textAlign
|
||||
text: getMessageStatusText(myMessage, index, chatView.lastReadSentIndex, messageDateText.useElapsed)
|
||||
text: getMessageStatusText(myMessage, messageIndex, chatView.lastReadSentIndex, messageDateText.useElapsed)
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: !messageListItem.precalculatedValues.pageIsSelecting
|
||||
onClicked: {
|
||||
messageDateText.useElapsed = !messageDateText.useElapsed;
|
||||
messageDateText.text = getMessageStatusText(myMessage, index, chatView.lastReadSentIndex, messageDateText.useElapsed);
|
||||
messageDateText.text = getMessageStatusText(myMessage, messageIndex, chatView.lastReadSentIndex, messageDateText.useElapsed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ Loader {
|
|||
id: loader
|
||||
property var minithumbnail
|
||||
property bool highlighted
|
||||
property int fillMode: tdLibImage.fillMode
|
||||
anchors.fill: parent
|
||||
active: !!minithumbnail
|
||||
sourceComponent: Component {
|
||||
|
@ -32,7 +33,7 @@ Loader {
|
|||
id: minithumbnailImage
|
||||
anchors.fill: parent
|
||||
source: "data:image/jpg;base64,"+minithumbnail.data
|
||||
fillMode: tdLibImage.fillMode
|
||||
fillMode: loader.fillMode
|
||||
opacity: status === Image.Ready ? 1.0 : 0.0
|
||||
cache: false
|
||||
visible: opacity > 0
|
||||
|
@ -43,12 +44,12 @@ Loader {
|
|||
effect: PressEffect { source: minithumbnailImage }
|
||||
}
|
||||
}
|
||||
|
||||
FastBlur {
|
||||
anchors.fill: parent
|
||||
source: minithumbnailImage
|
||||
radius: Theme.paddingLarge
|
||||
}
|
||||
// this had a visible impact on performance
|
||||
// FastBlur {
|
||||
// anchors.fill: parent
|
||||
// source: minithumbnailImage
|
||||
// radius: Theme.paddingLarge
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ Item {
|
|||
|
||||
readonly property bool hasVisibleThumbnail: thumbnailImage.opacity !== 1.0
|
||||
&& !(videoThumbnailLoader.item && videoThumbnailLoader.item.opacity === 1.0)
|
||||
|
||||
property alias fillMode: thumbnailImage.fillMode
|
||||
layer {
|
||||
enabled: highlighted
|
||||
effect: PressEffect { source: tdlibThumbnail }
|
||||
|
@ -67,6 +67,7 @@ Item {
|
|||
|
||||
TDLibMinithumbnail {
|
||||
id: minithumbnailLoader
|
||||
fillMode: thumbnailImage.fillMode
|
||||
active: !!minithumbnail && thumbnailImage.opacity < 1.0
|
||||
}
|
||||
BackgroundImage {
|
||||
|
@ -103,6 +104,7 @@ Item {
|
|||
sourceSize.width: width
|
||||
sourceSize.height: height
|
||||
mimeType: tdlibThumbnail.videoMimeType
|
||||
fillMode: thumbnailImage.fillMode == Image.PreserveAspectFit ? Thumbnail.PreserveAspectFit : Thumbnail.PreserveAspectCrop
|
||||
visible: opacity > 0
|
||||
opacity: status === Thumbnail.Ready ? 1.0 : 0.0
|
||||
Behavior on opacity { FadeAnimation {} }
|
||||
|
|
|
@ -20,7 +20,6 @@ import QtQuick 2.6
|
|||
import Sailfish.Silica 1.0
|
||||
import QtMultimedia 5.6
|
||||
import "../"
|
||||
import "../../js/functions.js" as Functions
|
||||
import "../../js/debug.js" as Debug
|
||||
|
||||
Item {
|
||||
|
|
|
@ -22,28 +22,25 @@ import "../"
|
|||
|
||||
MessageContentBase {
|
||||
|
||||
function calculateBiggest() {
|
||||
var candidateBiggest = rawMessage.content.photo.sizes[rawMessage.content.photo.sizes.length - 1];
|
||||
if (candidateBiggest.width === 0 && rawMessage.content.photo.sizes.length > 1) {
|
||||
for (var i = (rawMessage.content.photo.sizes.length - 2); i >= 0; i--) {
|
||||
candidateBiggest = rawMessage.content.photo.sizes[i];
|
||||
if (candidateBiggest.width > 0) {
|
||||
height: Math.max(Theme.itemSizeExtraSmall, Math.min(Math.round(width * 0.66666666), width / getAspectRatio()))
|
||||
readonly property alias photoData: photo.photo;
|
||||
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("../../pages/MediaAlbumPage.qml"), {
|
||||
"messages" : [rawMessage],
|
||||
})
|
||||
}
|
||||
function getAspectRatio() {
|
||||
var candidate = photoData.sizes[photoData.sizes.length - 1];
|
||||
if (candidate.width === 0 && photoData.sizes.length > 1) {
|
||||
for (var i = (photoData.sizes.length - 2); i >= 0; i--) {
|
||||
candidate = photoData.sizes[i];
|
||||
if (candidate.width > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidateBiggest;
|
||||
}
|
||||
|
||||
height: Math.max(Theme.itemSizeExtraSmall, Math.min(defaultHeight, width / (biggest.width/biggest.height)))
|
||||
readonly property int defaultHeight: Math.round(width * 0.66666666)
|
||||
readonly property var biggest: calculateBiggest();
|
||||
|
||||
onClicked: {
|
||||
pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), {
|
||||
"photoData" : photo.photo,
|
||||
// "pictureFileInformation" : photo.fileInformation
|
||||
})
|
||||
return candidate.width / candidate.height;
|
||||
}
|
||||
TDLibPhoto {
|
||||
id: photo
|
||||
|
@ -51,7 +48,4 @@ MessageContentBase {
|
|||
photo: rawMessage.content.photo
|
||||
highlighted: parent.highlighted
|
||||
}
|
||||
BackgroundImage {
|
||||
visible: !rawMessage.content.photo.minithumbnail && photo.image.status !== Image.Ready
|
||||
}
|
||||
}
|
||||
|
|
207
qml/components/messageContent/MessagePhotoAlbum.qml
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
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 "../"
|
||||
|
||||
MessageContentBase {
|
||||
id: messageContent
|
||||
property string chatId
|
||||
readonly property int heightUnit: Math.round(width * 0.66666666)
|
||||
readonly property var albumId: rawMessage.media_album_id
|
||||
property var albumMessageIds: messageListItem ? messageListItem.messageAlbumMessageIds : []//overlayFlickable.messageAlbumMessageIds
|
||||
onAlbumMessageIdsChanged: albumMessages = getMessages() //chatModel.getMessagesForAlbum(messageContent.albumId)
|
||||
property var albumMessages: getMessages()//chatModel.getMessagesForAlbum(messageContent.albumId)
|
||||
property bool firstLarge: albumMessages.length % 2 !== 0;
|
||||
|
||||
clip: true
|
||||
height: defaultExtraContentHeight//(firstLarge ? heightUnit * 0.75 : 0 ) + heightUnit * 0.25 * albumMessageIds.length
|
||||
|
||||
|
||||
onClicked: {
|
||||
if(messageListItem.precalculatedValues.pageIsSelecting) {
|
||||
page.toggleMessageSelection(rawMessage);
|
||||
return;
|
||||
}
|
||||
openDetail(-1);
|
||||
}
|
||||
function getMessages() {
|
||||
var msgs = [rawMessage];
|
||||
if(messageContent.albumId === '0' || messageContent.albumMessageIds.length < 2) {
|
||||
return msgs;
|
||||
}
|
||||
// var othermsgIds =
|
||||
// getMessages from tdlib isn't faster
|
||||
// if(rawMessage && rawMessage.chat_id) {
|
||||
// var messages = [];
|
||||
// return albumMessageIds.map(function(msgId){
|
||||
// if(msgId === rawMessage.id) {
|
||||
// return rawMessage;
|
||||
// }
|
||||
// return tdLibWrapper.getMessage(rawMessage.chat_id, msgId);
|
||||
// })
|
||||
// }
|
||||
chatModel.getMessagesForAlbum(messageContent.albumId, 1).forEach(function(msg){
|
||||
msgs.push(msg);
|
||||
});
|
||||
//
|
||||
return msgs; //chatModel.getMessagesForAlbum(messageContent.albumId);
|
||||
}
|
||||
|
||||
function openDetail(index) {
|
||||
console.log('open detail', index || 0);
|
||||
|
||||
|
||||
pageStack.push(Qt.resolvedUrl("../../pages/MediaAlbumPage.qml"), {
|
||||
"messages" : albumMessages,
|
||||
"index": index || 0
|
||||
})
|
||||
}
|
||||
Connections { // TODO: needed?
|
||||
target: tdLibWrapper
|
||||
|
||||
onReceivedMessage: {
|
||||
if (albumMessageIds.indexOf(messageId)) {
|
||||
// albumMessages = getMessages()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: photoPreviewComponent
|
||||
MessagePhoto {
|
||||
// width: parent.width
|
||||
// height: parent.height
|
||||
messageListItem: messageContent.messageListItem
|
||||
overlayFlickable: messageContent.overlayFlickable
|
||||
rawMessage: albumMessages[modelIndex]
|
||||
highlighted: mediaBackgroundItem.highlighted
|
||||
}
|
||||
}
|
||||
Component {
|
||||
id: videoPreviewComponent
|
||||
Item {
|
||||
property bool highlighted: mediaBackgroundItem.highlighted
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
TDLibThumbnail {
|
||||
id: tdLibImage
|
||||
width: parent.width //don't use anchors here for easier custom scaling
|
||||
height: parent.height
|
||||
highlighted: parent.highlighted
|
||||
thumbnail: albumMessages[modelIndex].content.video.thumbnail
|
||||
minithumbnail: albumMessages[modelIndex].content.video.minithumbnail
|
||||
}
|
||||
Rectangle {
|
||||
anchors {
|
||||
fill: videoIcon
|
||||
leftMargin: -Theme.paddingSmall
|
||||
topMargin: -Theme.paddingSmall
|
||||
bottomMargin: -Theme.paddingSmall
|
||||
rightMargin: -Theme.paddingLarge
|
||||
|
||||
}
|
||||
|
||||
radius: Theme.paddingSmall
|
||||
color: Theme.rgba(Theme.overlayBackgroundColor, 0.4)
|
||||
|
||||
}
|
||||
|
||||
Icon {
|
||||
id: videoIcon
|
||||
source: "image://theme/icon-m-video"
|
||||
width: Theme.iconSizeSmall
|
||||
height: Theme.iconSizeSmall
|
||||
highlighted: parent.highlighted
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Theme.paddingSmall
|
||||
bottom: parent.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: contentGrid
|
||||
property int firstWidth: firstLarge ? contentGrid.width : normalWidth
|
||||
property int firstHeight: firstLarge ? heightUnit - contentGrid.spacing : normalHeight
|
||||
property int normalWidth: (contentGrid.width - contentGrid.spacing) / 2
|
||||
property int normalHeight: (heightUnit / 2) - contentGrid.spacing
|
||||
|
||||
anchors.fill: parent
|
||||
spacing: Theme.paddingMedium
|
||||
|
||||
Repeater {
|
||||
model: albumMessages
|
||||
delegate: BackgroundItem {
|
||||
id: mediaBackgroundItem
|
||||
property bool isLarge: firstLarge && model.index === 0
|
||||
width: model.index === 0 ? contentGrid.firstWidth : contentGrid.normalWidth
|
||||
height: model.index === 0 ? contentGrid.firstHeight : contentGrid.normalHeight
|
||||
|
||||
readonly property bool isSelected: messageListItem.precalculatedValues.pageIsSelecting && page.selectedMessages.some(function(existingMessage) {
|
||||
return existingMessage.id === albumMessages[index].id
|
||||
});
|
||||
highlighted: isSelected || down || messageContent.highlighted
|
||||
onClicked: {
|
||||
if(messageListItem.precalculatedValues.pageIsSelecting) {
|
||||
page.toggleMessageSelection(albumMessages[index]);
|
||||
return;
|
||||
}
|
||||
|
||||
openDetail(index);
|
||||
}
|
||||
onPressAndHold: {
|
||||
page.toggleMessageSelection(albumMessages[index]);
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
// asynchronous: true
|
||||
|
||||
readonly property int modelIndex: index
|
||||
sourceComponent: albumMessages[index].content["@type"] === 'messageVideo' ? videoPreviewComponent : photoPreviewComponent
|
||||
opacity: status === Loader.Ready
|
||||
Behavior on opacity {FadeAnimator{}}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO video:
|
||||
rawMessage.content.video.thumbnail
|
||||
TDLibPhoto {
|
||||
id: photo
|
||||
anchors.fill: parent
|
||||
photo: rawMessage.content.photo
|
||||
highlighted: parent.highlighted
|
||||
}
|
||||
*/
|
||||
Rectangle {
|
||||
visible: mediaBackgroundItem.isSelected
|
||||
anchors {
|
||||
fill: parent
|
||||
}
|
||||
color: 'transparent'
|
||||
border.color: Theme.highlightColor
|
||||
border.width: Theme.paddingSmall
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,7 +26,12 @@ import "../../js/debug.js" as Debug
|
|||
MessageContentBase {
|
||||
id: videoMessageComponent
|
||||
|
||||
property var videoData: ( rawMessage.content['@type'] === "messageVideo" ) ? rawMessage.content.video : ( ( rawMessage.content['@type'] === "messageAnimation" ) ? rawMessage.content.animation : rawMessage.content.video_note )
|
||||
property var videoData: ( rawMessage.content['@type'] === "messageVideo" )
|
||||
? rawMessage.content.video
|
||||
: (
|
||||
( rawMessage.content['@type'] === "messageAnimation" )
|
||||
? rawMessage.content.animation
|
||||
: rawMessage.content.video_note )
|
||||
property string videoUrl;
|
||||
property int previewFileId;
|
||||
property int videoFileId;
|
||||
|
|
19
qml/components/messageContent/MessageVideoAlbum.qml
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
MessagePhotoAlbum {}
|
|
@ -0,0 +1,279 @@
|
|||
/*
|
||||
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 QtGraphicalEffects 1.0
|
||||
import Sailfish.Silica 1.0
|
||||
import "../../../js/functions.js" as Functions
|
||||
|
||||
|
||||
Item {
|
||||
// id
|
||||
id: overlay
|
||||
// property declarations
|
||||
property int pageCount
|
||||
property int currentIndex
|
||||
property alias text: captionLabel.text
|
||||
property bool active: true
|
||||
property var message
|
||||
readonly property color gradientColor: '#bb000000'
|
||||
readonly property int gradientPadding: Theme.itemSizeMedium
|
||||
// signal declarations
|
||||
// JavaScript functions
|
||||
// object properties
|
||||
anchors.fill: parent
|
||||
opacity: active ? 1 : 0
|
||||
Behavior on opacity { FadeAnimator {} }
|
||||
// large property bindings
|
||||
// child objects
|
||||
// states
|
||||
// transitions
|
||||
|
||||
onActiveChanged: {
|
||||
console.log('overlay active', active)
|
||||
}
|
||||
|
||||
function forwardMessage() {
|
||||
var neededPermissions = Functions.getMessagesNeededForwardPermissions([message]);
|
||||
pageStack.push(Qt.resolvedUrl("../../../pages/ChatSelectionPage.qml"), {
|
||||
myUserId: tdLibWrapper.getUserInformation().id,
|
||||
headerDescription: qsTr("Forward %Ln messages", "dialog header", 1),
|
||||
payload: {fromChatId: message.chat_id, messageIds:[message.id], neededPermissions: neededPermissions},
|
||||
state: "forwardMessages"
|
||||
});
|
||||
}
|
||||
|
||||
// "header"
|
||||
|
||||
LinearGradient {
|
||||
id: topGradient
|
||||
property int startY: 0;
|
||||
// Behavior on startY { NumberAnimation {duration: 2000} }
|
||||
start: Qt.point(0, Math.min(height-gradientPadding*2, startY))
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
bottom: closeButton.bottom
|
||||
|
||||
bottomMargin: -gradientPadding
|
||||
}
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: gradientColor }
|
||||
GradientStop { position: 1.0; color: 'transparent' }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IconButton {
|
||||
id: closeButton
|
||||
icon.source: "image://theme/icon-m-cancel?" + (pressed
|
||||
? Theme.highlightColor
|
||||
: Theme.lightPrimaryColor)
|
||||
onClicked: pageStack.pop()
|
||||
anchors {
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
margins: Theme.horizontalPageMargin
|
||||
}
|
||||
}
|
||||
|
||||
SilicaFlickable {
|
||||
id: captionFlickable
|
||||
anchors {
|
||||
left: parent.left
|
||||
// leftMargin: Theme.horizontalPageMargin
|
||||
right: closeButton.left
|
||||
top: parent.top
|
||||
// topMargin: Theme.horizontalPageMargin
|
||||
}
|
||||
interactive: captionLabel.expanded && contentHeight > height
|
||||
clip: true
|
||||
height: Math.min(contentHeight, parent.height / 4)
|
||||
contentHeight: captionLabel.height + Theme.horizontalPageMargin
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
VerticalScrollDecorator {
|
||||
opacity: visible ? 1.0 : 0.0
|
||||
flickable: captionFlickable
|
||||
}
|
||||
|
||||
Label {
|
||||
id: captionLabel
|
||||
property bool expandable: expanded || height < contentHeight
|
||||
property bool expanded
|
||||
|
||||
height: text ?
|
||||
expanded
|
||||
? contentHeight
|
||||
: Theme.itemSizeMedium
|
||||
: 0;
|
||||
// maximumLineCount: expanded ? 0 : 3
|
||||
color: Theme.primaryColor
|
||||
// text: model.modelData.content.caption.text
|
||||
text: Emoji.emojify(Functions.enhanceMessageText(message.content.caption, false), Theme.fontSizeExtraSmall)
|
||||
onTextChanged: expanded = false
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
wrapMode: Text.WrapAnywhere
|
||||
bottomPadding: expanded ? Theme.paddingLarge : 0
|
||||
anchors {
|
||||
left: parent.left
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.paddingLarge
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
topMargin: Theme.horizontalPageMargin
|
||||
}
|
||||
|
||||
Behavior on height { NumberAnimation {duration: 300} }
|
||||
Behavior on text {
|
||||
SequentialAnimation {
|
||||
FadeAnimation {
|
||||
target: captionLabel
|
||||
to: 0.0
|
||||
duration: 300
|
||||
}
|
||||
PropertyAction {}
|
||||
FadeAnimation {
|
||||
target: captionLabel
|
||||
to: 1.0
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
OpacityRampEffect {
|
||||
sourceItem: captionLabel
|
||||
enabled: !captionLabel.expanded
|
||||
direction: OpacityRamp.TopToBottom
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: captionLabel
|
||||
enabled: captionLabel.expandable
|
||||
onClicked: {
|
||||
captionLabel.expanded = !captionLabel.expanded
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// "footer"
|
||||
LinearGradient {
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: buttons.top
|
||||
bottom: parent.bottom
|
||||
topMargin: -gradientPadding
|
||||
}
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop { position: 0.0; color: 'transparent' }
|
||||
GradientStop { position: 1.0; color: gradientColor }
|
||||
}
|
||||
}
|
||||
Loader {
|
||||
asynchronous: true
|
||||
active: overlay.pageCount > 1
|
||||
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
verticalCenter: buttons.bottom
|
||||
}
|
||||
sourceComponent: Component {
|
||||
|
||||
Row {
|
||||
id: pageIndicatorRow
|
||||
height: Theme.paddingSmall
|
||||
spacing: height
|
||||
Repeater {
|
||||
id: pageIndicator
|
||||
model: overlay.pageCount
|
||||
Rectangle {
|
||||
property bool active: model.index === overlay.currentIndex
|
||||
width: pageIndicatorRow.height
|
||||
height: pageIndicatorRow.height
|
||||
color: active ? Theme.lightPrimaryColor : Theme.rgba(Theme.lightSecondaryColor, Theme.opacityLow)
|
||||
Behavior on color { ColorAnimation {} }
|
||||
radius: Theme.paddingSmall
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
id: buttons
|
||||
height: Theme.itemSizeSmall
|
||||
width: childrenRect.width
|
||||
spacing: Theme.paddingLarge
|
||||
anchors {
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
bottom: parent.bottom
|
||||
bottomMargin: Theme.paddingLarge
|
||||
}
|
||||
|
||||
// IconButton {
|
||||
// icon.source: "image://theme/icon-m-cancel?" + (pressed
|
||||
// ? Theme.highlightColor
|
||||
// : Theme.lightPrimaryColor)
|
||||
// onClicked: pageStack.pop()
|
||||
|
||||
// }
|
||||
IconButton {
|
||||
icon.source: "image://theme/icon-m-downloads?" + (pressed
|
||||
? Theme.highlightColor
|
||||
: Theme.lightPrimaryColor)
|
||||
onClicked: pageStack.pop()
|
||||
}
|
||||
Item {
|
||||
width: Theme.itemSizeSmall
|
||||
height: Theme.itemSizeSmall
|
||||
}
|
||||
|
||||
IconButton {
|
||||
enabled: message.can_be_forwarded
|
||||
opacity: enabled ? 1.0 : 0.2
|
||||
icon.source: "image://theme/icon-m-share?" + (pressed
|
||||
? Theme.highlightColor
|
||||
: Theme.lightPrimaryColor)
|
||||
onClicked: forwardMessage()
|
||||
}
|
||||
}
|
||||
states: [
|
||||
State {
|
||||
name: 'hasCaption'
|
||||
when: captionLabel.height > 0
|
||||
PropertyChanges { target: topGradient;
|
||||
startY: captionFlickable.height
|
||||
}
|
||||
AnchorChanges {
|
||||
target: topGradient
|
||||
// anchors.top: captionLabel.verticalCenter
|
||||
anchors.bottom: captionFlickable.bottom
|
||||
}
|
||||
}
|
||||
]
|
||||
transitions:
|
||||
Transition {
|
||||
AnchorAnimation { duration: 200 }
|
||||
NumberAnimation { properties: "startY"; duration: 200 }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
|
||||
import QtQuick 2.6
|
||||
|
||||
ZoomImage {
|
||||
photoData: model.modelData.content.photo
|
||||
onClicked: {
|
||||
console.log('clicked', zoomed)
|
||||
if(zoomed) {
|
||||
zoomOut(true)
|
||||
page.overlayActive = true
|
||||
} else {
|
||||
page.overlayActive = !page.overlayActive
|
||||
}
|
||||
}
|
||||
|
||||
}
|
181
qml/components/messageContent/mediaAlbumPage/VideoComponent.qml
Normal file
|
@ -0,0 +1,181 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
import QtMultimedia 5.6
|
||||
import QtGraphicalEffects 1.0
|
||||
import "../../"
|
||||
|
||||
Video {
|
||||
id: video
|
||||
property var videoData: model.modelData.content.video
|
||||
readonly property bool isPlaying: playbackState === MediaPlayer.PlayingState
|
||||
readonly property bool isCurrent: index === page.index
|
||||
property bool shouldPlay
|
||||
autoLoad: true
|
||||
source: file.isDownloadingCompleted ? file.path : ''
|
||||
onIsCurrentChanged: {
|
||||
if(!isCurrent) {
|
||||
pause()
|
||||
}
|
||||
}
|
||||
onStatusChanged: {
|
||||
if(status === MediaPlayer.EndOfMedia) {
|
||||
page.overlayActive = true
|
||||
}
|
||||
}
|
||||
TDLibThumbnail {
|
||||
id: tdLibImage
|
||||
|
||||
property bool active: !file.isDownloadingCompleted || (!video.isPlaying && (video.position === 0 || video.status === MediaPlayer.EndOfMedia))
|
||||
opacity: active ? 1 : 0
|
||||
visible: active || opacity > 0
|
||||
|
||||
width: parent.width //don't use anchors here for easier custom scaling
|
||||
height: parent.height
|
||||
// highlighted: parent.highlighted
|
||||
thumbnail: videoData.thumbnail
|
||||
minithumbnail: videoData.minithumbnail
|
||||
fillMode: Image.PreserveAspectFit
|
||||
|
||||
|
||||
}
|
||||
|
||||
TDLibFile {
|
||||
id: file
|
||||
autoLoad: false
|
||||
tdlib: tdLibWrapper
|
||||
fileInformation: videoData.video
|
||||
property real progress: isDownloadingCompleted ? 1.0 : (downloadedSize / size)
|
||||
onDownloadingCompletedChanged: {
|
||||
if(isDownloadingCompleted) {
|
||||
video.source = file.path
|
||||
if(video.shouldPlay) {
|
||||
video.play()
|
||||
delayedOverlayHide.start()
|
||||
video.shouldPlay = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: 'dl: '+file.downloadedSize
|
||||
+ ' \ns: '+file.size
|
||||
+ ' \nes: '+file.expectedSize
|
||||
+ ' \nd:'+file.isDownloadingActive
|
||||
+ ' \nc:'+file.isDownloadingCompleted
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: page.overlayActive = !page.overlayActive
|
||||
}
|
||||
|
||||
RadialGradient { // white videos = invisible button. I can't tell since which SFOS version the opaque button is available, so:
|
||||
id: buttonBg
|
||||
anchors.centerIn: parent
|
||||
width: Theme.itemSizeLarge; height: Theme.itemSizeLarge
|
||||
property color baseColor: Theme.rgba(palette.overlayBackgroundColor, 0.2)
|
||||
|
||||
enabled: videoUI.active || !file.isDownloadingCompleted
|
||||
opacity: enabled ? 1 : 0
|
||||
Behavior on opacity { FadeAnimator {} }
|
||||
gradient: Gradient {
|
||||
|
||||
GradientStop { position: 0.0; color: buttonBg.baseColor }
|
||||
GradientStop { position: 0.3; color: buttonBg.baseColor }
|
||||
GradientStop { position: 0.5; color: 'transparent' }
|
||||
}
|
||||
|
||||
IconButton {
|
||||
anchors.fill: parent
|
||||
icon.source: "image://theme/icon-l-"+(video.isPlaying || video.shouldPlay ? 'pause' : 'play')+"?" + (pressed
|
||||
? Theme.highlightColor
|
||||
: Theme.lightPrimaryColor)
|
||||
onClicked: {
|
||||
if (!file.isDownloadingCompleted) {
|
||||
video.shouldPlay = !video.shouldPlay;
|
||||
if(video.shouldPlay) {
|
||||
file.load()
|
||||
} else {
|
||||
file.cancel()
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (video.isPlaying) {
|
||||
video.pause()
|
||||
} else {
|
||||
video.play()
|
||||
delayedOverlayHide.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProgressCircle {
|
||||
property bool active: file.isDownloadingActive
|
||||
opacity: active ? 1 : 0
|
||||
Behavior on opacity { FadeAnimator {} }
|
||||
anchors.centerIn: parent
|
||||
value: file.progress
|
||||
}
|
||||
Item {
|
||||
id: videoUI
|
||||
property bool active: overlay.active// && file.isDownloadingCompleted
|
||||
anchors.fill: parent
|
||||
opacity: active ? 1 : 0
|
||||
Behavior on opacity { FadeAnimator {} }
|
||||
|
||||
Slider {
|
||||
id: slider
|
||||
value: video.position
|
||||
minimumValue: 0
|
||||
maximumValue: video.duration || 0.1
|
||||
enabled: parent.active && video.seekable
|
||||
width: parent.width
|
||||
handleVisible: false
|
||||
animateValue: true
|
||||
stepSize: 500
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
bottomMargin: Theme.itemSizeMedium
|
||||
}
|
||||
valueText: value > 0 || down ? Format.formatDuration((value)/1000, Formatter.Duration) : ''
|
||||
leftMargin: Theme.horizontalPageMargin
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
onDownChanged: {
|
||||
if(!down) {
|
||||
video.seek(value)
|
||||
value = Qt.binding(function() { return video.position })
|
||||
}
|
||||
}
|
||||
Label {
|
||||
anchors {
|
||||
right: parent.right
|
||||
rightMargin: Theme.horizontalPageMargin
|
||||
bottom: parent.bottom
|
||||
topMargin: Theme.paddingSmall
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeExtraSmall
|
||||
text: file.isDownloadingCompleted
|
||||
? Format.formatDuration((parent.maximumValue - parent.value)/1000, Formatter.Duration)
|
||||
: (video.videoData.duration
|
||||
? Format.formatDuration(video.videoData.duration, Formatter.Duration) + ', '
|
||||
: '') + Format.formatFileSize(file.size || file.expectedSize)
|
||||
color: Theme.secondaryColor
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: delayedOverlayHide
|
||||
interval: 500
|
||||
onTriggered: {
|
||||
if(video.isPlaying) {
|
||||
page.overlayActive = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
148
qml/components/messageContent/mediaAlbumPage/ZoomArea.qml
Normal file
|
@ -0,0 +1,148 @@
|
|||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
|
||||
SilicaFlickable {
|
||||
// id
|
||||
id: flickable
|
||||
// property declarations
|
||||
property real zoom
|
||||
property bool zoomed
|
||||
// override if needed
|
||||
property bool zoomEnabled: true
|
||||
property real minimumZoom: fitZoom
|
||||
property real maximumZoom: 4 //Math.max(fitZoom, 1) * 3
|
||||
|
||||
default property alias zoomContentItem: zoomContentItem.data
|
||||
property alias implicitContentWidth: zoomContentItem.implicitWidth
|
||||
property alias implicitContentHeight: zoomContentItem.implicitHeight
|
||||
// factor for "PreserveAspectFit"
|
||||
readonly property real fitZoom: implicitContentWidth > 0 && implicitContentHeight > 0
|
||||
? Math.min(maximumZoom, width / implicitContentWidth, height / implicitContentHeight)
|
||||
: 1.0
|
||||
readonly property int minimumBoundaryAxis: (implicitContentWidth / implicitContentHeight) > (width / height) ? Qt.Horizontal : Qt.Vertical
|
||||
|
||||
// JavaScript functions
|
||||
function zoomOut(animated) {
|
||||
if (zoomed) {
|
||||
if(animated) { zoomOutAnimation.start() }
|
||||
else {
|
||||
zoom = fitZoom
|
||||
zoomed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// object properties
|
||||
contentWidth: Math.max(width, zoomContentItem.width)
|
||||
contentHeight: Math.max(height, zoomContentItem.height)
|
||||
enabled: !zoomOutAnimation.running && implicitContentWidth > 0 && implicitContentHeight > 0
|
||||
flickableDirection: Flickable.HorizontalAndVerticalFlick
|
||||
interactive: zoomed
|
||||
// According to Jolla, otherwise pinching would sometimes not work:
|
||||
pressDelay: 0
|
||||
Binding { // Update zoom on orientation changes and set as default
|
||||
target: flickable
|
||||
when: !zoomed
|
||||
property: "zoom"
|
||||
value: minimumZoom
|
||||
}
|
||||
// child objects
|
||||
|
||||
PinchArea {
|
||||
id: pinchArea
|
||||
parent: flickable.contentItem
|
||||
width: flickable.contentWidth
|
||||
height: flickable.contentHeight
|
||||
enabled: zoomEnabled && minimumZoom !== maximumZoom && flickable.enabled
|
||||
onPinchUpdated: {
|
||||
scrollDecoratorTimer.restart()
|
||||
var f = flickable;
|
||||
var requestedZoomFactor = 1.0 + pinch.scale - pinch.previousScale;
|
||||
var previousWidth = f.contentWidth
|
||||
var previousHeight = f.contentHeight
|
||||
var targetWidth
|
||||
var targetHeight
|
||||
var targetZoom = requestedZoomFactor * f.zoom;
|
||||
if (targetZoom < f.minimumZoom) {
|
||||
f.zoom = f.minimumZoom;
|
||||
f.zoomed = false;
|
||||
f.contentX = 0;
|
||||
f.contentY = 0;
|
||||
return
|
||||
} else if(targetZoom >= f.maximumZoom) {
|
||||
f.zoom = f.maximumZoom;
|
||||
targetHeight = f.implicitContentHeight * f.zoom
|
||||
targetWidth = f.implicitContentWidth * f.zoom
|
||||
}
|
||||
else if(targetZoom < f.maximumZoom) {
|
||||
if (f.minimumBoundaryAxis == Qt.Horizontal) {
|
||||
targetWidth = f.contentWidth * requestedZoomFactor
|
||||
f.zoom = targetWidth / f.implicitContentWidth
|
||||
targetHeight = f.implicitContentHeight * f.zoom
|
||||
} else {
|
||||
targetHeight = f.contentHeight * requestedZoomFactor
|
||||
f.zoom = targetHeight / f.implicitContentHeight
|
||||
targetWidth = f.implicitContentWidth * f.zoom
|
||||
}
|
||||
}
|
||||
// calculate center difference
|
||||
f.contentX += pinch.previousCenter.x - pinch.center.x
|
||||
f.contentY += pinch.previousCenter.y - pinch.center.y
|
||||
// move to new (zoomed) center. this jumps a tiny bit, but is bearable:
|
||||
if (targetWidth > f.width)
|
||||
f.contentX -= (previousWidth - targetWidth)/(previousWidth/pinch.previousCenter.x)
|
||||
if (targetHeight > f.height)
|
||||
f.contentY -= (previousHeight - targetHeight)/(previousHeight/pinch.previousCenter.y)
|
||||
|
||||
f.zoomed = true
|
||||
}
|
||||
onPinchFinished: {
|
||||
returnToBounds()
|
||||
}
|
||||
Item {
|
||||
id: zoomContentItem
|
||||
anchors.centerIn: parent
|
||||
implicitWidth: flickable.width
|
||||
implicitHeight: flickable.height
|
||||
width: Math.ceil(implicitWidth * zoom)
|
||||
height: Math.ceil(implicitHeight * zoom)
|
||||
}
|
||||
}
|
||||
// enable zoom to minimumZoom on click
|
||||
ParallelAnimation {
|
||||
id: zoomOutAnimation
|
||||
NumberAnimation {
|
||||
target: flickable
|
||||
properties: "contentX, contentY"
|
||||
to: 0
|
||||
}
|
||||
NumberAnimation {
|
||||
target: flickable
|
||||
property: "zoom"
|
||||
to: fitZoom
|
||||
}
|
||||
onRunningChanged: {
|
||||
if(!running) {
|
||||
zoomed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// show scroll decorators when scrolling OR zooming
|
||||
Timer {
|
||||
id: scrollDecoratorTimer
|
||||
readonly property bool moving: flickable.moving
|
||||
readonly property bool showing: moving || running
|
||||
onMovingChanged: restart()
|
||||
interval: 300
|
||||
}
|
||||
|
||||
VerticalScrollDecorator {
|
||||
flickable: flickable
|
||||
opacity: scrollDecoratorTimer.showing ? 1.0 : 0.0
|
||||
}
|
||||
HorizontalScrollDecorator {
|
||||
flickable: flickable
|
||||
opacity: scrollDecoratorTimer.showing ? 1.0 : 0.0
|
||||
}
|
||||
}
|
127
qml/components/messageContent/mediaAlbumPage/ZoomImage.qml
Normal file
|
@ -0,0 +1,127 @@
|
|||
import QtQuick 2.0
|
||||
import Sailfish.Silica 1.0
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
import "../../"
|
||||
|
||||
ZoomArea {
|
||||
// id
|
||||
id: zoomArea
|
||||
property var photoData //albumMessages[index].content.photo
|
||||
property bool active: true
|
||||
property alias image: image
|
||||
|
||||
signal clicked
|
||||
|
||||
maximumZoom: Math.max(Screen.width, Screen.height) / 200
|
||||
// maximumZoom: Math.max(fitZoom, 1) * 3
|
||||
implicitContentWidth: image.implicitWidth
|
||||
implicitContentHeight: image.implicitHeight
|
||||
zoomEnabled: image.status == Image.Ready
|
||||
|
||||
onActiveChanged: {
|
||||
if (!active) {
|
||||
zoomOut()
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// var photoData = albumMessages[index].content.photo;
|
||||
if (photoData) {
|
||||
|
||||
var biggestIndex = -1
|
||||
for (var i = 0; i < photoData.sizes.length; i++) {
|
||||
if (biggestIndex === -1 || photoData.sizes[i].width > photoData.sizes[biggestIndex].width) {
|
||||
biggestIndex = i;
|
||||
}
|
||||
}
|
||||
if (biggestIndex > -1) {
|
||||
// imageDelegate.imageWidth = photoData.sizes[biggestIndex].width;
|
||||
// imageDelegate.imageHeight = photoData.sizes[biggestIndex].height;
|
||||
image.sourceSize.width = photoData.sizes[biggestIndex].width
|
||||
image.sourceSize.height = photoData.sizes[biggestIndex].height
|
||||
image.fileInformation = photoData.sizes[biggestIndex].photo
|
||||
|
||||
console.log('loading photo', JSON.stringify(image.fileInformation))
|
||||
}
|
||||
}
|
||||
}
|
||||
TDLibImage {
|
||||
id: image
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
source: file.isDownloadingCompleted ? file.path : ""
|
||||
// enabled: true //!!file.fileId
|
||||
// anchors.fill: parent
|
||||
anchors.centerIn: parent
|
||||
|
||||
fillMode: Image.PreserveAspectFit
|
||||
asynchronous: true
|
||||
smooth: !(movingVertically || movingHorizontally)
|
||||
|
||||
// sourceSize.width: Screen.height
|
||||
// visible: opacity > 0
|
||||
// opacity: status === Image.Ready ? 1 : 0
|
||||
|
||||
Behavior on opacity { FadeAnimator{} }
|
||||
}
|
||||
// Label {
|
||||
// anchors.fill: parent
|
||||
// text: 'ok?' + image.enabled +' fileid:' +!!(image.file.fileId)
|
||||
// + '\n - dl?' + image.file.isDownloadingActive
|
||||
// + '\n completed?' + image.file.isDownloadingCompleted + ' path:'+ image.file.path
|
||||
// + '\n ' + image.source
|
||||
// wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
// }
|
||||
// Rectangle {
|
||||
// color: 'green'
|
||||
// anchors.fill: image
|
||||
// opacity: 0.3
|
||||
|
||||
// }
|
||||
|
||||
// Image {
|
||||
// id: image
|
||||
// anchors.fill: parent
|
||||
// smooth: !(movingVertically || movingHorizontally)
|
||||
// sourceSize.width: Screen.height
|
||||
// fillMode: Image.PreserveAspectFit
|
||||
// asynchronous: true
|
||||
// cache: false
|
||||
|
||||
// onSourceChanged: {
|
||||
// zoomOut()
|
||||
// }
|
||||
|
||||
// opacity: status == Image.Ready ? 1 : 0
|
||||
// Behavior on opacity { FadeAnimator{} }
|
||||
// }
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
}
|
||||
MouseArea {
|
||||
anchors.centerIn: parent
|
||||
width: zoomArea.contentWidth
|
||||
height: zoomArea.contentHeight
|
||||
onClicked: zoomArea.clicked()
|
||||
}
|
||||
|
||||
|
||||
BusyIndicator {
|
||||
running: image.file.isDownloadingActive && !delayBusyIndicator.running
|
||||
size: BusyIndicatorSize.Large
|
||||
anchors.centerIn: parent
|
||||
parent: zoomArea
|
||||
Timer {
|
||||
id: delayBusyIndicator
|
||||
running: image.file.isDownloadingActive
|
||||
interval: 1000
|
||||
}
|
||||
}
|
||||
// Rectangle {
|
||||
// color: 'green'
|
||||
// anchors.fill: parent
|
||||
// parent: zoomArea
|
||||
// }
|
||||
}
|
1
qml/js/emoji/1f426-200d-2b1b.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#FFAC33" d="M8.916 12.88c-.111 1.652 1.768 3.126-.712 2.959-2.48-.167-7.836-2.533-7.768-3.53s3.708-2.757 6.188-2.59c2.48.166 2.404 1.508 2.292 3.161m20.122 16.049a.966.966 0 0 0-.564.095c-2.325.232-3.225-1.885-3.225-1.885-.439-.336-.981-2.009-1.589-1.215l.187 1.402c.187 1.402 2.57 3.224 2.57 3.224l-1.215 1.589a1 1 0 1 0 1.589 1.215l.673-.88-.039.249a1 1 0 1 0 1.976.314l.47-2.963a1.003 1.003 0 0 0-.833-1.145zm-6.278.623a.984.984 0 0 0-.572.018c-2.335-.082-2.944-2.3-2.944-2.3-.39-.392-.703-2.123-1.412-1.417l-.003 1.414c-.003 1.414 2.115 3.539 2.115 3.539l-1.417 1.412a.999.999 0 1 0 1.411 1.417l.785-.782-.073.242a1 1 0 0 0 1.916.576l.862-2.873a.996.996 0 0 0-.668-1.246z"/><path fill="#31373D" d="M35.009 6.729c-.383-.17-.758-.057-1.05.244-.054.056-4.225 6.306-14.532 4.944-.34-.045 3.139 11.968 3.199 11.962.124-.014 3.07-.368 6.14-2.553 2.818-2.005 6.284-5.991 6.797-13.598.028-.418-.171-.828-.554-.999z"/><path fill="#31373D" d="M34.477 21.108c-.204-.336-.59-.56-.979-.471-1.293.295-3.197.543-4.53.453-6.357-.428-9.361-4.129-9.392-4.16-.275-.282.466 11.552.816 11.576 9.194.62 13.862-6.027 14.057-6.31.222-.326.233-.751.028-1.088"/><path fill="#31373D" d="M24.586 19.016c-.371 5.51 1.316 9.861-4.194 9.489-5.51-.371-10.145-4.92-9.774-10.431s14.34-4.568 13.968.942"/><path fill="#31373D" d="M23.257 12.412c-.353 5.235-3.922 9.257-9.156 8.904-5.235-.353-9.193-4.882-8.84-10.117.353-5.235 4.832-8.444 10.067-8.091 4.001.269 8.24 4.683 7.929 9.304z"/><circle cx="10.67" cy="8.989" r="2"/><path d="M18.179 16.645s7.63 5.648 12.387-4.459c.396-.842 1.685.793.099 4.162s-8.175 6.44-12.04 1.536c-.815-1.035-.446-1.239-.446-1.239"/><path fill="#31373D" d="M15.327 3.107s6.246.254 7.798-.477.136 2.932-3.262 3.789-4.536-3.312-4.536-3.312z"/><path fill="#31373D" d="M17.428 5.788s4.501.136 6.054-.594.136 2.932-3.262 3.789c-3.399.857-2.792-3.195-2.792-3.195z"/></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
qml/js/emoji/1f6dc.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><defs><clipPath id="a"><path fill="none" d="M0 0h36v36H0z"/></clipPath></defs><g clip-path="url(#a)"><path fill="#2b87c7" d="M36 32c0 4-4 4-4 4H4c-4 0-4-4-4-4V4c0-4 4-4 4-4h28s4 0 4 4z"/></g><path fill="#fff" d="m5.1 13.01 1.46 1.65c.15.16.39.19.57.07 3.01-1.98 6.77-3.17 10.83-3.17s7.88 1.2 10.9 3.21c.18.12.42.09.57-.07l1.47-1.64c.17-.2.14-.5-.07-.65-3.56-2.45-8.02-3.91-12.87-3.91S8.72 9.94 5.17 12.36c-.22.15-.25.45-.08.65Z"/><path fill="#fff" d="m9.43 17.9 1.45 1.64c.15.16.39.2.58.08 1.8-1.2 4.06-1.92 6.51-1.92s4.74.73 6.54 1.95c.18.12.42.1.57-.07l1.47-1.64c.18-.2.14-.5-.08-.65-2.34-1.66-5.29-2.65-8.5-2.65s-6.12.98-8.45 2.61a.43.43 0 0 0-.08.65Zm4.22 4.77 1.46 1.64c.14.16.39.19.57.07.63-.41 1.42-.65 2.28-.65s1.67.25 2.3.66c.18.12.42.09.57-.07l1.46-1.64a.44.44 0 0 0-.06-.64c-1.17-.86-2.65-1.37-4.27-1.37s-3.08.51-4.24 1.35c-.21.15-.24.45-.07.64Z"/><circle cx="17.91" cy="27.64" r="1.86" fill="#fff"/></svg>
|
After Width: | Height: | Size: 977 B |
1
qml/js/emoji/1fa75.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#88C9F9" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"/></svg>
|
After Width: | Height: | Size: 368 B |
1
qml/js/emoji/1fa76.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#99AAB5" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"/></svg>
|
After Width: | Height: | Size: 368 B |
1
qml/js/emoji/1fa77.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#F4ABBA" d="M35.885 11.833c0-5.45-4.418-9.868-9.867-9.868-3.308 0-6.227 1.633-8.018 4.129-1.791-2.496-4.71-4.129-8.017-4.129-5.45 0-9.868 4.417-9.868 9.868 0 .772.098 1.52.266 2.241C1.751 22.587 11.216 31.568 18 34.034c6.783-2.466 16.249-11.447 17.617-19.959.17-.721.268-1.469.268-2.242z"/></svg>
|
After Width: | Height: | Size: 368 B |
1
qml/js/emoji/1fa87.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><defs><clipPath id="a" clipPathUnits="userSpaceOnUse"><path d="M-35.367 13.848h36v-36h-36Z"/></clipPath><clipPath id="b" clipPathUnits="userSpaceOnUse"><path d="M-24.343 34.246h36v-36h-36Z"/></clipPath><clipPath id="c" clipPathUnits="userSpaceOnUse"><path d="M-36 10.269H0v-36h-36Z"/></clipPath><clipPath id="d" clipPathUnits="userSpaceOnUse"><path d="M-34.38 15.907h36v-36h-36Z"/></clipPath><clipPath id="e" clipPathUnits="userSpaceOnUse"><path d="M-31.406 19.303h36v-36h-36Z"/></clipPath><clipPath id="f" clipPathUnits="userSpaceOnUse"><path d="M-28.11 21.53h36v-36h-36Z"/></clipPath><clipPath id="g" clipPathUnits="userSpaceOnUse"><path d="M-12.71 6.294h36v-36h-36Z"/></clipPath><clipPath id="h" clipPathUnits="userSpaceOnUse"><path d="M-16.316 29.198h36v-36h-36Z"/></clipPath><clipPath id="i" clipPathUnits="userSpaceOnUse"><path d="M-11.042 3.065h36v-36h-36Z"/></clipPath><clipPath id="j" clipPathUnits="userSpaceOnUse"><path d="M-13.173 8.53h36v-36h-36Z"/></clipPath><clipPath id="k" clipPathUnits="userSpaceOnUse"><path d="M-12.869 13.034h36v-36h-36Z"/></clipPath><clipPath id="l" clipPathUnits="userSpaceOnUse"><path d="M-11.599 16.805h36v-36h-36Z"/></clipPath></defs><path fill="#fcd646" d="M0 0a10.926 10.926 0 0 0-.987-2.058l-.001-.001c-1.379-1.093-5.157-1.888-7.379-1.093-2.222.794-4 3-4.227 5.246.098.732.276 1.477.54 2.217a10.562 10.562 0 0 0 1.783 3.168c1.904-.631 3.847.105 5.904-.631 2.058-.736 3-2 5-3.269A10.622 10.622 0 0 0 0 0" clip-path="url(#a)" transform="matrix(1 0 0 -1 35.367 13.848)"/><path fill="#d4a086" d="M0 0c-.55-1.538-2.122-2.092-3.626-1.554-1.502.537-2.368 1.963-1.818 3.501.348.972.898 1.811 1.275 2.334 1.491 2.067 2.65 4.354 3.508 6.755l.036.101c.045.125.086.251.123.378 1.159.731 1.691.898 2.159.731.468-.168 0 0 .592-1.715a6.6 6.6 0 0 1-.145-.37l-.036-.101C1.209 7.659.654 5.156.496 2.612.456 1.969.394 1.102 0 0" clip-path="url(#b)" transform="matrix(1 0 0 -1 24.343 34.246)"/><path fill="#d24248" d="M0 0c-1.778-.237-3.836-.021-5.895.715-2.056.736-3.785 1.875-5.009 3.185 1.922 2.334 4.664 3.444 7.073 2.583C-1.422 5.621-.007 3.024 0 0" clip-path="url(#c)" transform="matrix(1 0 0 -1 36 10.269)"/><path fill="#82ae63" d="M0 0a10.36 10.36 0 0 0-.431-.64 12.303 12.303 0 0 0-2.543-2.757c-1.406-.696-3.867-.247-5.406.304-1.538.55-2 1-3.082 2.732a12.312 12.312 0 0 0-.217 3.745c.015.255.039.511.073.769C-10.373 2.709-8.535 1.445-6.314.65-4.091-.145-1.869-.333 0 0" clip-path="url(#d)" transform="matrix(1 0 0 -1 34.38 15.907)"/><path fill="#d24248" d="M0 0a10.735 10.735 0 0 0-1.724-1.11 6.727 6.727 0 0 1-1.573-1.117c-2.109 0-1.41-.72-2.109-.47-.697.25-1.013.987-1.946 1.92a6.698 6.698 0 0 1-.507 1.861 10.78 10.78 0 0 0-.629 1.952c1.096-.904 2.45-1.679 3.989-2.229C-2.961.256-1.422-.003 0 0" clip-path="url(#e)" transform="matrix(1 0 0 -1 31.406 19.303)"/><path fill="#ba6e54" d="M0 0a6.63 6.63 0 0 1-1.517-2.184 14.314 14.314 0 0 0-2.751.984c.252.865.32 1.766.213 2.651.614-.334 1.274-.63 1.971-.88C-1.385.321-.688.132 0 0" clip-path="url(#f)" transform="matrix(1 0 0 -1 28.11 21.53)"/><path fill="#fcd646" d="M0 0c.239-.75.391-1.499.463-2.235v-.001C.029-3.942-2.492-6.865-4.741-7.581c-2.248-.716-5-.041-6.542 1.608a10.935 10.935 0 0 0-.916 2.091 10.586 10.586 0 0 0-.504 3.599c1.897.653 2.996 2.416 5.077 3.079 2.083.663 3.599.229 5.958.433A10.592 10.592 0 0 0 0 0" clip-path="url(#g)" transform="matrix(1 0 0 -1 12.71 6.294)"/><path fill="#d4a086" d="M0 0c.496-1.557-.419-2.95-1.94-3.434s-3.074.124-3.569 1.681C-5.822-.77-5.893.23-5.911.875c-.068 2.548-.534 5.069-1.307 7.499l-.033.102c-.04.127-.084.252-.132.375.478 1.284.8 1.739 1.273 1.89.474.151 0 0 1.511-1.003.033-.129.069-.256.109-.383l.033-.103c.773-2.429 1.85-4.756 3.267-6.875C-.832 1.841-.355 1.115 0 0" clip-path="url(#h)" transform="matrix(1 0 0 -1 16.316 29.198)"/><path fill="#d24248" d="M0 0c-1.27-1.267-3.037-2.343-5.12-3.006-2.082-.663-4.147-.806-5.915-.506.113 3.022 1.62 5.567 4.057 6.343C-4.54 3.607-1.84 2.4 0 0" clip-path="url(#i)" transform="matrix(1 0 0 -1 11.042 3.065)"/><path fill="#ec9435" d="M0 0c.024-.258.04-.516.046-.77.059-1.085 0-2.378-.35-3.734C-1-5.911-3.229-7.046-4.786-7.542c-1.557-.495-2.197-.417-4.109.304a12.287 12.287 0 0 0-2.443 2.845c-.143.212-.279.43-.409.656 1.857-.4 4.084-.291 6.332.425C-3.165-2.596-1.284-1.398 0 0" clip-path="url(#j)" transform="matrix(1 0 0 -1 13.173 8.53)"/><path fill="#d24248" d="M0 0a10.72 10.72 0 0 0-.698-1.928A6.694 6.694 0 0 1-1.27-3.77c-1.677-1.279-.686-1.428-1.393-1.653-.705-.224-1.404.171-2.712.347a6.693 6.693 0 0 1-1.531 1.172c-.624.35-1.184.747-1.684 1.17 1.42-.054 2.966.151 4.523.647C-2.51-1.592-1.129-.865 0 0" clip-path="url(#k)" transform="matrix(1 0 0 -1 12.869 13.035)"/><path fill="#ba6e54" d="M0 0a6.594 6.594 0 0 1 .119-2.656 13.854 13.854 0 0 0-1.371-.514 14.2 14.2 0 0 0-1.414-.373 6.617 6.617 0 0 1-1.438 2.237c.691.107 1.395.272 2.101.497C-1.296-.584-.627-.312 0 0" clip-path="url(#l)" transform="matrix(1 0 0 -1 11.599 16.805)"/></svg>
|
After Width: | Height: | Size: 4.9 KiB |
1
qml/js/emoji/1fa88.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#FFCC4D" d="m29.346.937 4.95 4.95L6.012 34.17l-4.95-4.95z"/><circle cx="4.5" cy="30.75" r="3.5" fill="#C1694F"/><circle cx="3.5" cy="31.75" r="3.5" fill="#FFCC4D"/><circle cx="3.5" cy="31.75" r="2" fill="#292F33"/><circle cx="31.75" cy="3.5" r="3.5" fill="#FFCC4D"/><circle cx="25.75" cy="9.5" r="3.5" fill="#C1694F"/><circle cx="24.75" cy="10.5" r="3.5" fill="#FFCC4D"/><circle cx="7.95" cy="26.15" r="1.25" fill="#C1694F"/><circle cx="8.2" cy="26.4" r="1" fill="#292F33"/><circle cx="10.95" cy="23.15" r="1.25" fill="#C1694F"/><circle cx="11.2" cy="23.4" r="1" fill="#292F33"/><circle cx="13.95" cy="20.15" r="1.25" fill="#C1694F"/><circle cx="14.2" cy="20.4" r="1" fill="#292F33"/><circle cx="16.95" cy="17.15" r="1.25" fill="#C1694F"/><circle cx="17.2" cy="17.4" r="1" fill="#292F33"/><circle cx="19.95" cy="14.15" r="1.25" fill="#C1694F"/><circle cx="20.2" cy="14.4" r="1" fill="#292F33"/><circle cx="22.95" cy="11.15" r="1.25" fill="#C1694F"/><circle cx="23.2" cy="11.4" r="1" fill="#292F33"/><circle cx="29.95" cy="4.15" r="1.25" fill="#C1694F"/><circle cx="30.2" cy="4.4" r="1" fill="#292F33"/></svg>
|
After Width: | Height: | Size: 1.2 KiB |
1
qml/js/emoji/1faad.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#e80040" d="m18 28 17.08-10.2c.42-.25.52-.84.19-1.2C30.98 11.94 24.84 9.01 18 9.01S5.02 11.93.73 16.59c-.33.36-.24.95.19 1.2L18 27.99Z"/><path fill="#a80018" d="m18 25.79.03-.05.47-1.71V9.01c-.17 0-.33-.01-.5-.01s-.33 0-.5.01v15.02l.47 1.71zm-.81 1.26-.06.1.23.15-.03-.1zm2.99-2.79 8.25-12.81c-.3-.15-.6-.3-.91-.43l-7.68 11.93-.58 2.12.92-.81Z"/><path fill="#a80018" d="m18.01 25.81.02-.07-.03.05zm.76 1.01 14.15-12.45c-.26-.22-.53-.43-.8-.63L20.17 24.25l-.92.81-.48 1.75Zm-1.54.03-.12.11.08.09.14.15zm1.21.62.06.23.04-.02.1-.38-.13.08z"/><path fill="#a80018" d="m19.25 25.07.58-2.12 3.63-13.3c-.32-.08-.65-.15-.98-.21L18.5 24.03l-.47 1.71-.02.07.55.86.2.18v-.03zm-3.08-2.12L8.49 11.02c-.31.14-.61.28-.91.43l8.25 12.81.92.81-.58-2.12Z"/><path fill="#a80018" d="m17.97 25.74.14.53.46.4-.56-.86-.01-.02zm.54 1.64.13-.08.23-.15-.06-.1z"/><path fill="#a80018" d="m18.57 26.67-.46-.4.33 1.2.07-.09.3-.33.08-.09-.12-.11zm-1.82-1.6-.92-.81L3.87 13.75c-.27.2-.54.41-.8.63l14.15 12.45-.48-1.75Z"/><path fill="#a80018" d="m18.44 27.47-.33-1.19-.14-.53-.47-1.71-3.98-14.59c-.33.06-.66.13-.98.21l3.63 13.3.58 2.12.48 1.75v.03l.1.35.03.09.1.38.54.32.5-.3-.06-.23Z"/><path fill="#de9a7e" d="m18 28 6.59-3.94a8.628 8.628 0 0 0-13.18 0z"/><path fill="#fff" d="M12.19 23.95c1.53-1.56 3.62-2.45 5.81-2.45s4.28.88 5.81 2.45L18 27.42l-5.81-3.47Z"/><path fill="#de9a7e" d="m19.52 27.09 5.07-3.03a8.628 8.628 0 0 0-13.18 0l5.07 3.03-2.08 1.49a.38.38 0 0 0-.08.55c.93 1.15 2.24 1.87 3.69 1.87s2.75-.72 3.69-1.87c.14-.17.09-.42-.08-.55l-2.08-1.49Zm3.47-3.23-3.4 2.03c-.1-.15-.22-.28-.35-.4l1.83-2.84c.69.3 1.34.71 1.92 1.21Zm-4.61-1.84c.68.03 1.34.16 1.97.36l-1.76 2.73c-.07-.02-.14-.04-.22-.06v-3.03Zm-.75 0v3.03c-.07.02-.15.03-.22.06l-1.76-2.73c.63-.21 1.3-.33 1.97-.36Zm-4.61 1.84c.58-.5 1.23-.9 1.92-1.21l1.83 2.84c-.13.12-.25.25-.35.4l-3.4-2.03Z"/><circle cx="18" cy="27" r="1" fill="#a80018"/></svg>
|
After Width: | Height: | Size: 1.9 KiB |
1
qml/js/emoji/1faae.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#31373d" d="M35.9 12.22c-.13-.13-.37-.13-.51 0-.24.23-11.05 10.8-11.92 11.52-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 11.29-11.67 11.52-11.92.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.49 11.24-12.35 11.95-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 11.72-12.11 11.95-12.35.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.77 11.52-12.64 12.24-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 12.01-12.39 12.24-12.64.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.92 11.67-12.78 12.38-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 12.15-12.54 12.38-12.78.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.92 11.67-12.78 12.38-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 12.15-12.54 12.38-12.78.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.77 11.52-12.64 12.24-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 12.01-12.39 12.24-12.64.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.49 11.24-12.35 11.95-.19.16-.45.16-.61 0s-.16-.42 0-.61c.72-.86 11.72-12.11 11.95-12.35.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.05 10.8-11.92 11.52-.19.16-.45.16-.61 0s-.16-.42 0-.61C12.94 11.63 23.51.82 23.74.57c.13-.14.13-.38 0-.51s-.37-.13-.51 0c-.24.23-11.31 10.98-12.15 11.73-4.62 4.17-2.53 6.17-2.3 8.58.37 3.97-2.44 6.21-4.38 6.41-2.52.26-4.45 2.06-4.45 4.59 0 1.27.51 2.42 1.35 3.25.83.83 1.98 1.35 3.25 1.35 2.54 0 4.33-1.93 4.59-4.45.2-1.94 2.44-4.75 6.41-4.38 2.41.22 4.41 2.32 8.58-2.3.75-.83 11.5-11.9 11.73-12.15.13-.14.13-.38 0-.51zM4.56 32.69c-.35 0-.66-.14-.88-.37a1.24 1.24 0 0 1-.37-.88c0-.69.56-1.25 1.25-1.25.35 0 .66.14.88.37s.37.54.37.88c0 .69-.56 1.25-1.25 1.25"/><path fill="none" stroke="#7a8891" stroke-linecap="round" stroke-miterlimit="10" d="M3.88 28.12c-1.46.3-2.58 1.55-2.67 3.08m9.28-17.1c-1.61 2.13-1.3 2.91-.65 5.23.55 1.97.06 3.81-.65 5.23"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
qml/js/emoji/1faaf.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 36 36"><path fill="#9266cc" d="M36 32c0 2.2-1.8 4-4 4H4c-2.2 0-4-1.8-4-4V4c0-2.2 1.8-4 4-4h28c2.2 0 4 1.8 4 4z"/><path fill="#fff" d="M23.5 6.9s4 2.3 3.6 7.5c-.4 5.1-8.3 10.1-8.3 10.1v-1.6l2.1-1.5c-.1-.5-.2-.9-.3-1.4 2.8-1.1 4.9-3.8 4.9-7s-2-5.9-4.8-7c.1-.7.2-1 .2-1L18 2l-2.9 3s.1.3.2.9c-2.8 1.1-4.8 3.8-4.8 7s2 5.9 4.8 7c-.1.5-.2.9-.3 1.4l2.1 1.5v1.6s-7.9-4.9-8.3-10.1c-.4-5.1 3.6-7.5 3.6-7.5s-6.1 1-6.5 7.5c-.4 6.3 5.8 11 5.8 11s1.1.9 1.2 1.9l2.7-2 1 .7-3.4 2.6c-.3.2-.5.6-.5 1 0 .8.6 1.4 1.4 1.4s1.4-.6 1.4-1.4c0-.3-.1-.6-.3-.8l1.9-1.3v3c-.6.3-1 .9-1 1.6 0 1 .8 1.9 1.9 1.9s1.9-.8 1.9-1.9c0-.7-.4-1.3-1-1.6v-3l1.9 1.3c-.2.2-.3.5-.3.8 0 .8.6 1.4 1.4 1.4s1.4-.6 1.4-1.4c0-.4-.2-.8-.5-1l-3.4-2.6 1-.7 2.7 2c.1-1 1.2-1.9 1.2-1.9s6.2-4.7 5.8-11c-.5-6.4-6.6-7.4-6.6-7.4m.5 6c0 2.5-1.5 4.6-3.6 5.5-.7-4.6-.3-8.6.1-11 2 1 3.5 3.1 3.5 5.5m-12 0c0-2.4 1.5-4.5 3.6-5.5.4 2.4.7 6.4.1 11-2.2-.9-3.7-3-3.7-5.5"/></svg>
|
After Width: | Height: | Size: 982 B |
1
qml/js/emoji/1fabb.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#69b546" d="M31.71 28.26c-1.78-.49-4.33.36-6.77 1.57 1.9-2.33 3.91-4.76 6.1-6.08 1.82-1.09 2.07-2.09 1.86-2.82-.24-.86-1.17-1.32-2.05-1.18-4.49.7-9.71 8.85-11.86 12.52v-5.53h-2v5.53c-2.14-3.68-7.36-11.82-11.86-12.52-.88-.14-1.81.32-2.05 1.18-.2.73.05 1.73 1.86 2.82 2.19 1.32 4.2 3.75 6.1 6.08-2.44-1.21-5-2.07-6.77-1.57-.68.19-1.2.83-1.09 1.53.09.59.6 1.24 2.28 1.43 4.21.49 9.43 4.74 12.53 4.52 3.1.23 8.32-4.03 12.53-4.52 1.68-.19 2.18-.84 2.28-1.43.11-.7-.41-1.34-1.09-1.53Z"/><path fill="#894fc4" d="M23.68 6.26c1.93-4-1.93-3-1.93-3C21-.24 18 2.32 18 2.32s-3-2.56-3.75.94c0 0-3.86-1-1.93 3 0 0-3.07 1-2.07 4l.82 3.68S8.75 21.85 13 19.56c0 0-1.75 3.7 2.25 2.7 0 0-.46 3.38 1.02 5.32a2.145 2.145 0 0 0 3.45 0c1.48-1.94 1.02-5.32 1.02-5.32 4 1 2.25-2.7 2.25-2.7 4.25 2.3 1.93-5.62 1.93-5.62l.82-3.68c1-3-2.07-4-2.07-4Z"/><path fill="#ae6dee" d="M19.17 2.98c0 1.93-.52 4.28-1.17 4.28s-1.17-2.34-1.17-4.28S17.35.26 18 .26s1.17.79 1.17 2.72"/><path fill="#ae6dee" d="M19.17 10.54c0-1.93-.52-4.28-1.17-4.28s-1.17 2.34-1.17 4.28.52 2.72 1.17 2.72 1.17-.79 1.17-2.72"/><path fill="#ae6dee" d="M21.62 5.05c-1.17 1.17-2.9 2.27-3.29 1.88s.71-2.12 1.88-3.29 1.96-1.33 2.35-.94.23 1.18-.94 2.35"/><path fill="#ae6dee" d="M21.62 8.47c-1.17-1.17-2.9-2.27-3.29-1.88s.71 2.12 1.88 3.29 1.96 1.33 2.35.94.23-1.18-.94-2.35m-7.24-3.42c1.17 1.17 2.9 2.27 3.29 1.88s-.71-2.12-1.88-3.29-1.96-1.33-2.35-.94-.23 1.18.94 2.35Z"/><path fill="#ae6dee" d="M14.38 8.47c1.17-1.17 2.9-2.27 3.29-1.88s-.71 2.12-1.88 3.29-1.96 1.33-2.35.94-.23-1.18.94-2.35Z"/><circle cx="18" cy="6.76" r=".8" fill="#cd95ff"/><path fill="#ae6dee" d="M19.17 16.98c0 1.93-.52 4.28-1.17 4.28s-1.17-2.34-1.17-4.28.52-2.72 1.17-2.72 1.17.79 1.17 2.72"/><path fill="#ae6dee" d="M19.17 24.54c0-1.93-.52-4.28-1.17-4.28s-1.17 2.34-1.17 4.28.52 2.72 1.17 2.72 1.17-.79 1.17-2.72"/><path fill="#ae6dee" d="M21.62 19.05c-1.17 1.17-2.9 2.27-3.29 1.88s.71-2.12 1.88-3.29 1.96-1.33 2.35-.94.23 1.18-.94 2.35"/><path fill="#ae6dee" d="M21.62 22.47c-1.17-1.17-2.9-2.27-3.29-1.88s.71 2.12 1.88 3.29 1.96 1.33 2.35.94.23-1.18-.94-2.35m-7.24-3.42c1.17 1.17 2.9 2.27 3.29 1.88s-.71-2.12-1.88-3.29-1.96-1.33-2.35-.94-.23 1.18.94 2.35Z"/><path fill="#ae6dee" d="M14.38 22.47c1.17-1.17 2.9-2.27 3.29-1.88s-.71 2.12-1.88 3.29-1.96 1.33-2.35.94-.23-1.18.94-2.35Z"/><circle cx="18" cy="20.76" r=".8" fill="#cd95ff"/><path fill="#ae6dee" d="M22.17 13.3c1.19.62 2.8 1.04 3.01.65s-1.07-1.47-2.26-2.08-1.84-.55-2.05-.15.11.97 1.31 1.59Z"/><path fill="#ae6dee" d="M22.17 14.21c1.19-.62 2.8-1.04 3.01-.65s-1.07 1.47-2.26 2.08-1.84.55-2.05.15.11-.97 1.31-1.59Z"/><path fill="#ae6dee" d="M27.83 13.3c-1.19.62-2.8 1.04-3.01.65s1.07-1.47 2.26-2.08 1.84-.55 2.05-.15-.11.97-1.31 1.59Z"/><path fill="#ae6dee" d="M27.83 14.21c-1.19-.62-2.8-1.04-3.01-.65s1.07 1.47 2.26 2.08 1.84.55 2.05.15-.11-.97-1.31-1.59Z"/><path fill="#ae6dee" d="M26.84 11.03c-.58 1.47-1.67 3.1-2.16 2.91s-.19-2.13.39-3.61 1.21-1.92 1.7-1.73.65.95.08 2.42Z"/><path fill="#ae6dee" d="M26.84 16.49c-.58-1.47-1.67-3.1-2.16-2.91s-.19 2.13.39 3.61 1.21 1.92 1.7 1.73.65-.95.08-2.42Z"/><ellipse cx="25.35" cy="13.76" fill="#cd95ff" rx=".4" ry=".8"/><path fill="#ae6dee" d="M13.83 13.3c-1.19.62-2.8 1.04-3.01.65s1.07-1.47 2.26-2.08 1.84-.55 2.05-.15-.11.97-1.31 1.59Z"/><path fill="#ae6dee" d="M13.83 14.21c-1.19-.62-2.8-1.04-3.01-.65s1.07 1.47 2.26 2.08 1.84.55 2.05.15-.11-.97-1.31-1.59Z"/><path fill="#ae6dee" d="M8.17 13.3c1.19.62 2.8 1.04 3.01.65s-1.07-1.47-2.26-2.08-1.84-.55-2.05-.15.11.97 1.31 1.59Z"/><path fill="#ae6dee" d="M8.17 14.21c1.19-.62 2.8-1.04 3.01-.65s-1.07 1.47-2.26 2.08-1.84.55-2.05.15.11-.97 1.31-1.59Z"/><path fill="#ae6dee" d="M9.16 11.03c.58 1.47 1.67 3.1 2.16 2.91s.19-2.13-.39-3.61-1.21-1.92-1.7-1.73-.65.95-.08 2.42Z"/><path fill="#ae6dee" d="M9.16 16.49c.58-1.47 1.67-3.1 2.16-2.91s.19 2.13-.39 3.61-1.21 1.92-1.7 1.73-.65-.95-.08-2.42Z"/><ellipse cx="10.65" cy="13.76" fill="#cd95ff" rx=".4" ry=".8"/></svg>
|
After Width: | Height: | Size: 3.9 KiB |
1
qml/js/emoji/1fabc.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#44abf3" d="M13.5 35c-.26 0-.53-.07-.77-.21-.71-.43-.94-1.35-.51-2.06l1.59-2.65c.45-.75.3-1.71-.34-2.29a4.804 4.804 0 0 1-.84-6.19l2.2-3.44c.45-.7 1.37-.9 2.07-.45.7.45.9 1.37.45 2.07l-2.2 3.44c-.48.75-.35 1.73.32 2.33 1.72 1.54 2.1 4.09.92 6.06l-1.59 2.65a1.5 1.5 0 0 1-1.29.73Zm-6-2c-.26 0-.53-.07-.77-.21-.71-.43-.94-1.35-.51-2.06l1.59-2.65c.45-.75.3-1.71-.34-2.29a4.804 4.804 0 0 1-.84-6.19l2.2-3.44c.45-.7 1.37-.9 2.07-.45.7.45.9 1.38.45 2.07l-2.2 3.44c-.48.75-.35 1.73.32 2.33 1.72 1.54 2.1 4.09.92 6.06L8.8 32.26a1.5 1.5 0 0 1-1.29.73Zm14.44 2a1.5 1.5 0 0 1-1.29-.73l-1.59-2.65c-1.19-1.98-.8-4.53.92-6.06.67-.6.8-1.58.32-2.33l-2.2-3.44a1.499 1.499 0 0 1 2.52-1.62l2.2 3.44c1.28 2 .93 4.6-.84 6.19-.65.58-.79 1.54-.34 2.29l1.59 2.65c.43.71.2 1.63-.51 2.06-.24.15-.51.21-.77.21Zm6-2a1.5 1.5 0 0 1-1.29-.73l-1.59-2.65c-1.19-1.98-.8-4.53.92-6.06.67-.6.8-1.58.32-2.33l-2.2-3.44a1.499 1.499 0 0 1 2.52-1.62l2.2 3.44c1.28 2 .93 4.6-.84 6.19-.65.58-.79 1.54-.34 2.29l1.59 2.65c.43.71.2 1.63-.51 2.06-.24.15-.51.21-.77.21Z"/><path fill="#44abf3" d="M18 22.27c-1.17 0-2.3-.29-3.36-.85-.71-.38-1.28-.82-1.68-1.31-.61-.75-1.5-1.17-2.42-1.17-.11 0-.21 0-.32.02-.33.04-.72.06-1.15.06-3.21 0-5.26-1.36-6.1-4.04C1.6 10.6 4.73 7.51 7.59 5.7c1.13-.72 5.7-2.68 10.42-2.68S27.3 4.99 28.43 5.7c2.87 1.82 6 4.9 4.62 9.28-.84 2.68-2.89 4.04-6.1 4.04-.43 0-.82-.03-1.15-.06-.11-.01-.21-.02-.32-.02-.92 0-1.81.43-2.42 1.17-.41.5-.97.94-1.68 1.32-1.06.57-2.2.85-3.36.85Z"/><path fill="#2b87c7" d="M18 4c4.44 0 8.86 1.88 9.89 2.53 2.57 1.63 5.39 4.36 4.21 8.14-.26.83-1.05 3.34-5.15 3.34-.34 0-.7-.02-1.05-.06-.14-.02-.28-.02-.43-.02-1.23 0-2.39.56-3.19 1.54-.32.39-.79.75-1.38 1.07-.92.49-1.89.74-2.9.74s-1.98-.25-2.9-.74c-.59-.32-1.06-.67-1.38-1.07-.8-.98-1.97-1.54-3.19-1.54-.14 0-.28 0-.43.02-.35.04-.7.06-1.05.06-4.1 0-4.89-2.51-5.15-3.34-1.18-3.78 1.63-6.51 4.21-8.14C9.13 5.88 13.55 4 18 4m0-2C13 2 8.24 4.08 7.04 4.84 4.44 6.48.36 10.02 2 15.26 3.25 19.25 6.67 20 9.06 20c.47 0 .89-.03 1.26-.07.07 0 .14-.01.22-.01.61 0 1.21.27 1.65.81.54.66 1.25 1.17 1.99 1.56 1.22.65 2.53.97 3.83.97s2.62-.32 3.83-.97c.73-.39 1.44-.9 1.99-1.56.44-.54 1.04-.81 1.65-.81.07 0 .14 0 .22.01.36.04.79.07 1.26.07 2.39 0 5.81-.75 7.06-4.74 1.64-5.25-2.44-8.78-5.04-10.43-1.19-.76-5.96-2.84-10.96-2.84Z"/><path fill="#fff" d="M8.12 12.67c-.57 1.67-.98 2.83-1.99 2.49s-1.36-1.97-.79-3.64 1.84-2.75 2.84-2.41.5 1.89-.06 3.57Z"/><path fill="#2b87c7" d="M23.12 6.98c-.61-.48-1.76-1.72-5.12-1.72s-4.51 1.25-5.12 1.72c-.78.61-.86 1.53-.19 2.06.67.53 1.85.46 2.62-.15.11-.08.24-.21.39-.35-.11.37-.18.7-.18.9 0 .86 1.11 1.56 2.48 1.56s2.48-.7 2.48-1.56c0-.21-.06-.53-.18-.9.15.15.28.27.39.35.78.61 1.95.68 2.62.15.67-.53.59-1.45-.19-2.06"/><ellipse cx="10" cy="7.5" fill="#fff" rx="1.5" ry="1" transform="rotate(-42.63 9.993 7.502)"/><path fill="#fff" d="M30.24 15.68c-.77 1.03-1.9 1.49-2.52 1.03s-.5-1.68.28-2.71 1.9-1.49 2.52-1.03.5 1.67-.27 2.71Z"/></svg>
|
After Width: | Height: | Size: 2.9 KiB |
1
qml/js/emoji/1fabd.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#CAD4DB" d="M33.86 3.06c.03-.8-.92-1.26-1.53-.75-6.2 5.13-13.64 8.46-18.68 9.1-4.06.52-5.34 2.11-6.26 5.18-.29.97-.69 1.9-1.22 2.75l-3.19 5.12-.117.252c-.428.923-.873 1.881-.873 2.898 0 2.47 3.16 3.67 4.89 4.14.39.11.74-.15.82-.51l-.044-.063.078.022-1.515-4.012.563.241.026.072c.038.107.075.213.122.32v.01c.2.48.44.96.71 1.44 2.03 3.27 5.56 3.85 7.66 3.88.73.01 1.14-.83.69-1.41l-.68-.88-.036.073-2.524-2.495.763.108.067.054-.04-.05.052.007c4.516 2.8 8.073 3.373 10.298 3.333.97-.01 1.34-1.27.54-1.82l-.17-.12a23.27 23.27 0 0 1-.243-.065l-3.11-1.666.62-.19c6.053 1.66 9.432-.137 10.953-1.439.49-.42.27-1.21-.37-1.3l-1.17-.18-.137.024-5.49-.743.189-.099.208.018-.19-.027.007-.004c3.684-.136 5.926-1.552 7.103-2.609.35-.31.26-.82-.06-1.06l-.18.045-6.015-.093.102-.106.113-.006c3.99-1.03 5.97-2.54 6.95-3.79.65-.82-.07-2.01-1.11-1.87l-.73.1.008.02-4.599 1.012.32-.353c.117-.035.234-.072.351-.109l-.28.04c4.44-1.27 6.06-3.74 6.66-5.38a.795.795 0 0 0-.81-1.07l-.029.021.023-.024-4.512 2.012c-.562.18-.857.3-1.16.392a4.781 4.781 0 0 1-.234.066l.015-.025c5.22-2.61 6.277-6.232 6.377-8.442z"/><path fill="#97A8B3" d="M24.8 21.53c3.37 0 6.05-.49 7.77-.92a.69.69 0 0 0-.41-.13h-5.68l.11-.03c-3.13.17-7.02-.05-11.37-1.25.31-.41.61-.86.9-1.33.58.03 1.19.04 1.82.04 4.11 0 9.13-.64 13.78-2.96l-.02-.05-3.92.56c-3.9 1.24-7.86 1.5-11.09 1.4.27-.52.52-1.08.75-1.66h.24c2.98 0 8.64-.88 15.67-6.16a.76.76 0 0 0-.25.06l-5.29 2.27c-4.39 2.28-7.9 2.77-10 2.8.06-.18.13-.35.19-.53a.5.5 0 0 0-.33-.62c-.04-.01-.08 0-.12-.01-.22 0-.43.12-.5.35-2.41 8.04-8.32 10.1-12 10.58-.19.03-.39.05-.57.07-.28.03-.48.27-.45.54.02.26.24.45.5.45h.05c.2-.02.41-.04.64-.07.19 2.07 1.04 4.19 2.52 6.32.02-.1.03-.21 0-.32L6.69 27.1c-.27-.79-.43-1.57-.49-2.34.78-.16 1.66-.39 2.59-.75 1.92 4.58 6.46 6.91 6.52 6.94l.04-.08-1.74-2.26c-1.33-1.07-2.96-2.73-3.9-4.98.36-.16.72-.35 1.08-.55 4.17 4.34 12.35 6.58 13.49 6.88l-2.8-1.93c-2.93-1.03-7.2-2.87-9.82-5.49.4-.26.79-.55 1.19-.87 4.01 1.96 9.68 3.72 14.83 3.72 1.13 0 2.24-.09 3.3-.28l-5.25-.8c-4.31-.35-8.75-1.81-12.05-3.37.3-.28.59-.58.87-.91 3.83 1.11 7.32 1.5 10.27 1.5z"/></svg>
|
After Width: | Height: | Size: 2.1 KiB |
1
qml/js/emoji/1fabf.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#ffa800" d="M20.43 33.26a.736.736 0 0 0-.32-.31s-.36-.08-.42-.17c-.67-1.12 1.29-5.33 1.29-5.33h-2l-1.21 4.9-1.11-.03a.773.773 0 0 0-.79.76c-.01.43.33.78.76.79l.86.02-.17.09c-.38.19-.53.66-.34 1.04s.66.53 1.04.34l2.07-1.06c.38-.19.53-.66.34-1.04Z"/><path fill="#ffa800" d="M25.12 31.7a.743.743 0 0 0-.44-.06s-.33.15-.44.11c-1.21-.49-2.15-5.05-2.15-5.05l-1.6 1.19 1.96 4.65-.91.64c-.35.25-.43.73-.19 1.08.25.35.73.43 1.08.19l.7-.5-.09.18c-.19.38-.03.85.35 1.04s.85.03 1.04-.35l1.03-2.08a.78.78 0 0 0-.35-1.04Z"/><path fill="#dfe7ed" d="M9.23 11.39c-1.03 1.43-1.74 3.08-1.77 4.84-.08 5.16 4.11 7.45 6.01 8.71 1.33.88 2.85 2.35 4.13 3.72 1.47 1.56 3.98 1.41 5.24-.32 1.5-2.07 3.54-4.48 5.57-5.62 2.41-1.37 3.27-3.3 3.57-4.59.16-.66-.4-1.26-1.08-1.23-3.54.17-5.43-1.96-5.43-1.96-5.02-5.02-10.04-2.38-11.55-1.38-.25.17-.6.04-.68-.25-.38-1.35-.12-3.35.77-5.42.57-1.32.76-2.79.47-4.19-.12-.61-.34-1.22-.69-1.76-1.31-2-5.31-2-6.32 1.17-1.21 3.77 1.02 2.83 1.02 2.83s3.12 2.16.75 5.45Z"/><path fill="#fc8a00" d="M4.47 4.8c.91-.22 2.04-.55 2.94-.97.31-.14.66-.02.85.27.23.35.63.73 1.34.81.42.04.52.63.17.86-1.16.74-3.06 1.42-5.44.24-.53-.26-.43-1.07.14-1.21Z"/><circle cx="10.98" cy="3.44" r="1" fill="#282f33"/><path fill="#cad4db" d="M21.43 23.72c-1.02 0-1.99-.18-2.91-.55-4.06-1.62-5.47-6.22-5.52-6.41-.08-.26.07-.54.34-.62.27-.08.54.07.62.34.01.04 1.33 4.34 4.94 5.77 2.38.95 5.25.46 8.54-1.43a.35.35 0 0 0 .17-.3c0-.06-.02-.22-.19-.3l-2.65-1.33a.488.488 0 0 1-.22-.67c.12-.25.42-.34.67-.22l2.65 1.33c.44.22.73.67.74 1.16.01.49-.24.95-.67 1.2-2.35 1.36-4.53 2.04-6.51 2.04Z"/></svg>
|
After Width: | Height: | Size: 1.6 KiB |
1
qml/js/emoji/1face.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#6c1a0d" d="M.75 8.93s.24-3.25 3.01-5.01c.67-.43 1.46.33 1.08 1.03-.82 1.47-1.64 3.51-1.12 5.2.1.32.54.34.65.03.25-.73.67-1.83 1.28-2.75.37-.56 1.26-.23 1.18.44-.12.96-.21 2.12-.11 2.99.07.64.84.93 1.31.49.3-.28.62-.66.83-1.13.23-.5.96-.44 1.13.08.12.37.19.84.15 1.41-.05.85.36 1.66 1.08 2.1l2.05 1.26-1.15.94-1.92-1.28c-.63-.42-1.42-.52-2.12-.23-2.31.93-7.59 2.22-7.31-5.56Zm34.5 0s-.24-3.25-3.01-5.01c-.67-.43-1.46.33-1.08 1.03.82 1.47 1.64 3.51 1.12 5.2-.1.32-.54.34-.65.03-.25-.73-.67-1.83-1.28-2.75-.37-.56-1.26-.23-1.18.44.12.96.21 2.12.11 2.99-.07.64-.84.93-1.31.49-.3-.28-.62-.66-.83-1.13-.23-.5-.96-.44-1.13.08-.12.37-.19.84-.15 1.41.05.85-.36 1.66-1.08 2.1l-2.05 1.26 1.15.94 1.92-1.28c.63-.42 1.42-.52 2.12-.23 2.31.93 7.59 2.22 7.31-5.56Zm-15.73.53-.7.63-.49-.87c-.16-.29-.49-.29-.65 0l-.49.87-.7-.63c-.22-.2-.52-.07-.61.27L15.01 13h6l-.87-3.27c-.09-.34-.39-.47-.61-.27Z"/><path fill="#282f33" d="M13.15 15.06s-2.37-3.81-.72-4.76 3.73 3.06 3.73 3.06z"/><path fill="#c86349" d="m12.97 15.73-.25-.41c-.18-.28-1.71-2.82-1.31-4.42.11-.46.38-.81.76-1.04.39-.22.83-.27 1.27-.14 1.58.46 3 3.1 3.15 3.4l.22.43-3.85 2.18Zm-.01-5.08c-.1 0-.2.03-.29.08-.15.09-.25.22-.3.42-.21.84.49 2.38.95 3.23l2.15-1.21c-.58-.98-1.54-2.26-2.31-2.48a.761.761 0 0 0-.21-.03Z"/><path fill="#282f33" d="M22.85 15.06s2.37-3.81.72-4.76-3.73 3.06-3.73 3.06z"/><path fill="#c86349" d="m23.03 15.73-3.85-2.18.22-.43c.16-.3 1.57-2.94 3.15-3.4.45-.13.89-.08 1.28.14s.65.58.76 1.04c.4 1.6-1.14 4.14-1.31 4.42l-.25.41Zm-2.5-2.56 2.15 1.21c.47-.86 1.16-2.39.95-3.23-.05-.19-.14-.33-.29-.41-.15-.09-.31-.1-.5-.05-.83.24-1.81 1.64-2.31 2.48Z"/><circle cx="18" cy="30" r="2.5" fill="#282f33"/><path fill="#c86349" d="M18 33c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3m0-5c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2"/><path fill="#c86349" d="M25 17.5c0-3.31-3.13-6-7-6s-7 2.69-7 6c0 1.2.41 2.32 1.13 3.26.78 1.02 1 2.37.76 3.64-.25 1.33-.39 2.46-.39 3.11 0 2.76 2.46 3 5.5 3s5.5-.24 5.5-3c0-.65-.14-1.77-.39-3.11-.24-1.26-.02-2.61.76-3.64.71-.94 1.13-2.05 1.13-3.26"/><path fill="#262b2b" d="M14.4 20.01s0-1.03 1.03-1.03 1.03 1.03 1.03 1.03v1.03s0 1.03-1.03 1.03-1.03-1.03-1.03-1.03v-1.03Zm5.15 0s0-1.03 1.03-1.03 1.03 1.03 1.03 1.03v1.03s0 1.03-1.03 1.03-1.03-1.03-1.03-1.03z"/><path fill="#6c1a0d" d="M16.06 28.03c.36-.09.51-.76.33-1.49s-.63-1.25-1-1.15-.51.76-.33 1.49.63 1.25 1 1.15Zm4.86-1.16c.19-.73.04-1.4-.33-1.49s-.81.42-1 1.15-.04 1.4.33 1.49.81-.42 1-1.15"/></svg>
|
After Width: | Height: | Size: 2.5 KiB |
1
qml/js/emoji/1facf.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#738695" d="m16.07 26.09 3.23 6.04c.1.18.35.22.49.07l1.49-1.49c.12-.12.12-.31 0-.43l-2.24-2.43a1.03 1.03 0 0 1-.27-.69v-3.72l-3.28-1.94-1 3 1.57 1.59Zm5.7-2.88S23 26 25 27l-1.33 4.07c-.08.2.07.43.29.43h1.52c.14 0 .26-.09.3-.22l1.72-5.78-3-5.38-3 2z"/><path fill="#bfccd5" d="M6.97 5s-1.86 3.92-.18 5.5h1.14S9.02 8.48 6.97 5"/><path fill="#738695" d="M7.02 8.82s.38-1.7 3.48-2.32c1.36-.27 2.42.05 3.11.39.48.24.57.89.16 1.25l-.76.67s1.72-.24 1.99.18c.22.33-.5 1.5-.5 1.5s1.08.02 1.5.5c.11.13.52.54.94.96.69.68 1.54 1.16 2.48 1.4l2.57.64-6.5-.5-4.04-2.91-4.44-1.77Z"/><path fill="#bfccd5" d="M31.4 12.92c-1.91-2.01-5.4-2.75-8.9-.42-4.85 3.23-10-2-10-2-3.36-2.69-5.37-2.21-6.32-1.61-.38.24-.67.59-.87.99l-2.2 4.36c-.84 1.66.82 3.47 2.55 2.79L9.01 16c.71 2.83 2.17 4.41 2.96 5.09.35.3.58.72.64 1.18l.9 7.23-.75 4.05c-.05.27.15.51.42.51h1.89c.24 0 .43-.19.43-.43V29.5s.63-3.81.89-5.36c.06-.34.4-.53.72-.42 3.39 1.12 5.78-.06 6.81-.77.28-.19.67-.08.78.25 1.15 3.42 3.79 4.3 3.79 4.3l-1.34 6.04c-.06.27.15.53.42.53h1.58c.2 0 .37-.13.42-.32l1.81-6.86c.06-.24.03-.51-.1-.73l-.78-1.36a.788.788 0 0 1-.06-.67l2.03-5.63c.06-.16.1-.32.15-.48.22 1.19.35 2.66.35 4.48 0 .28.22.5.5.5s.5-.22.5-.5c0-5.84-1.37-8.43-2.6-9.58Z"/><path fill="#dfe7ed" d="M5.82 15.37S6.5 11.5 2.5 13.5c-2 1-1.06 2.92.36 3.98 1.04.77 2.53.6 3.33-.41.5-.63.67-1.31-.38-1.7Z"/><path fill="#bfccd5" d="M10.38 4.3s-2.86 3.97-1.32 6.06l1.26.23s1.62-2.02.06-6.3Z"/><path fill="#738695" d="M9.76 8.82c.25.1.52.23.79.38.11-.74.08-1.78-.43-3.18 0 0-.88 1.26-1.08 2.59.24.04.48.11.71.2Zm-6 6.12c.13-.52.06-.98-.15-1.04s-.5.32-.63.84-.06.98.15 1.04.5-.32.63-.84"/><path d="M7.2 12.82c.44 0 .8-.36.8-.8s-.36-.8-.8-.8-.8.36-.8.8.36.8.8.8"/><path fill="#738695" d="M13.18 34.06h1.89c.24 0 .43-.19.43-.43V33h-2.65l-.1.55c-.05.27.15.51.42.51ZM27.28 33l-.12.54c-.06.27.15.53.42.53h1.58c.2 0 .37-.13.42-.32l.2-.74h-2.5Zm6.21-11.18c-.98 0-1.93 1.45 0 3.91 0 0 2.44-3.92 0-3.91"/></svg>
|
After Width: | Height: | Size: 2 KiB |
1
qml/js/emoji/1fada.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#f1b777" d="M16.4 26.75c.52.82 1.17 2 1.81 3.58.69 1.71 2.05 3.05 3.8 3.64.05.02.09.03.14.05 3.88 1.31 8.02-1.13 8.75-5.15.22-1.19-.05-2.42-.74-3.42l-1.32-1.9c-.3-.43-.25-1.01.13-1.37 1.35-1.29 4.18-4.55 3.34-8.56-.08-.4-2.81-4.11-6.72-1.05a1.77 1.77 0 0 0-.4 1.96c.36.84.71 2.15.48 3.73-.04.27-.41.32-.51.07-.42-.99-1.31-2.54-2.93-3.14-.42-.16-.71-.55-.71-1v-.98c0-.41.25-.78.63-.91 1.17-.42 3.61-1.55 4.37-3.8 0 0 .49-1.47-.59-2.35-.9-.74-2.29-.51-3.01.4-.38.48-.96.95-1.75.95 0 0 .08-.78.06-1.73a3.497 3.497 0 0 0-2.92-3.37h-.08c-2.49-.42-5.71.1-7.88 2.44-.51.55-1.01 1.1-1.2 1.83-.6 2.35-1.33 8.02 2.85 14.83 0 0-3.43-.77-4.95-4.31a2.197 2.197 0 0 0-2.46-1.3c-1.4.28-2.51 1.36-2.81 2.76-.41 1.87.14 3.82 1.47 5.2 1.9 1.96 5.27 3.9 10.54 2.02.98-.35 2.07 0 2.63.88Z"/><path fill="#ffd875" d="M29.06 27.58c-.69-1.6-3.11-2.09-5.41-1.1-2.3.99-3.6 3.09-2.91 4.69.69 1.6 3.11 2.09 5.41 1.1s3.6-3.09 2.91-4.69Z"/><path fill="#ea9e48" d="M20.21 24.17c-1.56 1.01-2.54 2.4-3.17 3.69.19.35.39.74.59 1.17.52-1.35 1.46-2.96 3.12-4.03 2.16-1.39 5.07-1.59 8.66-.63l-.58-.84c-.08-.11-.13-.24-.16-.36-3.43-.74-6.27-.42-8.46 1m-16.99-.32c.14.14.29.29.45.43-.14-1.9.23-3.4 1.09-4.48.83-1.04 1.96-1.47 2.77-1.65-.17-.28-.34-.59-.48-.92-.93.25-2.13.79-3.06 1.94-.83 1.03-1.27 2.37-1.33 3.98.17.25.36.48.57.7Zm6.8-3.21c-.51-.32-1.07-.74-1.59-1.3-.78.65-1.84 1.79-2.25 3.48-.24 1-.23 2.04.04 3.11.7.3 1.47.52 2.34.63-.53-1.17-.68-2.26-.44-3.24.34-1.42 1.4-2.32 1.9-2.68m6.88-1.34c1.98-2.42 5.18-3.07 6.72-3.24a4.27 4.27 0 0 0-1.27-.82c-1.83.36-4.42 1.23-6.21 3.42-1.49 1.82-2.12 4.2-1.92 7.1.34-.05.69-.02 1.01.08-.22-2.7.33-4.9 1.68-6.54Zm4.6-5.24v-.85c0-.41.25-.78.63-.91.06-.02.13-.05.2-.08-2.73-1.63-5.39-2.16-7.93-1.55-2.46.59-4.27 2.13-5.4 3.39.15.78.35 1.59.63 2.44.64-.94 2.46-3.22 5.25-3.89 2.06-.49 4.29 0 6.62 1.45ZM8.94 7.5c-.08.43-.16.91-.21 1.46 2.43-2.11 7.03-5.05 12.46-3.32-.02-.39-.1-.77-.25-1.12-5.04-1.36-9.34.91-12 2.98Zm14.98-1.67c-.36.13-.69.35-.95.65.76.34 1.62.87 2.09 1.71.35.62.43 1.34.27 2.16a5.2 5.2 0 0 0 1.02-1.48c-.08-.41-.21-.8-.42-1.17-.48-.86-1.25-1.45-2.01-1.86Zm8.51 8.7c-1.28-1.21-2.63-1.88-4.03-1.98-1.4-.09-2.54.41-3.3.87-.09.36-.07.74.08 1.09 0 .01.01.03.02.05.54-.41 1.7-1.12 3.14-1.01 1.39.1 2.76.91 4.06 2.39.05-.45.07-.92.03-1.41m-3.98.82c-.97-.3-1.96-.25-2.96.12.08.31.14.65.18 1.02.85-.36 1.68-.43 2.48-.18 1.46.44 2.56 1.77 3.21 2.75.18-.33.34-.68.49-1.05-.76-1.03-1.91-2.21-3.41-2.66Z"/></svg>
|
After Width: | Height: | Size: 2.4 KiB |
1
qml/js/emoji/1fadb.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#4e932b" d="M28 5C12 5 2.03 33.73 2.03 33.73c.01.24.21.42.45.4l8.78-5.46s.36-.61.83-1.4c.75.3 1.57.45 2.43.4a5.789 5.789 0 0 0 5.44-5.08 6.373 6.373 0 0 0 4.31-6.19c3.64-.44 6.18-4.23 4.61-8.08-.62-1.52.75-3.33-.89-3.33Z"/><circle cx="7.7" cy="30.6" r="3.3" fill="#9bd57f"/><path fill="#4e932b" d="M7 25s-2 4 1.7 6c.26.14 2.46-1.81 2.38-1.4S7.4 25.11 7.4 25.11z"/><circle cx="12.16" cy="26.74" r="5.16" fill="#9bd57f"/><path fill="#4e932b" d="M11 20s-4 2 1 8l4 1z"/><circle cx="15.5" cy="21.5" r="5.5" fill="#9bd57f"/><path fill="#4e932b" d="M13.8 15.12S12.48 21.99 19 24l1.42-1.14-6.63-7.74Z"/><circle cx="19.75" cy="16.33" r="5.58" fill="#9bd57f"/><path fill="#4e932b" d="M19.27 9.73s-1.49 5.78 2.9 8.38l5.69-2.55-8.6-5.83Z"/><circle cx="24.44" cy="11.46" r="4.96" fill="#9bd57f"/><path fill="#69b546" d="M2.35 34.03C4.2 33.16 19 22 29.25 8.47l1.71 1S21 38 2.39 34.23c-.1-.02-.13-.15-.04-.2Z"/><path fill="#4e932b" d="M32.64 3.18c2.46.88 2.24-1.04 1.69-1.62-.81-.84-2.22-.94-3.3-.07-.35.28-.83.89-1.32 1.59-.2.29-.57.38-.89.25-2.85-1.16-5.8-1.23-9.4.4 0 0 2.41 3.35 7.37 3.46 0 0-3.37 3.24-.99 8.24 0 0 3.35-2.41 3.42-5.71 0 0 1.6 2.51 4.91 2.58 0 0-.61-5.8-3.37-7.95-.18-.14-.16-.43.04-.56.74-.47 1.43-.77 1.87-.61Z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
1
qml/js/emoji/1fae8.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><defs><clipPath id="a"><path fill="none" d="M.997 18 17.996 1.001l16.999 17-17 16.998z"/></clipPath></defs><g clip-path="url(#a)"><path fill="#ffcb26" d="M26.5 26.5c-4.69 4.69-12.31 4.69-17 0-4.69-4.69-4.69-12.31 0-17s12.31-4.69 17 0c4.69 4.69 4.69 12.31 0 17"/><path fill="#b68600" d="M14.93 13.99c.65.65 1.92.44 2.83-.47.91-.91 1.12-2.18.47-2.83s-1.92-.44-2.83.47-1.12 2.18-.47 2.83Z"/><path fill="#b68600" d="M16.35 15.4c.65.65 1.92.44 2.83-.47.91-.91 1.12-2.18.47-2.83s-1.92-.44-2.83.47-1.12 2.18-.47 2.83m5.66 5.67c.65.65 1.92.44 2.83-.47s1.12-2.18.47-2.83-1.92-.44-2.83.47-1.12 2.18-.47 2.83Z"/><path fill="#b68600" d="M20.6 19.65c.65.65 1.92.44 2.83-.47s1.12-2.18.47-2.83-1.92-.44-2.83.47-1.12 2.18-.47 2.83"/><path fill="#694400" d="M12.33 23.67c1.04 1.04 2.95.83 4.25-.47s1.52-3.21.47-4.25-2.95-.83-4.25.47-1.52 3.21-.47 4.25Z"/></g><path fill="#4facf0" d="M21.89 33.66c-.46 0-.88-.32-.98-.79-.11-.54.23-1.07.77-1.19 8.4-1.78 9.92-9.63 9.99-9.96.1-.54.62-.9 1.16-.81s.9.62.81 1.16c-.02.09-1.79 9.5-11.54 11.57-.07.01-.14.02-.21.02Zm5.31 2.33c-.46 0-.88-.32-.98-.79-.11-.54.23-1.07.77-1.19 5.89-1.25 6.97-6.75 7.01-6.99.1-.54.62-.9 1.16-.8.54.1.9.61.81 1.16-.05.29-1.33 7.06-8.57 8.59-.07.01-.14.02-.21.02ZM3.34 15.1c-.07 0-.14 0-.21-.02a.998.998 0 0 1-.77-1.19C4.43 4.15 13.83 2.37 13.93 2.36a1 1 0 1 1 .35 1.97c-.35.06-8.18 1.6-9.96 9.99-.1.47-.52.79-.98.79ZM1.01 9.8c-.07 0-.14 0-.21-.02a.998.998 0 0 1-.77-1.19C1.56 1.36 8.34.08 8.62.03A1 1 0 1 1 8.97 2c-.26.05-5.74 1.14-6.99 7.01-.1.47-.51.79-.98.79Z"/><path fill="#694400" d="M15.64 14.69c.65.65 1.92.44 2.83-.47.91-.91 1.12-2.18.47-2.83s-1.92-.44-2.83.47-1.12 2.18-.47 2.83Zm5.67 5.67c.65.65 1.92.44 2.83-.47s1.12-2.18.47-2.83-1.92-.44-2.83.47-1.12 2.18-.47 2.83"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
1
qml/js/emoji/1faf7-1f3fb.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E0AA94" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#F7DECE" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path fill="#E0AA94" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 958 B |
1
qml/js/emoji/1faf7-1f3fc.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#D2A077" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#F3D2A2" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path fill="#D2A077" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 958 B |
1
qml/js/emoji/1faf7-1f3fd.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#B78B60" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#D5AB88" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path fill="#B78B60" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 958 B |
1
qml/js/emoji/1faf7-1f3fe.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path xmlns="http://www.w3.org/2000/svg" fill="#90603E" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#AF7E57" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path xmlns="http://www.w3.org/2000/svg" fill="#90603E" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 1 KiB |
1
qml/js/emoji/1faf7-1f3ff.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#583529" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#7C533E" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path fill="#583529" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 958 B |
1
qml/js/emoji/1faf7.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#EF9645" d="M16.5 31c-.64 0-1.28-.24-1.77-.73C9.28 24.82 6.79 5.49 6.52 3.3 6.35 1.93 7.33.68 8.7.52c1.38-.17 2.62.81 2.78 2.18.93 7.6 3.59 20.84 6.79 24.04a2.499 2.499 0 0 1-1.77 4.27Z"/><path fill="#FFDC5D" d="m28.9 25.33-8.75 1.15c-2.15.51-3.94-1.06-5.01-2.8l-.17-.38c-1.3-2.86-2.22-5.87-2.73-8.97L10.32 2.64a2.392 2.392 0 0 0-4.77.31l.22 12.21c0 .07-.02.14-.05.21-.78 1.3-1.35 3.72.04 7.88-.15.77-.44 1.48-.92 2.69-1.28 4.82 2.35 9.55 7.34 9.55h16.51a2.76 2.76 0 0 0 2.76-2.76v-5.16c0-1.35-1.19-2.4-2.54-2.22Z"/><path fill="#EF9645" d="M12.21 26.47c-.77-1.68-1.11-3.93-1.47-5.82-.22-1.26-.42-2.55-.6-3.81-.05-1.6-1.43-2.97-3.04-2.74-.47.01-.92.11-1.35.26l.02.86c1.24-.57 2.76-.43 3.19 1.06.44 3.71.43 7.3 1.67 10.9.47 1.09 2.09.36 1.59-.71ZM26.55 34H13.33c-1.55 0-3.09-.15-4.61-.46l-2.04-.41a7.564 7.564 0 0 0 5.49 2.35h16.51c1.25 0 2.3-.84 2.64-1.98-1.57.32-3.16.5-4.76.5Z"/></svg>
|
After Width: | Height: | Size: 958 B |
1
qml/js/emoji/1faf8-1f3fb.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#E0AA94" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#F7DECE" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#E0AA94" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5"/></svg>
|
After Width: | Height: | Size: 947 B |
1
qml/js/emoji/1faf8-1f3fc.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#D2A077" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#F3D2A2" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#D2A077" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5Z"/></svg>
|
After Width: | Height: | Size: 948 B |
1
qml/js/emoji/1faf8-1f3fd.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#B78B60" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#D5AB88" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#B78B60" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5"/></svg>
|
After Width: | Height: | Size: 947 B |
1
qml/js/emoji/1faf8-1f3fe.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#90603E" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#AF7E57" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#90603E" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5"/></svg>
|
After Width: | Height: | Size: 947 B |
1
qml/js/emoji/1faf8-1f3ff.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#583529" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#7C533E" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#583529" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5"/></svg>
|
After Width: | Height: | Size: 947 B |
1
qml/js/emoji/1faf8.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36"><path fill="#EF9645" d="M19.5 31c.64 0 1.28-.24 1.77-.73 5.45-5.45 7.95-24.78 8.21-26.96.17-1.37-.81-2.62-2.18-2.78-1.38-.17-2.62.81-2.78 2.18-.93 7.6-3.59 20.84-6.79 24.04a2.499 2.499 0 0 0 1.77 4.27Z"/><path fill="#FFDC5D" d="m7.1 25.33 8.75 1.15c2.15.51 3.94-1.06 5.01-2.8l.17-.38c1.3-2.86 2.22-5.87 2.73-8.97l1.92-11.69a2.392 2.392 0 0 1 4.77.31l-.22 12.21c0 .07.02.14.05.21.78 1.3 1.35 3.72-.04 7.88.15.77.44 1.48.92 2.69 1.28 4.82-2.35 9.55-7.34 9.55H7.33a2.76 2.76 0 0 1-2.76-2.76v-5.16c0-1.35 1.19-2.4 2.54-2.22Z"/><path fill="#EF9645" d="M23.79 26.47c.77-1.68 1.11-3.93 1.47-5.82.22-1.26.42-2.55.6-3.81.05-1.6 1.43-2.97 3.04-2.74.47.01.92.11 1.35.26l-.02.86c-1.24-.57-2.76-.43-3.19 1.06-.44 3.71-.43 7.3-1.67 10.9-.47 1.09-2.09.36-1.59-.71ZM9.45 34h13.22c1.55 0 3.09-.15 4.61-.46l2.04-.41a7.564 7.564 0 0 1-5.49 2.35H7.33c-1.25 0-2.3-.84-2.64-1.98 1.57.32 3.16.5 4.76.5"/></svg>
|
After Width: | Height: | Size: 947 B |
|
@ -517,7 +517,7 @@ function handleErrorMessage(code, message) {
|
|||
}
|
||||
|
||||
function getMessagesNeededForwardPermissions(messages) {
|
||||
var neededPermissions = ["can_send_messages"]
|
||||
var neededPermissions = ["can_send_basic_messages"]
|
||||
|
||||
var mediaMessageTypes = ["messageAudio", "messageDocument", "messagePhoto", "messageVideo", "messageVideoNote", "messageVoiceNote"]
|
||||
var otherMessageTypes = ["messageAnimation", "messageGame", "messageSticker"]
|
||||
|
|
|
@ -609,7 +609,8 @@ Page {
|
|||
Connections {
|
||||
target: chatModel
|
||||
onMessagesReceived: {
|
||||
Debug.log("[ChatPage] Messages received, view has ", chatView.count, " messages, last known message index ", modelIndex, ", own messages were read before index ", lastReadSentIndex);
|
||||
var proxyIndex = chatProxyModel.mapRowFromSource(modelIndex, -1);
|
||||
Debug.log("[ChatPage] Messages received, view has ", chatView.count, " messages, last known message index ", proxyIndex, "("+modelIndex+"), own messages were read before index ", lastReadSentIndex);
|
||||
if (totalCount === 0) {
|
||||
if (chatPage.iterativeInitialization) {
|
||||
chatPage.iterativeInitialization = false;
|
||||
|
@ -623,9 +624,9 @@ Page {
|
|||
}
|
||||
|
||||
chatView.lastReadSentIndex = lastReadSentIndex;
|
||||
chatView.scrollToIndex(modelIndex);
|
||||
chatView.scrollToIndex(proxyIndex);
|
||||
chatPage.loading = false;
|
||||
if (chatOverviewItem.visible && modelIndex >= (chatView.count - 10)) {
|
||||
if (chatOverviewItem.visible && proxyIndex >= (chatView.count - 10)) {
|
||||
chatView.inCooldown = true;
|
||||
chatModel.triggerLoadMoreFuture();
|
||||
}
|
||||
|
@ -669,10 +670,13 @@ Page {
|
|||
chatView.lastReadSentIndex = lastReadSentIndex;
|
||||
}
|
||||
onMessagesIncrementalUpdate: {
|
||||
Debug.log("Incremental update received. View now has ", chatView.count, " messages, view is on index ", modelIndex, ", own messages were read before index ", lastReadSentIndex);
|
||||
var proxyIndex = chatProxyModel.mapRowFromSource(modelIndex, -1);
|
||||
Debug.log("Incremental update received. View now has ", chatView.count, " messages, view is on index ", proxyIndex, "("+modelIndex+"), own messages were read before index ", lastReadSentIndex);
|
||||
chatView.lastReadSentIndex = lastReadSentIndex;
|
||||
if (!chatPage.isInitialized) {
|
||||
chatView.scrollToIndex(modelIndex);
|
||||
if (proxyIndex > -1) {
|
||||
chatView.scrollToIndex(proxyIndex);
|
||||
}
|
||||
}
|
||||
if (chatView.height > chatView.contentHeight) {
|
||||
Debug.log("[ChatPage] Chat content quite small...");
|
||||
|
@ -748,14 +752,26 @@ Page {
|
|||
onTriggered: {
|
||||
Debug.log("scroll position changed, message index: ", lastQueuedIndex);
|
||||
Debug.log("unread count: ", chatInformation.unread_count);
|
||||
var messageToRead = chatModel.getMessage(lastQueuedIndex);
|
||||
var modelIndex = chatProxyModel.mapRowToSource(lastQueuedIndex);
|
||||
var messageToRead = chatModel.getMessage(modelIndex);
|
||||
if (messageToRead['@type'] === "sponsoredMessage") {
|
||||
Debug.log("sponsored message to read: ", messageToRead.id);
|
||||
tdLibWrapper.viewMessage(chatInformation.id, messageToRead.message_id, false);
|
||||
} else if (chatInformation.unread_count > 0 && lastQueuedIndex > -1) {
|
||||
if (messageToRead) {
|
||||
Debug.log("message to read: ", messageToRead.id);
|
||||
if (messageToRead && messageToRead.id) {
|
||||
tdLibWrapper.viewMessage(chatInformation.id, messageToRead.id, false);
|
||||
var messageId = messageToRead.id;
|
||||
var type = messageToRead.content["@type"];
|
||||
if (messageToRead.media_album_id !== '0') {
|
||||
var albumIds = chatModel.getMessageIdsForAlbum(messageToRead.media_album_id);
|
||||
if (albumIds.length > 0) {
|
||||
messageId = albumIds[albumIds.length - 1];
|
||||
Debug.log("message to read last album message id: ", messageId);
|
||||
}
|
||||
}
|
||||
if (messageId) {
|
||||
tdLibWrapper.viewMessage(chatInformation.id, messageId, false);
|
||||
}
|
||||
}
|
||||
lastQueuedIndex = -1
|
||||
}
|
||||
|
@ -781,7 +797,7 @@ Page {
|
|||
NamedAction {
|
||||
visible: messageOptionsDrawer.showCopyMessageToClipboardMenuItem
|
||||
name: qsTr("Copy Message to Clipboard")
|
||||
action: messageOptionsDrawer.myMessage.copyMessageToClipboard
|
||||
action: messageOptionsDrawer.sourceItem.copyMessageToClipboard
|
||||
},
|
||||
NamedAction {
|
||||
visible: messageOptionsDrawer.showForwardMessageMenuItem && messageOptionsDrawer.myMessage.can_be_forwarded
|
||||
|
@ -1223,7 +1239,6 @@ Page {
|
|||
readonly property int messageInReplyToHeight: Theme.fontSizeExtraSmall * 2.571428571 + Theme.paddingSmall;
|
||||
readonly property int webPagePreviewHeight: ( (textColumnWidth * 2 / 3) + (6 * Theme.fontSizeExtraSmall) + ( 7 * Theme.paddingSmall) )
|
||||
readonly property bool pageIsSelecting: chatPage.isSelecting
|
||||
|
||||
}
|
||||
|
||||
function handleScrollPositionChanged() {
|
||||
|
@ -1246,6 +1261,9 @@ Page {
|
|||
positionViewAtIndex(index, (mode === undefined) ? ListView.Contain : mode)
|
||||
if(index === chatView.count - 1) {
|
||||
manuallyScrolledToBottom = true;
|
||||
if(!chatView.atYEnd) {
|
||||
chatView.positionViewAtEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1278,7 +1296,13 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
model: chatModel
|
||||
BoolFilterModel {
|
||||
id: chatProxyModel
|
||||
sourceModel: chatModel
|
||||
filterRoleName: "album_entry_filter"
|
||||
filterValue: false
|
||||
}
|
||||
model: chatProxyModel
|
||||
header: Component {
|
||||
Loader {
|
||||
active: !!chatPage.botInformation
|
||||
|
@ -1311,7 +1335,8 @@ Page {
|
|||
}
|
||||
}
|
||||
|
||||
function getContentComponentHeight(contentType, content, parentWidth) {
|
||||
function getContentComponentHeight(contentType, content, parentWidth, albumEntries) {
|
||||
var unit;
|
||||
switch(contentType) {
|
||||
case "messageAnimatedEmoji":
|
||||
return content.animated_emoji.sticker.height;
|
||||
|
@ -1327,6 +1352,10 @@ Page {
|
|||
case "messageVenue":
|
||||
return parentWidth * 0.66666666; // 2 / 3;
|
||||
case "messagePhoto":
|
||||
if(albumEntries > 0) {
|
||||
unit = (parentWidth * 0.66666666)
|
||||
return (albumEntries % 2 !== 0 ? unit * 0.75 : 0) + unit * albumEntries * 0.25
|
||||
}
|
||||
var biggest = content.photo.sizes[content.photo.sizes.length - 1];
|
||||
var aspectRatio = biggest.width/biggest.height;
|
||||
return Math.max(Theme.itemSizeExtraSmall, Math.min(parentWidth * 0.66666666, parentWidth / aspectRatio));
|
||||
|
@ -1335,6 +1364,10 @@ Page {
|
|||
case "messageSticker":
|
||||
return content.sticker.height;
|
||||
case "messageVideo":
|
||||
if(albumEntries > 0) {
|
||||
unit = (parentWidth * 0.66666666)
|
||||
return (albumEntries % 2 !== 0 ? unit * 0.75 : 0) + unit * albumEntries * 0.25
|
||||
}
|
||||
return Functions.getVideoHeight(parentWidth, content.video);
|
||||
case "messageVideoNote":
|
||||
return parentWidth
|
||||
|
@ -1390,10 +1423,11 @@ Page {
|
|||
chatId: chatModel.chatId
|
||||
myMessage: model.display
|
||||
messageId: model.message_id
|
||||
messageAlbumMessageIds: model.album_message_ids
|
||||
messageViewCount: model.view_count
|
||||
reactions: model.reactions
|
||||
chatReactions: availableReactions
|
||||
messageIndex: model.index
|
||||
messageIndex: chatProxyModel.mapRowToSource(model.index)
|
||||
hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1
|
||||
canReplyToMessage: chatPage.canSendMessages
|
||||
onReplyToMessage: {
|
||||
|
@ -1414,9 +1448,21 @@ Page {
|
|||
id: messageListViewItemSimpleComponent
|
||||
MessageListViewItemSimple {}
|
||||
}
|
||||
sourceComponent: chatView.simpleDelegateMessages.indexOf(model.content_type) > -1 ? messageListViewItemSimpleComponent : messageListViewItemComponent
|
||||
Component {
|
||||
id: messageListViewItemHiddenComponent
|
||||
Item {
|
||||
property var myMessage: display
|
||||
property bool senderIsUser: myMessage.sender_id["@type"] === "messageSenderUser"
|
||||
property var userInformation: senderIsUser ? tdLibWrapper.getUserInformation(myMessage.sender_id.user_id) : null
|
||||
property bool isOwnMessage: senderIsUser && chatPage.myUserId === myMessage.sender_id.user_id
|
||||
height: 1
|
||||
}
|
||||
VerticalScrollDecorator {}
|
||||
}
|
||||
sourceComponent: chatView.simpleDelegateMessages.indexOf(model.content_type) > -1
|
||||
? messageListViewItemSimpleComponent
|
||||
: messageListViewItemComponent
|
||||
}
|
||||
VerticalScrollDecorator { flickable: chatView }
|
||||
|
||||
ViewPlaceholder {
|
||||
id: chatViewPlaceholder
|
||||
|
@ -1877,7 +1923,7 @@ Page {
|
|||
|
||||
Image {
|
||||
id: emojiPicture
|
||||
source: "../js/emoji/" + modelData.file_name
|
||||
source: "../js/emoji/" + modelData.file_name +".svg"
|
||||
width: Theme.fontSizeLarge
|
||||
height: Theme.fontSizeLarge
|
||||
}
|
||||
|
|
109
qml/pages/MediaAlbumPage.qml
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
// jolla-gallery/pages/FlickableImageView.qml
|
||||
/*
|
||||
|
||||
FullscreenContentPage
|
||||
- PagedView (jolla-gallery/FlickableImageView)
|
||||
- delegate: Loader
|
||||
- SilicaFlickable (Silica.private/ZoomableFlickable) (Sailfish.Gallery/ImageViewer)
|
||||
- PinchArea
|
||||
- dragDetector(?)
|
||||
- image
|
||||
- Item (Sailfish.Gallery/GalleryOverlay)
|
||||
|
||||
*/
|
||||
|
||||
import QtQuick 2.6
|
||||
import Sailfish.Silica 1.0
|
||||
import WerkWolf.Fernschreiber 1.0
|
||||
import "../components"
|
||||
|
||||
import "../components/messageContent/mediaAlbumPage"
|
||||
import "../js/twemoji.js" as Emoji
|
||||
import "../js/functions.js" as Functions
|
||||
|
||||
Page {
|
||||
// id
|
||||
id: page
|
||||
// property declarations
|
||||
|
||||
property alias index: pagedView.currentIndex
|
||||
property alias overlayActive: overlay.active
|
||||
property alias delegate: pagedView.delegate
|
||||
property var messages: [];
|
||||
// message.content.caption.text
|
||||
palette.colorScheme: Theme.LightOnDark
|
||||
clip: status !== PageStatus.Active || pageStack.dragInProgress
|
||||
navigationStyle: PageNavigation.Vertical
|
||||
backgroundColor: 'black'
|
||||
allowedOrientations: Orientation.All
|
||||
// signal declarations
|
||||
// JavaScript functions
|
||||
|
||||
// object (parent) properties
|
||||
// large property bindings
|
||||
// child objects
|
||||
// states
|
||||
// transitions
|
||||
|
||||
|
||||
|
||||
// content
|
||||
PagedView {
|
||||
id: pagedView
|
||||
anchors.fill: parent
|
||||
model: messages
|
||||
delegate: Component {
|
||||
Loader {
|
||||
id: loader
|
||||
asynchronous: true
|
||||
visible: status == Loader.Ready
|
||||
width: PagedView.contentWidth
|
||||
height: PagedView.contentHeight
|
||||
|
||||
states: [
|
||||
State {
|
||||
when: model.modelData.content['@type'] === 'messagePhoto'
|
||||
PropertyChanges {
|
||||
target: loader
|
||||
source: "../components/messageContent/mediaAlbumPage/PhotoComponent.qml"
|
||||
}
|
||||
},
|
||||
State {
|
||||
when: model.modelData.content['@type'] === 'messageVideo'
|
||||
PropertyChanges {
|
||||
target: loader
|
||||
source: "../components/messageContent/mediaAlbumPage/VideoComponent.qml"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// overlay
|
||||
FullscreenOverlay {
|
||||
id: overlay
|
||||
pageCount: messages.length
|
||||
currentIndex: page.index
|
||||
message: messages[currentIndex]
|
||||
//
|
||||
}
|
||||
}
|
153
src/boolfiltermodel.cpp
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "boolfiltermodel.h"
|
||||
|
||||
#define DEBUG_MODULE BoolFilterModel
|
||||
#include "debuglog.h"
|
||||
|
||||
BoolFilterModel::BoolFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
setDynamicSortFilter(true);
|
||||
// setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
// setFilterFixedString(QString());
|
||||
filterValue = true;
|
||||
}
|
||||
|
||||
void BoolFilterModel::setSource(QObject *model)
|
||||
{
|
||||
setSourceModel(qobject_cast<QAbstractItemModel*>(model));
|
||||
}
|
||||
|
||||
void BoolFilterModel::setSourceModel(QAbstractItemModel *model)
|
||||
{
|
||||
if (sourceModel() != model) {
|
||||
LOG(model);
|
||||
QSortFilterProxyModel::setSourceModel(model);
|
||||
updateFilterRole();
|
||||
emit sourceChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString BoolFilterModel::getFilterRoleName() const
|
||||
{
|
||||
return filterRoleName;
|
||||
}
|
||||
|
||||
void BoolFilterModel::setFilterRoleName(QString role)
|
||||
{
|
||||
if (filterRoleName != role) {
|
||||
filterRoleName = role;
|
||||
LOG(role);
|
||||
updateFilterRole();
|
||||
emit filterRoleNameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool BoolFilterModel::getFilterValue() const
|
||||
{
|
||||
return filterValue;
|
||||
}
|
||||
|
||||
void BoolFilterModel::setFilterValue(bool value)
|
||||
{
|
||||
if(value != filterValue) {
|
||||
filterValue = value;
|
||||
invalidateFilter();
|
||||
}
|
||||
}
|
||||
|
||||
int BoolFilterModel::mapRowFromSource(int i, int fallbackDirection)
|
||||
{
|
||||
QModelIndex myIndex = mapFromSource(sourceModel()->index(i, 0));
|
||||
LOG("mapping index" << i << "to source model:" << myIndex.row() << "valid?" << myIndex.isValid());
|
||||
if(myIndex.isValid()) {
|
||||
return myIndex.row();
|
||||
}
|
||||
|
||||
if(fallbackDirection > 0) {
|
||||
int max = sourceModel()->rowCount();
|
||||
i += 1;
|
||||
while (i < max) {
|
||||
myIndex = mapFromSource(sourceModel()->index(i, 0));
|
||||
|
||||
LOG("fallback ++ " << i << "to source model:" << myIndex.row() << "valid?" << myIndex.isValid());
|
||||
if(myIndex.isValid()) {
|
||||
return myIndex.row();
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
} else if(fallbackDirection < 0) {
|
||||
i -= 1;
|
||||
while (i > -1) {
|
||||
myIndex = mapFromSource(sourceModel()->index(i, 0));
|
||||
LOG("fallback -- " << i << "to source model:" << myIndex.row() << "valid?" << myIndex.isValid());
|
||||
if(myIndex.isValid()) {
|
||||
return myIndex.row();
|
||||
}
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return myIndex.row(); // may still be -1
|
||||
}
|
||||
|
||||
int BoolFilterModel::mapRowToSource(int i)
|
||||
{
|
||||
QModelIndex sourceIndex = mapToSource(index(i, 0));
|
||||
return sourceIndex.row();
|
||||
}
|
||||
bool BoolFilterModel::filterAcceptsRow(int sourceRow,
|
||||
const QModelIndex &sourceParent) const
|
||||
{
|
||||
// sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(); //.toString().contains( /*string for column 0*/ ))
|
||||
// LOG("Filter Role " << filterRole());
|
||||
// QModelIndex index = this->sourceModel()->index(sourceRow,1,sourceParent);
|
||||
// sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(filterRole()).toBool();
|
||||
// LOG("Filter index DATA"<< sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(filterRole())); //<< index << index.isValid());
|
||||
// LOG("Filter parent " << sourceParent << sourceParent.isValid());
|
||||
// LOG("Filter Model Value" << sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(filterRole()).toBool());
|
||||
// LOG("Filter Model filterValue" << filterValue);
|
||||
// LOG("Filter Model result" << (sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(filterRole()).toBool() == filterValue));
|
||||
// LOG("Filter Model MESSAGE" << sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data());
|
||||
return sourceModel()->index(sourceRow, 0, sourceParent.child(sourceRow, 0)).data(filterRole()).toBool() == filterValue;
|
||||
}
|
||||
|
||||
int BoolFilterModel::findRole(QAbstractItemModel *model, QString role)
|
||||
{
|
||||
if (model && !role.isEmpty()) {
|
||||
const QByteArray roleName(role.toUtf8());
|
||||
const QHash<int,QByteArray> roleMap(model->roleNames());
|
||||
const QList<int> roles(roleMap.keys());
|
||||
const int n = roles.count();
|
||||
for (int i = 0; i < n; i++) {
|
||||
const QByteArray name(roleMap.value(roles.at(i)));
|
||||
if (name == roleName) {
|
||||
LOG(role << roles.at(i));
|
||||
return roles.at(i);
|
||||
}
|
||||
}
|
||||
LOG("Unknown role" << role);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void BoolFilterModel::updateFilterRole()
|
||||
{
|
||||
const int role = findRole(sourceModel(), filterRoleName);
|
||||
setFilterRole((role >= 0) ? role : Qt::DisplayRole);
|
||||
}
|
63
src/boolfiltermodel.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#ifndef BOOLFILTERMODEL_H
|
||||
#define BOOLFILTERMODEL_H
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class BoolFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString filterRoleName READ getFilterRoleName WRITE setFilterRoleName NOTIFY filterRoleNameChanged)
|
||||
Q_PROPERTY(bool filterValue READ getFilterValue WRITE setFilterValue NOTIFY filterValueChanged)
|
||||
Q_PROPERTY(QObject* sourceModel READ sourceModel WRITE setSource NOTIFY sourceChanged)
|
||||
|
||||
public:
|
||||
BoolFilterModel(QObject *parent = Q_NULLPTR);
|
||||
|
||||
void setSource(QObject* model);
|
||||
void setSourceModel(QAbstractItemModel *model) Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
QString getFilterRoleName() const;
|
||||
void setFilterRoleName(QString role);
|
||||
|
||||
bool getFilterValue() const;
|
||||
void setFilterValue(bool value);
|
||||
Q_INVOKABLE int mapRowFromSource(int i, int fallbackDirection);
|
||||
Q_INVOKABLE int mapRowToSource(int i);
|
||||
|
||||
signals:
|
||||
void sourceChanged();
|
||||
void filterRoleNameChanged();
|
||||
void filterValueChanged();
|
||||
|
||||
private slots:
|
||||
void updateFilterRole();
|
||||
|
||||
private:
|
||||
static int findRole(QAbstractItemModel *model, QString role);
|
||||
|
||||
private:
|
||||
QString filterRoleName;
|
||||
bool filterValue;
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
};
|
||||
|
||||
#endif // BOOLFILTERMODEL_H
|
|
@ -30,6 +30,7 @@ namespace {
|
|||
const QString ID("id");
|
||||
const QString CONTENT("content");
|
||||
const QString CHAT_ID("chat_id");
|
||||
const QString DATE("date");
|
||||
const QString PHOTO("photo");
|
||||
const QString SMALL("small");
|
||||
const QString UNREAD_COUNT("unread_count");
|
||||
|
@ -48,6 +49,7 @@ namespace {
|
|||
// "view_count": 47
|
||||
// }
|
||||
const QString TYPE_MESSAGE_INTERACTION_INFO("messageInteractionInfo");
|
||||
const QString MEDIA_ALBUM_ID("media_album_id");
|
||||
const QString INTERACTION_INFO("interaction_info");
|
||||
const QString VIEW_COUNT("view_count");
|
||||
const QString REACTIONS("reactions");
|
||||
|
@ -63,7 +65,9 @@ public:
|
|||
RoleMessageId,
|
||||
RoleMessageContentType,
|
||||
RoleMessageViewCount,
|
||||
RoleMessageReactions
|
||||
RoleMessageReactions,
|
||||
RoleMessageAlbumEntryFilter,
|
||||
RoleMessageAlbumMessageIds,
|
||||
};
|
||||
|
||||
enum RoleFlag {
|
||||
|
@ -71,7 +75,9 @@ public:
|
|||
RoleFlagMessageId = 0x02,
|
||||
RoleFlagMessageContentType = 0x04,
|
||||
RoleFlagMessageViewCount = 0x08,
|
||||
RoleFlagMessageReactions = 0x16
|
||||
RoleFlagMessageReactions = 0x16,
|
||||
RoleFlagMessageAlbumEntryFilter = 0x32,
|
||||
RoleFlagMessageAlbumMessageIds = 0x64
|
||||
};
|
||||
|
||||
MessageData(const QVariantMap &data, qlonglong msgid);
|
||||
|
@ -86,12 +92,16 @@ public:
|
|||
uint updateViewCount(const QVariantMap &interactionInfo);
|
||||
uint updateInteractionInfo(const QVariantMap &interactionInfo);
|
||||
uint updateReactions(const QVariantMap &interactionInfo);
|
||||
uint updateAlbumEntryFilter(const bool isAlbumChild);
|
||||
uint updateAlbumEntryMessageIds(const QVariantList &newAlbumMessageIds);
|
||||
|
||||
QVector<int> diff(const MessageData *message) const;
|
||||
QVector<int> setMessageData(const QVariantMap &data);
|
||||
QVector<int> setContent(const QVariantMap &content);
|
||||
QVector<int> setReplyMarkup(const QVariantMap &replyMarkup);
|
||||
QVector<int> setInteractionInfo(const QVariantMap &interactionInfo);
|
||||
QVector<int> setAlbumEntryFilter(bool isAlbumChild);
|
||||
QVector<int> setAlbumEntryMessageIds(const QVariantList &newAlbumMessageIds);
|
||||
|
||||
int senderUserId() const;
|
||||
qlonglong senderChatId() const;
|
||||
|
@ -104,6 +114,8 @@ public:
|
|||
QString messageContentType;
|
||||
int viewCount;
|
||||
QVariantList reactions;
|
||||
bool albumEntryFilter;
|
||||
QVariantList albumMessageIds;
|
||||
};
|
||||
|
||||
ChatModel::MessageData::MessageData(const QVariantMap &data, qlonglong msgid) :
|
||||
|
@ -112,7 +124,9 @@ ChatModel::MessageData::MessageData(const QVariantMap &data, qlonglong msgid) :
|
|||
messageType(data.value(_TYPE).toString()),
|
||||
messageContentType(data.value(CONTENT).toMap().value(_TYPE).toString()),
|
||||
viewCount(data.value(INTERACTION_INFO).toMap().value(VIEW_COUNT).toInt()),
|
||||
reactions(data.value(INTERACTION_INFO).toMap().value(REACTIONS).toList())
|
||||
reactions(data.value(INTERACTION_INFO).toMap().value(REACTIONS).toList()),
|
||||
albumEntryFilter(false),
|
||||
albumMessageIds(QVariantList())
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -134,6 +148,12 @@ QVector<int> ChatModel::MessageData::flagsToRoles(uint flags)
|
|||
if (flags & RoleFlagMessageReactions) {
|
||||
roles.append(RoleMessageReactions);
|
||||
}
|
||||
if (flags & RoleFlagMessageAlbumEntryFilter) {
|
||||
roles.append(RoleMessageAlbumEntryFilter);
|
||||
}
|
||||
if (flags & RoleFlagMessageAlbumMessageIds) {
|
||||
roles.append(RoleMessageAlbumMessageIds);
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -169,6 +189,12 @@ QVector<int> ChatModel::MessageData::diff(const MessageData *message) const
|
|||
if (message->reactions != reactions) {
|
||||
roles.append(RoleMessageReactions);
|
||||
}
|
||||
if (message->albumEntryFilter != albumEntryFilter) {
|
||||
roles.append(RoleMessageAlbumEntryFilter);
|
||||
}
|
||||
if (message->albumMessageIds != albumMessageIds) {
|
||||
roles.append(RoleMessageAlbumMessageIds);
|
||||
}
|
||||
}
|
||||
return roles;
|
||||
}
|
||||
|
@ -237,6 +263,37 @@ uint ChatModel::MessageData::updateReactions(const QVariantMap &interactionInfo)
|
|||
return (reactions == oldReactions) ? 0 : RoleFlagMessageReactions;
|
||||
}
|
||||
|
||||
uint ChatModel::MessageData::updateAlbumEntryFilter(const bool isAlbumChild)
|
||||
{
|
||||
LOG("Updating album filter... for id " << messageId << " value:" << isAlbumChild << "previously" << albumEntryFilter);
|
||||
const bool oldAlbumFiltered = albumEntryFilter;
|
||||
albumEntryFilter = isAlbumChild;
|
||||
return (isAlbumChild == oldAlbumFiltered) ? 0 : RoleFlagMessageAlbumEntryFilter;
|
||||
}
|
||||
|
||||
|
||||
QVector<int> ChatModel::MessageData::setAlbumEntryFilter(bool isAlbumChild)
|
||||
{
|
||||
LOG("setAlbumEntryFilter");
|
||||
return flagsToRoles(updateAlbumEntryFilter(isAlbumChild));
|
||||
}
|
||||
|
||||
uint ChatModel::MessageData::updateAlbumEntryMessageIds(const QVariantList &newAlbumMessageIds)
|
||||
{
|
||||
LOG("Updating albumMessageIds... id" << messageId);
|
||||
LOG(" Updating albumMessageIds..." << newAlbumMessageIds << "previously" << albumMessageIds << "same?" << (newAlbumMessageIds == albumMessageIds));
|
||||
const QVariantList oldAlbumMessageIds = albumMessageIds;
|
||||
albumMessageIds = newAlbumMessageIds;
|
||||
|
||||
LOG(" Updating albumMessageIds... same again?" << (newAlbumMessageIds == oldAlbumMessageIds));
|
||||
return (newAlbumMessageIds == oldAlbumMessageIds) ? 0 : RoleFlagMessageAlbumMessageIds;
|
||||
}
|
||||
|
||||
QVector<int> ChatModel::MessageData::setAlbumEntryMessageIds(const QVariantList &newAlbumMessageIds)
|
||||
{
|
||||
return flagsToRoles(updateAlbumEntryMessageIds(newAlbumMessageIds));
|
||||
}
|
||||
|
||||
QVector<int> ChatModel::MessageData::setInteractionInfo(const QVariantMap &info)
|
||||
{
|
||||
return flagsToRoles(updateInteractionInfo(info));
|
||||
|
@ -295,6 +352,8 @@ QHash<int,QByteArray> ChatModel::roleNames() const
|
|||
roles.insert(MessageData::RoleMessageContentType, "content_type");
|
||||
roles.insert(MessageData::RoleMessageViewCount, "view_count");
|
||||
roles.insert(MessageData::RoleMessageReactions, "reactions");
|
||||
roles.insert(MessageData::RoleMessageAlbumEntryFilter, "album_entry_filter");
|
||||
roles.insert(MessageData::RoleMessageAlbumMessageIds, "album_message_ids");
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -314,6 +373,8 @@ QVariant ChatModel::data(const QModelIndex &index, int role) const
|
|||
case MessageData::RoleMessageContentType: return message->messageContentType;
|
||||
case MessageData::RoleMessageViewCount: return message->viewCount;
|
||||
case MessageData::RoleMessageReactions: return message->reactions;
|
||||
case MessageData::RoleMessageAlbumEntryFilter: return message->albumEntryFilter;
|
||||
case MessageData::RoleMessageAlbumMessageIds: return message->albumMessageIds;
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
|
@ -331,6 +392,7 @@ void ChatModel::clear(bool contentOnly)
|
|||
qDeleteAll(messages);
|
||||
messages.clear();
|
||||
messageIndexMap.clear();
|
||||
albumMessageMap.clear();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
|
@ -356,6 +418,7 @@ void ChatModel::initialize(const QVariantMap &chatInformation)
|
|||
this->chatId = chatId;
|
||||
this->messages.clear();
|
||||
this->messageIndexMap.clear();
|
||||
this->albumMessageMap.clear();
|
||||
this->searchQuery.clear();
|
||||
endResetModel();
|
||||
emit chatIdChanged();
|
||||
|
@ -420,6 +483,36 @@ int ChatModel::getMessageIndex(qlonglong messageId)
|
|||
return -1;
|
||||
}
|
||||
|
||||
QVariantList ChatModel::getMessageIdsForAlbum(qlonglong albumId)
|
||||
{
|
||||
QVariantList foundMessages;
|
||||
if(albumMessageMap.contains(albumId)) { // there should be only one in here
|
||||
QHash< qlonglong, QVariantList >::iterator i = albumMessageMap.find(albumId);
|
||||
return i.value();
|
||||
}
|
||||
return foundMessages;
|
||||
}
|
||||
|
||||
QVariantList ChatModel::getMessagesForAlbum(qlonglong albumId, int startAt)
|
||||
{
|
||||
LOG("getMessagesForAlbumId" << albumId);
|
||||
QVariantList messageIds = getMessageIdsForAlbum(albumId);
|
||||
int count = messageIds.size();
|
||||
if ( count == 0) {
|
||||
return messageIds;
|
||||
}
|
||||
QVariantList foundMessages;
|
||||
for (int messageNum = startAt; messageNum < count; ++messageNum) {
|
||||
const int position = messageIndexMap.value(messageIds.at(messageNum).toLongLong(), -1);
|
||||
if(position >= 0 && position < messages.size()) {
|
||||
foundMessages.append(messages.at(position)->messageData);
|
||||
} else {
|
||||
LOG("Not found in messages: #"<< messageNum);
|
||||
}
|
||||
}
|
||||
return foundMessages;
|
||||
}
|
||||
|
||||
int ChatModel::getLastReadMessageIndex()
|
||||
{
|
||||
LOG("Obtaining last read message index");
|
||||
|
@ -477,7 +570,8 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCo
|
|||
const qlonglong messageId = messageData.value(ID).toLongLong();
|
||||
if (messageId && messageData.value(CHAT_ID).toLongLong() == chatId && !messageIndexMap.contains(messageId)) {
|
||||
LOG("New message will be added:" << messageId);
|
||||
messagesToBeAdded.append(new MessageData(messageData, messageId));
|
||||
MessageData* message = new MessageData(messageData, messageId);
|
||||
messagesToBeAdded.append(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -485,6 +579,7 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages, int totalCo
|
|||
|
||||
if (!messagesToBeAdded.isEmpty()) {
|
||||
insertMessages(messagesToBeAdded);
|
||||
setMessagesAlbum(messagesToBeAdded);
|
||||
}
|
||||
|
||||
// First call only returns a few messages, we need to get a little more than that...
|
||||
|
@ -540,6 +635,7 @@ void ChatModel::handleNewMessageReceived(qlonglong chatId, const QVariantMap &me
|
|||
QList<MessageData*> messagesToBeAdded;
|
||||
messagesToBeAdded.append(new MessageData(message, messageId));
|
||||
insertMessages(messagesToBeAdded);
|
||||
setMessagesAlbum(messagesToBeAdded);
|
||||
emit newMessageReceived(message);
|
||||
} else {
|
||||
LOG("New message in this chat, but not relevant as less recent messages need to be loaded first!");
|
||||
|
@ -591,6 +687,7 @@ void ChatModel::handleMessageSendSucceeded(qlonglong messageId, qlonglong oldMes
|
|||
messages.replace(pos, newMessage);
|
||||
messageIndexMap.remove(oldMessageId);
|
||||
messageIndexMap.insert(messageId, pos);
|
||||
// TODO when we support sending album messages, handle ID change in albumMessageMap
|
||||
const QVector<int> changedRoles(newMessage->diff(oldMessage));
|
||||
delete oldMessage;
|
||||
LOG("Message was replaced at index" << pos);
|
||||
|
@ -635,7 +732,8 @@ void ChatModel::handleMessageContentUpdated(qlonglong chatId, qlonglong messageI
|
|||
LOG("We know the message that was updated" << messageId);
|
||||
const int pos = messageIndexMap.value(messageId, -1);
|
||||
if (pos >= 0) {
|
||||
const QVector<int> changedRoles(messages.at(pos)->setContent(newContent));
|
||||
MessageData* messageData = messages.at(pos);
|
||||
const QVector<int> changedRoles(messageData->setContent(newContent));
|
||||
LOG("Message was updated at index" << pos);
|
||||
const QModelIndex messageIndex(index(pos));
|
||||
emit dataChanged(messageIndex, messageIndex, changedRoles);
|
||||
|
@ -664,7 +762,8 @@ void ChatModel::handleMessageEditedUpdated(qlonglong chatId, qlonglong messageId
|
|||
LOG("We know the message that was updated" << messageId);
|
||||
const int pos = messageIndexMap.value(messageId, -1);
|
||||
if (pos >= 0) {
|
||||
const QVector<int> changedRoles(messages.at(pos)->setReplyMarkup(replyMarkup));
|
||||
MessageData* messageData = messages.at(pos);
|
||||
const QVector<int> changedRoles(messageData->setReplyMarkup(replyMarkup));
|
||||
LOG("Message was edited at index" << pos);
|
||||
const QModelIndex messageIndex(index(pos));
|
||||
emit dataChanged(messageIndex, messageIndex, changedRoles);
|
||||
|
@ -709,18 +808,31 @@ void ChatModel::handleMessagesDeleted(qlonglong chatId, const QList<qlonglong> &
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void ChatModel::removeRange(int firstDeleted, int lastDeleted)
|
||||
{
|
||||
if (firstDeleted >= 0 && firstDeleted <= lastDeleted) {
|
||||
LOG("Removing range" << firstDeleted << "..." << lastDeleted << "| current messages size" << messages.size());
|
||||
beginRemoveRows(QModelIndex(), firstDeleted, lastDeleted);
|
||||
QList<qlonglong> rescanAlbumIds;
|
||||
for (int i = firstDeleted; i <= lastDeleted; i++) {
|
||||
MessageData *message = messages.at(i);
|
||||
messageIndexMap.remove(message->messageId);
|
||||
|
||||
qlonglong albumId = message->messageData.value(MEDIA_ALBUM_ID).toLongLong();
|
||||
if(albumId != 0 && albumMessageMap.contains(albumId)) {
|
||||
rescanAlbumIds.append(albumId);
|
||||
}
|
||||
delete message;
|
||||
}
|
||||
messages.erase(messages.begin() + firstDeleted, messages.begin() + (lastDeleted + 1));
|
||||
// rebuild following messageIndexMap
|
||||
for(int i = firstDeleted; i < messages.size(); ++i) {
|
||||
messageIndexMap.insert(messages.at(i)->messageId, i);
|
||||
}
|
||||
endRemoveRows();
|
||||
|
||||
updateAlbumMessages(rescanAlbumIds, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -757,7 +869,7 @@ void ChatModel::appendMessages(const QList<MessageData*> newMessages)
|
|||
beginInsertRows(QModelIndex(), oldSize, oldSize + count - 1);
|
||||
messages.append(newMessages);
|
||||
for (int i = 0; i < count; i++) {
|
||||
// Appens new indeces to the map
|
||||
// Append new indices to the map
|
||||
messageIndexMap.insert(newMessages.at(i)->messageId, oldSize + i);
|
||||
}
|
||||
endInsertRows();
|
||||
|
@ -785,6 +897,90 @@ void ChatModel::prependMessages(const QList<MessageData*> newMessages)
|
|||
endInsertRows();
|
||||
}
|
||||
|
||||
void ChatModel::updateAlbumMessages(qlonglong albumId, bool checkDeleted)
|
||||
{
|
||||
if(albumMessageMap.contains(albumId)) {
|
||||
const QVariantList empty;
|
||||
QHash< qlonglong, QVariantList >::iterator album = albumMessageMap.find(albumId);
|
||||
QVariantList messageIds = album.value();
|
||||
std::sort(messageIds.begin(), messageIds.end());
|
||||
int count;
|
||||
// first: clear deleted messageIds:
|
||||
if(checkDeleted) {
|
||||
QVariantList::iterator it = messageIds.begin();
|
||||
while (it != messageIds.end()) {
|
||||
if (!messageIndexMap.contains(it->toLongLong())) {
|
||||
it = messageIds.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
// second: remaining ones still exist
|
||||
count = messageIds.size();
|
||||
if(count == 0) {
|
||||
albumMessageMap.remove(albumId);
|
||||
} else {
|
||||
for (int i = 0; i < count; i++) {
|
||||
const int position = messageIndexMap.value(messageIds.at(i).toLongLong(), -1);
|
||||
if(position > -1) {
|
||||
// set list for first entry, empty for all others
|
||||
QVector<int> changedRolesFilter;
|
||||
QVector<int> changedRolesIds;
|
||||
|
||||
QModelIndex messageIndex(index(position));
|
||||
if(i == 0) {
|
||||
changedRolesFilter = messages.at(position)->setAlbumEntryFilter(false);
|
||||
changedRolesIds = messages.at(position)->setAlbumEntryMessageIds(messageIds);
|
||||
} else {
|
||||
changedRolesFilter = messages.at(position)->setAlbumEntryFilter(true);
|
||||
changedRolesIds = messages.at(position)->setAlbumEntryMessageIds(empty);
|
||||
}
|
||||
emit dataChanged(messageIndex, messageIndex, changedRolesIds);
|
||||
emit dataChanged(messageIndex, messageIndex, changedRolesFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
albumMessageMap.insert(albumId, messageIds);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatModel::updateAlbumMessages(QList<qlonglong> albumIds, bool checkDeleted)
|
||||
{
|
||||
const int albumsCount = albumIds.size();
|
||||
for (int i = 0; i < albumsCount; i++) {
|
||||
updateAlbumMessages(albumIds.at(i), checkDeleted);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatModel::setMessagesAlbum(const QList<MessageData *> newMessages)
|
||||
{
|
||||
const int count = newMessages.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
setMessagesAlbum(newMessages.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
void ChatModel::setMessagesAlbum(MessageData *message)
|
||||
{
|
||||
qlonglong albumId = message->messageData.value(MEDIA_ALBUM_ID).toLongLong();
|
||||
if (albumId > 0 && (message->messageContentType != "messagePhoto" || message->messageContentType != "messageVideo")) {
|
||||
qlonglong messageId = message->messageId;
|
||||
|
||||
if(albumMessageMap.contains(albumId)) {
|
||||
// find message id within album:
|
||||
QHash< qlonglong, QVariantList >::iterator i = albumMessageMap.find(albumId);
|
||||
if(!i.value().contains(messageId)) {
|
||||
i.value().append(messageId);
|
||||
}
|
||||
} else { // new album id
|
||||
albumMessageMap.insert(albumId, QVariantList() << messageId);
|
||||
}
|
||||
updateAlbumMessages(albumId, false);
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap ChatModel::enhanceMessage(const QVariantMap &message)
|
||||
{
|
||||
QVariantMap enhancedMessage = message;
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
Q_INVOKABLE void triggerLoadMoreFuture();
|
||||
Q_INVOKABLE QVariantMap getChatInformation();
|
||||
Q_INVOKABLE QVariantMap getMessage(int index);
|
||||
Q_INVOKABLE QVariantList getMessageIdsForAlbum(qlonglong albumId);
|
||||
Q_INVOKABLE QVariantList getMessagesForAlbum(qlonglong albumId, int startAt);
|
||||
Q_INVOKABLE int getLastReadMessageIndex();
|
||||
Q_INVOKABLE void setSearchQuery(const QString newSearchQuery);
|
||||
|
||||
|
@ -85,6 +87,10 @@ private:
|
|||
void insertMessages(const QList<MessageData*> newMessages);
|
||||
void appendMessages(const QList<MessageData*> newMessages);
|
||||
void prependMessages(const QList<MessageData*> newMessages);
|
||||
void updateAlbumMessages(qlonglong albumId, bool checkDeleted);
|
||||
void updateAlbumMessages(QList<qlonglong> albumIds, bool checkDeleted);
|
||||
void setMessagesAlbum(const QList<MessageData*> newMessages);
|
||||
void setMessagesAlbum(MessageData *message);
|
||||
QVariantMap enhanceMessage(const QVariantMap &message);
|
||||
int calculateLastKnownMessageId();
|
||||
int calculateLastReadSentMessageId();
|
||||
|
@ -95,6 +101,7 @@ private:
|
|||
TDLibWrapper *tdLibWrapper;
|
||||
QList<MessageData*> messages;
|
||||
QHash<qlonglong,int> messageIndexMap;
|
||||
QHash<qlonglong, QVariantList> albumMessageMap;
|
||||
QVariantMap chatInformation;
|
||||
qlonglong chatId;
|
||||
bool inReload;
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
#include "processlauncher.h"
|
||||
#include "stickermanager.h"
|
||||
#include "textfiltermodel.h"
|
||||
#include "boolfiltermodel.h"
|
||||
#include "tgsplugin.h"
|
||||
#include "fernschreiberutils.h"
|
||||
#include "knownusersmodel.h"
|
||||
|
@ -130,6 +131,7 @@ int main(int argc, char *argv[])
|
|||
qmlRegisterType<TDLibFile>(uri, 1, 0, "TDLibFile");
|
||||
qmlRegisterType<NamedAction>(uri, 1, 0, "NamedAction");
|
||||
qmlRegisterType<TextFilterModel>(uri, 1, 0, "TextFilterModel");
|
||||
qmlRegisterType<BoolFilterModel>(uri, 1, 0, "BoolFilterModel");
|
||||
qmlRegisterType<ChatPermissionFilterModel>(uri, 1, 0, "ChatPermissionFilterModel");
|
||||
qmlRegisterSingletonType<DebugLogJS>(uri, 1, 0, "DebugLog", DebugLogJS::createSingleton);
|
||||
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation>hat eine Videonachricht geschickt</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>%Ln Nachricht weiterleiten</numerusform>
|
||||
<numerusform>%Ln Nachrichten weiterleiten</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -905,6 +905,17 @@ messages</numerusform>
|
|||
<translation>sent a video note</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Forward %Ln message</numerusform>
|
||||
<numerusform>Forward %Ln messages</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation>envió nota de video</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Reenviar %Ln mensaje</numerusform>
|
||||
<numerusform>Reenviar %Ln mensajes</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -904,6 +904,17 @@
|
|||
<translation>lähetti videoviestin</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Välitä %Ln viesti</numerusform>
|
||||
<numerusform>Välitä %Ln viestiä</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation>a envoyé une note vidéo</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Transférer %Ln message</numerusform>
|
||||
<numerusform>Transférer %Ln messages</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -889,6 +889,16 @@
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation>ha inviato un videomessaggio</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Inoltra %Ln messaggio</numerusform>
|
||||
<numerusform>Inoltra %Ln messaggi</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -917,6 +917,18 @@
|
|||
<translation>wysłał notatkę video</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Przekaż %Ln wiadomość</numerusform>
|
||||
<numerusform>Przekaż %Ln wiadomości</numerusform>
|
||||
<numerusform>Przekaż %Ln wiadomości</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -920,6 +920,18 @@
|
|||
<translation>отправил(а) видео заметку</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Перенаправить %Ln сообщение</numerusform>
|
||||
<numerusform>Перенаправить %Ln сообщения</numerusform>
|
||||
<numerusform>Перенаправить %Ln сообщений</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -917,6 +917,18 @@
|
|||
<translation>poslal video-poznámku</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Postúpená %Ln správa</numerusform>
|
||||
<numerusform>Postúpené %Ln správy</numerusform>
|
||||
<numerusform>Postúpených %Ln správ</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation>skickade ett videomeddelande</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Vidarebefordra %Ln meddelande</numerusform>
|
||||
<numerusform>Vidarebefordra %Ln meddelanden</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -890,6 +890,16 @@
|
|||
<translation>发送视频消息</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation type="unfinished">
|
||||
<numerusform>转发 %Ln 则消息</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|
|
@ -903,6 +903,17 @@
|
|||
<translation type="unfinished">sent a video note</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>FullscreenOverlay</name>
|
||||
<message numerus="yes">
|
||||
<source>Forward %Ln messages</source>
|
||||
<comment>dialog header</comment>
|
||||
<translation>
|
||||
<numerusform>Forward %Ln message</numerusform>
|
||||
<numerusform>Forward %Ln messages</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ImagePage</name>
|
||||
<message>
|
||||
|
|