From d9991cce791eddadc0c6af2861b618fbf8336e03 Mon Sep 17 00:00:00 2001 From: Sebastian Wolf Date: Sun, 14 Feb 2021 21:57:48 +0100 Subject: [PATCH] Try something for the too large context menu --- qml/components/MessageListViewItem.qml | 22 +- qml/pages/ChatPage.qml | 2211 ++++++++++--------- rpm/harbour-fernschreiber.spec | 2 +- rpm/harbour-fernschreiber.yaml | 2 +- translations/harbour-fernschreiber-de.ts | 12 + translations/harbour-fernschreiber-en.ts | 12 + translations/harbour-fernschreiber-es.ts | 12 + translations/harbour-fernschreiber-fi.ts | 12 + translations/harbour-fernschreiber-hu.ts | 12 + translations/harbour-fernschreiber-it.ts | 12 + translations/harbour-fernschreiber-pl.ts | 12 + translations/harbour-fernschreiber-ru.ts | 12 + translations/harbour-fernschreiber-sk.ts | 12 + translations/harbour-fernschreiber-sv.ts | 12 + translations/harbour-fernschreiber-zh_CN.ts | 12 + translations/harbour-fernschreiber.ts | 12 + 16 files changed, 1314 insertions(+), 1067 deletions(-) diff --git a/qml/components/MessageListViewItem.qml b/qml/components/MessageListViewItem.qml index 203bf09..a2c4341 100644 --- a/qml/components/MessageListViewItem.qml +++ b/qml/components/MessageListViewItem.qml @@ -78,6 +78,13 @@ ListItem { chatView.manuallyScrolledToBottom = false; } + Connections { + target: messageOptionsDrawer + onCloseRequested: { + messageListItem.highlighted = false; + } + } + Loader { id: contextMenuLoader active: false @@ -110,18 +117,21 @@ ListItem { onClicked: messageListItem.editMessage() text: qsTr("Edit Message") } - MenuItem { - onClicked: { - Clipboard.text = Functions.getMessageText(myMessage, true, userInformation.id, true); - } - text: qsTr("Copy Message to Clipboard") - } MenuItem { onClicked: { page.toggleMessageSelection(myMessage); } text: qsTr("Select Message") } + MenuItem { + onClicked: { + messageOptionsDrawer.myMessage = myMessage; + messageOptionsDrawer.userInformation = userInformation; + messageListItem.highlighted = true; + messageOptionsDrawer.open = true; + } + text: qsTr("More Options...") + } MenuItem { onClicked: { if (myMessage.is_pinned) { diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index 6922ab7..477d0e2 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -681,1081 +681,1213 @@ Page { } } - SilicaFlickable { - id: chatContainer + Drawer { + id: messageOptionsDrawer - onContentYChanged: { - // For some strange reason contentY sometimes is > 0 which doesn't make sense without a PushUpMenu (?) - // That leads to the problem that the whole flickable is moved slightly (or sometimes considerably) up - // which creates UX issues... As a workaround we are setting it to 0 in such cases. - // Better solutions are highly appreciated, contributions always welcome! ;) - if (contentY > 0) { - contentY = 0; - } - } + property var myMessage: ({}) + property var userInformation: ({}) + + signal closeRequested(); anchors.fill: parent - contentHeight: height - contentWidth: width + dock: chatPage.isPortrait ? Dock.Top : Dock.Right - PullDownMenu { - visible: chatInformation.id !== chatPage.myUserId && !stickerPickerLoader.active && !voiceNoteOverlayLoader.active && !messageOverlayLoader.active && !stickerSetOverlayLoader.active - MenuItem { - id: closeSecretChatMenuItem - visible: chatPage.isSecretChat && chatPage.secretChatDetails.state["@type"] !== "secretChatStateClosed" - onClicked: { - var secretChatId = chatPage.secretChatDetails.id; - Remorse.popupAction(chatPage, qsTr("Closing chat"), function() { tdLibWrapper.closeSecretChat(secretChatId) }); - } - text: qsTr("Close Chat") - } - - MenuItem { - id: joinLeaveChatMenuItem - visible: (chatPage.isSuperGroup || chatPage.isBasicGroup) && chatGroupInformation && chatGroupInformation.status["@type"] !== "chatMemberStatusBanned" - onClicked: { - if (chatPage.userIsMember) { - var chatId = chatInformation.id; - Remorse.popupAction(chatPage, qsTr("Leaving chat"), function() { - tdLibWrapper.leaveChat(chatId); - // this does not care about the response (ideally type "ok" without further reference) for now - pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} )); - }); - } else { - tdLibWrapper.joinChat(chatInformation.id); + background: SilicaListView { + anchors.fill: parent + model: ListModel { + id: myListModel + property var actions: { + "copyToClipboard": function() { Clipboard.text = Functions.getMessageText(messageOptionsDrawer.myMessage, true, messageOptionsDrawer.userInformation.id, true) }, + "pinMessage": function() { + if (messageOptionsDrawer.myMessage.is_pinned) { + Remorse.popupAction(page, qsTr("Message unpinned"), function() { tdLibWrapper.unpinMessage(chatPage.chatInformation.id, messageOptionsDrawer.myMessage.id); + pinnedMessageItem.requestCloseMessage(); } ); + } else { + tdLibWrapper.pinMessage(chatPage.chatInformation.id, messageOptionsDrawer.myMessage.id); + } } } - text: chatPage.userIsMember ? qsTr("Leave Chat") : qsTr("Join Chat") - } - - MenuItem { - id: muteChatMenuItem - visible: chatPage.userIsMember - onClicked: { - var newNotificationSettings = chatInformation.notification_settings; - if (newNotificationSettings.mute_for > 0) { - newNotificationSettings.mute_for = 0; - } else { - newNotificationSettings.mute_for = 6666666; - } - newNotificationSettings.use_default_mute_for = false; - tdLibWrapper.setChatNotificationSettings(chatInformation.id, newNotificationSettings); + property var conditions: { + "copyToClipboard": function() { return true; }, + "pinMessage": function() { return canPinMessages(); } } - text: chatInformation.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat") - } - MenuItem { - id: searchInChatMenuItem - visible: !chatPage.isSecretChat && chatOverviewItem.visible - onClicked: { - // This automatically shows the search field as well - chatOverviewItem.visible = false; - searchInChatField.focus = true; + property var texts: { + "copyToClipboard": function() { return qsTr("Copy Message to Clipboard"); }, + "pinMessage": function() { return messageOptionsDrawer.myMessage.is_pinned ? qsTr("Unpin Message") : qsTr("Pin Message"); } } - text: qsTr("Search in Chat") - } - } - BackgroundItem { - id: headerMouseArea - height: headerRow.height - width: parent.width - onClicked: { - if (chatPage.isSelecting) { - chatPage.selectedMessages = []; - } else { - pageStack.navigateForward(); + ListElement { + elementActionName: "copyToClipboard" + } + + ListElement { + elementActionName: "pinMessage" } } - } - Column { - id: chatColumn - width: parent.width - height: parent.height - - Row { - id: headerRow - width: parent.width - (3 * Theme.horizontalPageMargin) - height: chatOverviewItem.height + ( chatPage.isPortrait ? (2 * Theme.paddingMedium) : (2 * Theme.paddingSmall) ) + header: Row { + width: parent.width - ( 4 * Theme.horizontalPageMargin) + height: messageOptionsLabel.height + Theme.paddingLarge + ( chatPage.isPortrait ? ( 2 * Theme.paddingSmall ) : 0 ) anchors.horizontalCenter: parent.horizontalCenter spacing: Theme.paddingMedium - - Item { - width: chatOverviewItem.height - height: chatOverviewItem.height - anchors.bottom: parent.bottom - anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall - - ProfileThumbnail { - id: chatPictureThumbnail - replacementStringHint: chatNameText.text - width: parent.height - height: parent.height - - // Setting it directly may cause an stale state for the thumbnail in case the chat page - // was previously loaded with a picture and now it doesn't have one. Instead setting it - // when the ChatModel indicates a change. This also avoids flickering when the page is loaded... - Connections { - target: chatModel - onSmallPhotoChanged: { - chatPictureThumbnail.photoData = chatModel.smallPhoto; - } - } - } - - Rectangle { - id: chatSecretBackground - color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityFaint) - width: chatPage.isPortrait ? Theme.fontSizeLarge : Theme.fontSizeMedium - height: width - anchors.left: parent.left - anchors.bottom: parent.bottom - radius: parent.width / 2 - visible: chatPage.isSecretChat - } - - Image { - source: "image://theme/icon-s-secure" - width: chatPage.isPortrait ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall - height: width - anchors.centerIn: chatSecretBackground - visible: chatPage.isSecretChat - } - - } - - Item { - id: chatOverviewItem - opacity: visible ? 1 : 0 - Behavior on opacity { FadeAnimation {} } - width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium - height: chatNameText.height + chatStatusText.height - anchors.bottom: parent.bottom - anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall - Label { - id: chatNameText - width: Math.min(implicitWidth, parent.width) - anchors.right: parent.right - text: chatInformation.title !== "" ? Emoji.emojify(chatInformation.title, font.pixelSize) : qsTr("Unknown") - textFormat: Text.StyledText - font.pixelSize: chatPage.isPortrait ? Theme.fontSizeLarge : Theme.fontSizeMedium - font.family: Theme.fontFamilyHeading - color: Theme.highlightColor - truncationMode: TruncationMode.Fade - maximumLineCount: 1 - } - Label { - id: chatStatusText - width: Math.min(implicitWidth, parent.width) - anchors { - right: parent.right - bottom: parent.bottom - } - text: "" - textFormat: Text.StyledText - font.pixelSize: chatPage.isPortrait ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny - font.family: Theme.fontFamilyHeading - color: headerMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor - truncationMode: TruncationMode.Fade - maximumLineCount: 1 - } - } - - Item { - id: searchInChatItem - visible: !chatOverviewItem.visible - opacity: visible ? 1 : 0 - Behavior on opacity { FadeAnimation {} } - width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium - height: searchInChatField.height - anchors.bottom: parent.bottom - anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingSmall : 0 - - SearchField { - id: searchInChatField - visible: false - width: visible ? parent.width : 0 - placeholderText: qsTr("Search in chat...") - active: searchInChatItem.visible - canHide: text === "" - - onTextChanged: { - searchInChatTimer.restart(); - } - - onHideClicked: { - resetFocus(); - } - - EnterKey.iconSource: "image://theme/icon-m-enter-close" - EnterKey.onClicked: { - resetFocus(); - } - } - } - } - - PinnedMessageItem { - id: pinnedMessageItem - onRequestShowMessage: { - messageOverlayLoader.overlayMessage = pinnedMessageItem.pinnedMessage; - messageOverlayLoader.active = true; - } - onRequestCloseMessage: { - messageOverlayLoader.overlayMessage = undefined; - messageOverlayLoader.active = false; - } - } - - Item { - id: chatViewItem - width: parent.width - height: parent.height - headerRow.height - pinnedMessageItem.height - newMessageColumn.height - selectedMessagesActions.height - - property int previousHeight; - - Component.onCompleted: { - previousHeight = height; - } - - onHeightChanged: { - var deltaHeight = previousHeight - height; - chatView.contentY = chatView.contentY + deltaHeight; - previousHeight = height; - } - - Timer { - id: chatViewCooldownTimer - interval: 2000 - repeat: false - running: false - onTriggered: { - Debug.log("[ChatPage] Cooldown completed..."); - chatView.inCooldown = false; - - if (!chatPage.isInitialized) { - Debug.log("Page is initialized!"); - chatPage.isInitialized = true; - chatView.handleScrollPositionChanged(); - } - } - } - - Loader { - asynchronous: true - active: chatView.blurred - anchors.fill: chatView - sourceComponent: Component { - FastBlur { - source: chatView - radius: Theme.paddingLarge - } - } - } - - SilicaListView { - id: chatView - - visible: !blurred - property bool blurred: messageOverlayLoader.item || stickerPickerLoader.item || voiceNoteOverlayLoader.item || inlineQuery.hasOverlay || stickerSetOverlayLoader.item - - anchors.fill: parent - opacity: chatPage.loading ? 0 : 1 - Behavior on opacity { FadeAnimation {} } - clip: true - highlightMoveDuration: 0 - highlightResizeDuration: 0 - property int lastReadSentIndex: -1 - property bool inCooldown: false - property bool manuallyScrolledToBottom - property QtObject precalculatedValues: QtObject { - readonly property alias page: chatPage - readonly property bool showUserInfo: page.isBasicGroup || ( page.isSuperGroup && !page.isChannel) - readonly property int profileThumbnailDimensions: showUserInfo ? Theme.itemSizeSmall : 0 - readonly property int pageMarginDouble: 2 * Theme.horizontalPageMargin - readonly property int paddingMediumDouble: 2 * Theme.paddingMedium - readonly property int entryWidth: chatView.width - pageMarginDouble - readonly property int textItemWidth: entryWidth - profileThumbnailDimensions - Theme.paddingSmall - readonly property int backgroundWidth: page.isChannel ? textItemWidth : textItemWidth - pageMarginDouble - readonly property int backgroundRadius: textItemWidth/50 - readonly property int textColumnWidth: backgroundWidth - Theme.horizontalPageMargin - 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() { - Debug.log("Current position: ", chatView.contentY); - if (chatOverviewItem.visible && chatInformation.unread_count > 0) { - var bottomIndex = chatView.indexAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin )); - if (bottomIndex > -1) { - viewMessageTimer.queueViewMessage(bottomIndex) - } - } else { - tdLibWrapper.readAllChatMentions(chatInformation.id); - } - manuallyScrolledToBottom = chatView.atYEnd - } - - function scrollToIndex(index) { - if(index > 0 && index < chatView.count) { - positionViewAtIndex(index, ListView.Contain) -// currentIndex = index; - if(index === chatView.count - 1) { - manuallyScrolledToBottom = true; - } - } - } - - onContentYChanged: { - if (!chatPage.loading && !chatView.inCooldown) { - if (chatView.indexAt(chatView.contentX, chatView.contentY) < 10) { - Debug.log("[ChatPage] Trying to get older history items..."); - chatView.inCooldown = true; - chatModel.triggerLoadMoreHistory(); - } else if (chatOverviewItem.visible && chatView.indexAt(chatView.contentX, chatView.contentY) > ( count - 10)) { - Debug.log("[ChatPage] Trying to get newer history items..."); - chatView.inCooldown = true; - chatModel.triggerLoadMoreFuture(); - } - } - } - - onMovementEnded: { - handleScrollPositionChanged(); - } - - onQuickScrollAnimatingChanged: { - if (!quickScrollAnimating) { - handleScrollPositionChanged(); - if(atYEnd) { // handle some false guesses from quick scroll - chatView.scrollToIndex(chatView.count - 2) - chatView.scrollToIndex(chatView.count - 1) - } - } - } - - model: chatModel - header: Component { - Loader { - active: !!chatPage.botInformation - && !!chatPage.botInformation.bot_info && chatPage.botInformation.bot_info.description.length > 0 - asynchronous: true - width: chatView.width - sourceComponent: Component { - Label { - id: botInfoLabel - topPadding: Theme.paddingLarge - bottomPadding: Theme.paddingLarge - leftPadding: Theme.horizontalPageMargin - rightPadding: Theme.horizontalPageMargin - text: Emoji.emojify(chatPage.botInformation.bot_info.description, font.pixelSize) - font.pixelSize: Theme.fontSizeSmall - color: Theme.highlightColor - wrapMode: Text.Wrap - textFormat: Text.StyledText - horizontalAlignment: Text.AlignHCenter - onLinkActivated: { - var chatCommand = Functions.handleLink(link); - if(chatCommand) { - tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand); - } - } - linkColor: Theme.primaryColor - visible: (text !== "") - } - } - } - } - - function getContentComponentHeight(contentType, content, parentWidth) { - switch(contentType) { - case "messageAnimation": - return Functions.getVideoHeight(parentWidth, content.animation); - case "messageAudio": - case "messageVoiceNote": - case "messageDocument": - return Theme.itemSizeLarge; - case "messageGame": - return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3; - case "messageLocation": - case "messageVenue": - return parentWidth * 0.66666666; // 2 / 3; - case "messagePhoto": - var biggest = content.photo.sizes[content.photo.sizes.length - 1]; - var aspectRatio = biggest.width/biggest.height; - return Math.max(Theme.itemSizeExtraSmall, Math.min(parentWidth * 0.66666666, parentWidth / aspectRatio)); - case "messagePoll": - return Theme.itemSizeSmall * (4 + content.poll.options); - case "messageSticker": - return content.sticker.height; - case "messageVideo": - return Functions.getVideoHeight(parentWidth, content.video); - case "messageVideoNote": - return parentWidth - } - } - - readonly property var delegateMessagesContent: [ - "messageAnimation", - "messageAudio", - // "messageContact", - // "messageDice" - "messageDocument", - "messageGame", - // "messageInvoice", - "messageLocation", - // "messagePassportDataSent", - // "messagePaymentSuccessful", - "messagePhoto", - "messagePoll", - // "messageProximityAlertTriggered", - "messageSticker", - "messageVenue", - "messageVideo", - "messageVideoNote", - "messageVoiceNote" - ] - - readonly property var simpleDelegateMessages: ["messageBasicGroupChatCreate", - "messageChatAddMembers", - "messageChatChangePhoto", - "messageChatChangeTitle", - "messageChatDeleteMember", - "messageChatDeletePhoto", - "messageChatJoinByLink", - "messageChatSetTtl", - "messageChatUpgradeFrom", - // "messageContactRegistered","messageExpiredPhoto", "messageExpiredVideo","messageWebsiteConnected" - "messageGameScore", - "messageChatUpgradeTo", - "messageCustomServiceAction", - "messagePinMessage", - "messageScreenshotTaken", - "messageSupergroupChatCreate", - "messageUnsupported"] - delegate: Loader { - width: chatView.width - Component { - id: messageListViewItemComponent - MessageListViewItem { - precalculatedValues: chatView.precalculatedValues - chatId: chatModel.chatId - myMessage: model.display - messageId: model.message_id - messageViewCount: model.view_count - messageIndex: model.index - hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1 - canReplyToMessage: chatPage.canSendMessages - onReplyToMessage: { - newMessageInReplyToRow.inReplyToMessage = myMessage - newMessageTextField.focus = true - } - onEditMessage: { - newMessageColumn.editMessageId = messageId - newMessageTextField.text = Functions.getMessageText(myMessage, false, chatPage.myUserId, true) - newMessageTextField.focus = true - } - } - } - Component { - id: messageListViewItemSimpleComponent - MessageListViewItemSimple {} - } - sourceComponent: chatView.simpleDelegateMessages.indexOf(model.content_type) > -1 ? messageListViewItemSimpleComponent : messageListViewItemComponent - } - VerticalScrollDecorator {} - - ViewPlaceholder { - id: chatViewPlaceholder - enabled: chatView.count === 0 - text: (chatPage.isSecretChat && !chatPage.isSecretChatReady) ? qsTr("This secret chat is not yet ready. Your chat partner needs to go online first.") : qsTr("This chat is empty.") - } - } - - Column { - width: parent.width - height: loadingLabel.height + loadingBusyIndicator.height + Theme.paddingMedium - spacing: Theme.paddingMedium + Label { + id: messageOptionsLabel + text: qsTr("Message Options") + color: Theme.highlightColor + font.pixelSize: Theme.fontSizeLarge + width: parent.width - closeMessageOptionsButton.width - Theme.paddingMedium anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight - opacity: chatPage.loading ? 1 : 0 - Behavior on opacity { FadeAnimation {} } - visible: chatPage.loading - - InfoLabel { - id: loadingLabel - text: qsTr("Loading messages...") - } - - BusyIndicator { - id: loadingBusyIndicator - anchors.horizontalCenter: parent.horizontalCenter - running: chatPage.loading - size: BusyIndicatorSize.Large + } + IconButton { + id: closeMessageOptionsButton + icon.source: "image://theme/icon-m-clear" + anchors.verticalCenter: parent.verticalCenter + onClicked: { + messageOptionsDrawer.closeRequested(); + messageOptionsDrawer.open = false; } } + } - Item { - id: chatUnreadMessagesItem - width: Theme.fontSizeHuge - height: Theme.fontSizeHuge - anchors.right: parent.right - anchors.rightMargin: Theme.paddingMedium - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.paddingMedium - visible: !chatPage.loading && chatInformation.unread_count > 0 && chatOverviewItem.visible - Rectangle { - id: chatUnreadMessagesCountBackground - color: Theme.highlightBackgroundColor - anchors.fill: parent - radius: width / 2 - visible: chatUnreadMessagesItem.visible - } + delegate: ListItem { + width: parent.width + visible: myListModel.actions[conditions]() + onClicked: { + myListModel.actions[elementActionName](); + } + Label { + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + text: myListModel.texts[elementActionName](); + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + horizontalAlignment: Text.AlignHCenter + } + } - Text { - id: chatUnreadMessagesCount - font.pixelSize: Theme.fontSizeMedium - font.bold: true - color: Theme.primaryColor - anchors.centerIn: chatUnreadMessagesCountBackground - visible: chatUnreadMessagesItem.visible - text: chatInformation.unread_count > 99 ? "99+" : chatInformation.unread_count + VerticalScrollDecorator {} + } + + SilicaFlickable { + id: chatContainer + + onContentYChanged: { + // For some strange reason contentY sometimes is > 0 which doesn't make sense without a PushUpMenu (?) + // That leads to the problem that the whole flickable is moved slightly (or sometimes considerably) up + // which creates UX issues... As a workaround we are setting it to 0 in such cases. + // Better solutions are highly appreciated, contributions always welcome! ;) + if (contentY > 0) { + contentY = 0; + } + } + + anchors.fill: parent + contentHeight: height + contentWidth: width + + PullDownMenu { + visible: chatInformation.id !== chatPage.myUserId && !stickerPickerLoader.active && !voiceNoteOverlayLoader.active && !messageOverlayLoader.active && !stickerSetOverlayLoader.active + MenuItem { + id: closeSecretChatMenuItem + visible: chatPage.isSecretChat && chatPage.secretChatDetails.state["@type"] !== "secretChatStateClosed" + onClicked: { + var secretChatId = chatPage.secretChatDetails.id; + Remorse.popupAction(chatPage, qsTr("Closing chat"), function() { tdLibWrapper.closeSecretChat(secretChatId) }); } - MouseArea { - anchors.fill: parent - onClicked: { - chatView.scrollToIndex(chatView.count - 1 - chatInformation.unread_count) + text: qsTr("Close Chat") + } + + MenuItem { + id: joinLeaveChatMenuItem + visible: (chatPage.isSuperGroup || chatPage.isBasicGroup) && chatGroupInformation && chatGroupInformation.status["@type"] !== "chatMemberStatusBanned" + onClicked: { + if (chatPage.userIsMember) { + var chatId = chatInformation.id; + Remorse.popupAction(chatPage, qsTr("Leaving chat"), function() { + tdLibWrapper.leaveChat(chatId); + // this does not care about the response (ideally type "ok" without further reference) for now + pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} )); + }); + } else { + tdLibWrapper.joinChat(chatInformation.id); } } + text: chatPage.userIsMember ? qsTr("Leave Chat") : qsTr("Join Chat") } - Loader { - id: stickerPickerLoader - active: false - asynchronous: true - width: parent.width - height: active ? parent.height : 0 - source: "../components/StickerPicker.qml" - } - - Connections { - target: stickerPickerLoader.item - onStickerPicked: { - Debug.log("Sticker picked: " + stickerId); - tdLibWrapper.sendStickerMessage(chatInformation.id, stickerId, newMessageColumn.replyToMessageId); - stickerPickerLoader.active = false; - attachmentOptionsFlickable.isNeeded = false; - newMessageInReplyToRow.inReplyToMessage = null; - newMessageColumn.editMessageId = "0"; - } - } - - Loader { - id: messageOverlayLoader - - property var overlayMessage; - - active: false - asynchronous: true - width: parent.width - height: active ? parent.height : 0 - sourceComponent: Component { - MessageOverlayFlickable { - overlayMessage: messageOverlayLoader.overlayMessage - showHeader: !chatPage.isChannel - onRequestClose: { - messageOverlayLoader.active = false; - } + MenuItem { + id: muteChatMenuItem + visible: chatPage.userIsMember + onClicked: { + var newNotificationSettings = chatInformation.notification_settings; + if (newNotificationSettings.mute_for > 0) { + newNotificationSettings.mute_for = 0; + } else { + newNotificationSettings.mute_for = 6666666; } + newNotificationSettings.use_default_mute_for = false; + tdLibWrapper.setChatNotificationSettings(chatInformation.id, newNotificationSettings); } + text: chatInformation.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat") } - Loader { - id: voiceNoteOverlayLoader - active: false - asynchronous: true - width: parent.width - height: active ? parent.height : 0 - source: "../components/VoiceNoteOverlay.qml" - onActiveChanged: { - if (!active) { - fernschreiberUtils.stopRecordingVoiceNote(); - } + MenuItem { + id: searchInChatMenuItem + visible: !chatPage.isSecretChat && chatOverviewItem.visible + onClicked: { + // This automatically shows the search field as well + chatOverviewItem.visible = false; + searchInChatField.focus = true; } + text: qsTr("Search in Chat") } + } - Loader { - id: stickerSetOverlayLoader - - property string stickerSetId; - - active: false - asynchronous: true - width: parent.width - height: active ? parent.height : 0 - sourceComponent: Component { - StickerSetOverlay { - stickerSetId: stickerSetOverlayLoader.stickerSetId - onRequestClose: { - stickerSetOverlayLoader.active = false; - } - } + BackgroundItem { + id: headerMouseArea + height: headerRow.height + width: parent.width + onClicked: { + if (chatPage.isSelecting) { + chatPage.selectedMessages = []; + } else { + pageStack.navigateForward(); } - - onActiveChanged: { - if (active) { - attachmentOptionsFlickable.isNeeded = false; - } - } - } - - InlineQuery { - id: inlineQuery - textField: newMessageTextField - chatId: chatInformation.id } } Column { - id: newMessageColumn - spacing: Theme.paddingSmall - topPadding: Theme.paddingSmall + inlineQuery.buttonPadding - anchors.horizontalCenter: parent.horizontalCenter - visible: height > 0 - width: parent.width - ( 2 * Theme.horizontalPageMargin ) - height: isNeeded ? implicitHeight : 0 - Behavior on height { SmoothedAnimation { duration: 200 } } + id: chatColumn + width: parent.width + height: parent.height - readonly property bool isNeeded: !chatPage.isSelecting && chatPage.canSendMessages - property string replyToMessageId: "0"; - property string editMessageId: "0"; + Row { + id: headerRow + width: parent.width - (3 * Theme.horizontalPageMargin) + height: chatOverviewItem.height + ( chatPage.isPortrait ? (2 * Theme.paddingMedium) : (2 * Theme.paddingSmall) ) + anchors.horizontalCenter: parent.horizontalCenter + spacing: Theme.paddingMedium - InReplyToRow { - onInReplyToMessageChanged: { - if (inReplyToMessage) { - newMessageColumn.replyToMessageId = newMessageInReplyToRow.inReplyToMessage.id.toString() - newMessageInReplyToRow.visible = true; - } else { - newMessageInReplyToRow.visible = false; - newMessageColumn.replyToMessageId = "0"; + Item { + width: chatOverviewItem.height + height: chatOverviewItem.height + anchors.bottom: parent.bottom + anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall + + ProfileThumbnail { + id: chatPictureThumbnail + replacementStringHint: chatNameText.text + width: parent.height + height: parent.height + + // Setting it directly may cause an stale state for the thumbnail in case the chat page + // was previously loaded with a picture and now it doesn't have one. Instead setting it + // when the ChatModel indicates a change. This also avoids flickering when the page is loaded... + Connections { + target: chatModel + onSmallPhotoChanged: { + chatPictureThumbnail.photoData = chatModel.smallPhoto; + } + } + } + + Rectangle { + id: chatSecretBackground + color: Theme.rgba(Theme.overlayBackgroundColor, Theme.opacityFaint) + width: chatPage.isPortrait ? Theme.fontSizeLarge : Theme.fontSizeMedium + height: width + anchors.left: parent.left + anchors.bottom: parent.bottom + radius: parent.width / 2 + visible: chatPage.isSecretChat + } + + Image { + source: "image://theme/icon-s-secure" + width: chatPage.isPortrait ? Theme.fontSizeSmall : Theme.fontSizeExtraSmall + height: width + anchors.centerIn: chatSecretBackground + visible: chatPage.isSecretChat + } + + } + + Item { + id: chatOverviewItem + opacity: visible ? 1 : 0 + Behavior on opacity { FadeAnimation {} } + width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium + height: chatNameText.height + chatStatusText.height + anchors.bottom: parent.bottom + anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingMedium : Theme.paddingSmall + Label { + id: chatNameText + width: Math.min(implicitWidth, parent.width) + anchors.right: parent.right + text: chatInformation.title !== "" ? Emoji.emojify(chatInformation.title, font.pixelSize) : qsTr("Unknown") + textFormat: Text.StyledText + font.pixelSize: chatPage.isPortrait ? Theme.fontSizeLarge : Theme.fontSizeMedium + font.family: Theme.fontFamilyHeading + color: Theme.highlightColor + truncationMode: TruncationMode.Fade + maximumLineCount: 1 + } + Label { + id: chatStatusText + width: Math.min(implicitWidth, parent.width) + anchors { + right: parent.right + bottom: parent.bottom + } + text: "" + textFormat: Text.StyledText + font.pixelSize: chatPage.isPortrait ? Theme.fontSizeExtraSmall : Theme.fontSizeTiny + font.family: Theme.fontFamilyHeading + color: headerMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor + truncationMode: TruncationMode.Fade + maximumLineCount: 1 } } - editable: true + Item { + id: searchInChatItem + visible: !chatOverviewItem.visible + opacity: visible ? 1 : 0 + Behavior on opacity { FadeAnimation {} } + width: parent.width - chatPictureThumbnail.width - Theme.paddingMedium + height: searchInChatField.height + anchors.bottom: parent.bottom + anchors.bottomMargin: chatPage.isPortrait ? Theme.paddingSmall : 0 - onClearRequested: { - newMessageInReplyToRow.inReplyToMessage = null; + SearchField { + id: searchInChatField + visible: false + width: visible ? parent.width : 0 + placeholderText: qsTr("Search in chat...") + active: searchInChatItem.visible + canHide: text === "" + + onTextChanged: { + searchInChatTimer.restart(); + } + + onHideClicked: { + resetFocus(); + } + + EnterKey.iconSource: "image://theme/icon-m-enter-close" + EnterKey.onClicked: { + resetFocus(); + } + } } - - id: newMessageInReplyToRow - myUserId: chatPage.myUserId - visible: false } - Flickable { - id: attachmentOptionsFlickable + PinnedMessageItem { + id: pinnedMessageItem + onRequestShowMessage: { + messageOverlayLoader.overlayMessage = pinnedMessageItem.pinnedMessage; + messageOverlayLoader.active = true; + } + onRequestCloseMessage: { + messageOverlayLoader.overlayMessage = undefined; + messageOverlayLoader.active = false; + } + } - property bool isNeeded: false - width: chatPage.width - x: -Theme.horizontalPageMargin - height: isNeeded && !inlineQuery.userNameIsValid ? attachmentOptionsRow.height : 0 - Behavior on height { SmoothedAnimation { duration: 200 } } + Item { + id: chatViewItem + width: parent.width + height: parent.height - headerRow.height - pinnedMessageItem.height - newMessageColumn.height - selectedMessagesActions.height + + property int previousHeight; + + Component.onCompleted: { + previousHeight = height; + } + + onHeightChanged: { + var deltaHeight = previousHeight - height; + chatView.contentY = chatView.contentY + deltaHeight; + previousHeight = height; + } + + Timer { + id: chatViewCooldownTimer + interval: 2000 + repeat: false + running: false + onTriggered: { + Debug.log("[ChatPage] Cooldown completed..."); + chatView.inCooldown = false; + + if (!chatPage.isInitialized) { + Debug.log("Page is initialized!"); + chatPage.isInitialized = true; + chatView.handleScrollPositionChanged(); + } + } + } + + Loader { + asynchronous: true + active: chatView.blurred + anchors.fill: chatView + sourceComponent: Component { + FastBlur { + source: chatView + radius: Theme.paddingLarge + } + } + } + + SilicaListView { + id: chatView + + visible: !blurred + property bool blurred: messageOverlayLoader.item || stickerPickerLoader.item || voiceNoteOverlayLoader.item || inlineQuery.hasOverlay || stickerSetOverlayLoader.item + + anchors.fill: parent + opacity: chatPage.loading ? 0 : 1 + Behavior on opacity { FadeAnimation {} } + clip: true + highlightMoveDuration: 0 + highlightResizeDuration: 0 + property int lastReadSentIndex: -1 + property bool inCooldown: false + property bool manuallyScrolledToBottom + property QtObject precalculatedValues: QtObject { + readonly property alias page: chatPage + readonly property bool showUserInfo: page.isBasicGroup || ( page.isSuperGroup && !page.isChannel) + readonly property int profileThumbnailDimensions: showUserInfo ? Theme.itemSizeSmall : 0 + readonly property int pageMarginDouble: 2 * Theme.horizontalPageMargin + readonly property int paddingMediumDouble: 2 * Theme.paddingMedium + readonly property int entryWidth: chatView.width - pageMarginDouble + readonly property int textItemWidth: entryWidth - profileThumbnailDimensions - Theme.paddingSmall + readonly property int backgroundWidth: page.isChannel ? textItemWidth : textItemWidth - pageMarginDouble + readonly property int backgroundRadius: textItemWidth/50 + readonly property int textColumnWidth: backgroundWidth - Theme.horizontalPageMargin + 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() { + Debug.log("Current position: ", chatView.contentY); + if (chatOverviewItem.visible && chatInformation.unread_count > 0) { + var bottomIndex = chatView.indexAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin )); + if (bottomIndex > -1) { + viewMessageTimer.queueViewMessage(bottomIndex) + } + } else { + tdLibWrapper.readAllChatMentions(chatInformation.id); + } + manuallyScrolledToBottom = chatView.atYEnd + } + + function scrollToIndex(index) { + if(index > 0 && index < chatView.count) { + positionViewAtIndex(index, ListView.Contain) + // currentIndex = index; + if(index === chatView.count - 1) { + manuallyScrolledToBottom = true; + } + } + } + + onContentYChanged: { + if (!chatPage.loading && !chatView.inCooldown) { + if (chatView.indexAt(chatView.contentX, chatView.contentY) < 10) { + Debug.log("[ChatPage] Trying to get older history items..."); + chatView.inCooldown = true; + chatModel.triggerLoadMoreHistory(); + } else if (chatOverviewItem.visible && chatView.indexAt(chatView.contentX, chatView.contentY) > ( count - 10)) { + Debug.log("[ChatPage] Trying to get newer history items..."); + chatView.inCooldown = true; + chatModel.triggerLoadMoreFuture(); + } + } + } + + onMovementEnded: { + handleScrollPositionChanged(); + } + + onQuickScrollAnimatingChanged: { + if (!quickScrollAnimating) { + handleScrollPositionChanged(); + if(atYEnd) { // handle some false guesses from quick scroll + chatView.scrollToIndex(chatView.count - 2) + chatView.scrollToIndex(chatView.count - 1) + } + } + } + + model: chatModel + header: Component { + Loader { + active: !!chatPage.botInformation + && !!chatPage.botInformation.bot_info && chatPage.botInformation.bot_info.description.length > 0 + asynchronous: true + width: chatView.width + sourceComponent: Component { + Label { + id: botInfoLabel + topPadding: Theme.paddingLarge + bottomPadding: Theme.paddingLarge + leftPadding: Theme.horizontalPageMargin + rightPadding: Theme.horizontalPageMargin + text: Emoji.emojify(chatPage.botInformation.bot_info.description, font.pixelSize) + font.pixelSize: Theme.fontSizeSmall + color: Theme.highlightColor + wrapMode: Text.Wrap + textFormat: Text.StyledText + horizontalAlignment: Text.AlignHCenter + onLinkActivated: { + var chatCommand = Functions.handleLink(link); + if(chatCommand) { + tdLibWrapper.sendTextMessage(chatInformation.id, chatCommand); + } + } + linkColor: Theme.primaryColor + visible: (text !== "") + } + } + } + } + + function getContentComponentHeight(contentType, content, parentWidth) { + switch(contentType) { + case "messageAnimation": + return Functions.getVideoHeight(parentWidth, content.animation); + case "messageAudio": + case "messageVoiceNote": + case "messageDocument": + return Theme.itemSizeLarge; + case "messageGame": + return parentWidth * 0.66666666 + Theme.itemSizeLarge; // 2 / 3; + case "messageLocation": + case "messageVenue": + return parentWidth * 0.66666666; // 2 / 3; + case "messagePhoto": + var biggest = content.photo.sizes[content.photo.sizes.length - 1]; + var aspectRatio = biggest.width/biggest.height; + return Math.max(Theme.itemSizeExtraSmall, Math.min(parentWidth * 0.66666666, parentWidth / aspectRatio)); + case "messagePoll": + return Theme.itemSizeSmall * (4 + content.poll.options); + case "messageSticker": + return content.sticker.height; + case "messageVideo": + return Functions.getVideoHeight(parentWidth, content.video); + case "messageVideoNote": + return parentWidth + } + } + + readonly property var delegateMessagesContent: [ + "messageAnimation", + "messageAudio", + // "messageContact", + // "messageDice" + "messageDocument", + "messageGame", + // "messageInvoice", + "messageLocation", + // "messagePassportDataSent", + // "messagePaymentSuccessful", + "messagePhoto", + "messagePoll", + // "messageProximityAlertTriggered", + "messageSticker", + "messageVenue", + "messageVideo", + "messageVideoNote", + "messageVoiceNote" + ] + + readonly property var simpleDelegateMessages: ["messageBasicGroupChatCreate", + "messageChatAddMembers", + "messageChatChangePhoto", + "messageChatChangeTitle", + "messageChatDeleteMember", + "messageChatDeletePhoto", + "messageChatJoinByLink", + "messageChatSetTtl", + "messageChatUpgradeFrom", + // "messageContactRegistered","messageExpiredPhoto", "messageExpiredVideo","messageWebsiteConnected" + "messageGameScore", + "messageChatUpgradeTo", + "messageCustomServiceAction", + "messagePinMessage", + "messageScreenshotTaken", + "messageSupergroupChatCreate", + "messageUnsupported"] + delegate: Loader { + width: chatView.width + Component { + id: messageListViewItemComponent + MessageListViewItem { + precalculatedValues: chatView.precalculatedValues + chatId: chatModel.chatId + myMessage: model.display + messageId: model.message_id + messageViewCount: model.view_count + messageIndex: model.index + hasContentComponent: !!myMessage.content && chatView.delegateMessagesContent.indexOf(model.content_type) > -1 + canReplyToMessage: chatPage.canSendMessages + onReplyToMessage: { + newMessageInReplyToRow.inReplyToMessage = myMessage + newMessageTextField.focus = true + } + onEditMessage: { + newMessageColumn.editMessageId = messageId + newMessageTextField.text = Functions.getMessageText(myMessage, false, chatPage.myUserId, true) + newMessageTextField.focus = true + } + } + } + Component { + id: messageListViewItemSimpleComponent + MessageListViewItemSimple {} + } + sourceComponent: chatView.simpleDelegateMessages.indexOf(model.content_type) > -1 ? messageListViewItemSimpleComponent : messageListViewItemComponent + } + VerticalScrollDecorator {} + + ViewPlaceholder { + id: chatViewPlaceholder + enabled: chatView.count === 0 + text: (chatPage.isSecretChat && !chatPage.isSecretChatReady) ? qsTr("This secret chat is not yet ready. Your chat partner needs to go online first.") : qsTr("This chat is empty.") + } + } + + Column { + width: parent.width + height: loadingLabel.height + loadingBusyIndicator.height + Theme.paddingMedium + spacing: Theme.paddingMedium + anchors.verticalCenter: parent.verticalCenter + + opacity: chatPage.loading ? 1 : 0 + Behavior on opacity { FadeAnimation {} } + visible: chatPage.loading + + InfoLabel { + id: loadingLabel + text: qsTr("Loading messages...") + } + + BusyIndicator { + id: loadingBusyIndicator + anchors.horizontalCenter: parent.horizontalCenter + running: chatPage.loading + size: BusyIndicatorSize.Large + } + } + + Item { + id: chatUnreadMessagesItem + width: Theme.fontSizeHuge + height: Theme.fontSizeHuge + anchors.right: parent.right + anchors.rightMargin: Theme.paddingMedium + anchors.bottom: parent.bottom + anchors.bottomMargin: Theme.paddingMedium + visible: !chatPage.loading && chatInformation.unread_count > 0 && chatOverviewItem.visible + Rectangle { + id: chatUnreadMessagesCountBackground + color: Theme.highlightBackgroundColor + anchors.fill: parent + radius: width / 2 + visible: chatUnreadMessagesItem.visible + } + + Text { + id: chatUnreadMessagesCount + font.pixelSize: Theme.fontSizeMedium + font.bold: true + color: Theme.primaryColor + anchors.centerIn: chatUnreadMessagesCountBackground + visible: chatUnreadMessagesItem.visible + text: chatInformation.unread_count > 99 ? "99+" : chatInformation.unread_count + } + MouseArea { + anchors.fill: parent + onClicked: { + chatView.scrollToIndex(chatView.count - 1 - chatInformation.unread_count) + } + } + } + + Loader { + id: stickerPickerLoader + active: false + asynchronous: true + width: parent.width + height: active ? parent.height : 0 + source: "../components/StickerPicker.qml" + } + + Connections { + target: stickerPickerLoader.item + onStickerPicked: { + Debug.log("Sticker picked: " + stickerId); + tdLibWrapper.sendStickerMessage(chatInformation.id, stickerId, newMessageColumn.replyToMessageId); + stickerPickerLoader.active = false; + attachmentOptionsFlickable.isNeeded = false; + newMessageInReplyToRow.inReplyToMessage = null; + newMessageColumn.editMessageId = "0"; + } + } + + Loader { + id: messageOverlayLoader + + property var overlayMessage; + + active: false + asynchronous: true + width: parent.width + height: active ? parent.height : 0 + sourceComponent: Component { + MessageOverlayFlickable { + overlayMessage: messageOverlayLoader.overlayMessage + showHeader: !chatPage.isChannel + onRequestClose: { + messageOverlayLoader.active = false; + } + } + } + } + + Loader { + id: voiceNoteOverlayLoader + active: false + asynchronous: true + width: parent.width + height: active ? parent.height : 0 + source: "../components/VoiceNoteOverlay.qml" + onActiveChanged: { + if (!active) { + fernschreiberUtils.stopRecordingVoiceNote(); + } + } + } + + Loader { + id: stickerSetOverlayLoader + + property string stickerSetId; + + active: false + asynchronous: true + width: parent.width + height: active ? parent.height : 0 + sourceComponent: Component { + StickerSetOverlay { + stickerSetId: stickerSetOverlayLoader.stickerSetId + onRequestClose: { + stickerSetOverlayLoader.active = false; + } + } + } + + onActiveChanged: { + if (active) { + attachmentOptionsFlickable.isNeeded = false; + } + } + } + + InlineQuery { + id: inlineQuery + textField: newMessageTextField + chatId: chatInformation.id + } + } + + Column { + id: newMessageColumn + spacing: Theme.paddingSmall + topPadding: Theme.paddingSmall + inlineQuery.buttonPadding + anchors.horizontalCenter: parent.horizontalCenter visible: height > 0 - contentHeight: attachmentOptionsRow.height - contentWidth: Math.max(width, attachmentOptionsRow.width) - property bool fadeRight: (attachmentOptionsRow.width-contentX) > width - property bool fadeLeft: !fadeRight && contentX > 0 - layer.enabled: fadeRight || fadeLeft - layer.effect: OpacityRampEffectBase { - direction: attachmentOptionsFlickable.fadeRight ? OpacityRamp.LeftToRight : OpacityRamp.RightToLeft - source: attachmentOptionsFlickable - slope: 1 + 6 * (chatPage.width) / Screen.width - offset: 1 - 1 / slope + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + height: isNeeded ? implicitHeight : 0 + Behavior on height { SmoothedAnimation { duration: 200 } } + + readonly property bool isNeeded: !chatPage.isSelecting && chatPage.canSendMessages + property string replyToMessageId: "0"; + property string editMessageId: "0"; + + InReplyToRow { + onInReplyToMessageChanged: { + if (inReplyToMessage) { + newMessageColumn.replyToMessageId = newMessageInReplyToRow.inReplyToMessage.id.toString() + newMessageInReplyToRow.visible = true; + } else { + newMessageInReplyToRow.visible = false; + newMessageColumn.replyToMessageId = "0"; + } + } + + editable: true + + onClearRequested: { + newMessageInReplyToRow.inReplyToMessage = null; + } + + id: newMessageInReplyToRow + myUserId: chatPage.myUserId + visible: false + } + + Flickable { + id: attachmentOptionsFlickable + + property bool isNeeded: false + width: chatPage.width + x: -Theme.horizontalPageMargin + height: isNeeded && !inlineQuery.userNameIsValid ? attachmentOptionsRow.height : 0 + Behavior on height { SmoothedAnimation { duration: 200 } } + visible: height > 0 + contentHeight: attachmentOptionsRow.height + contentWidth: Math.max(width, attachmentOptionsRow.width) + property bool fadeRight: (attachmentOptionsRow.width-contentX) > width + property bool fadeLeft: !fadeRight && contentX > 0 + layer.enabled: fadeRight || fadeLeft + layer.effect: OpacityRampEffectBase { + direction: attachmentOptionsFlickable.fadeRight ? OpacityRamp.LeftToRight : OpacityRamp.RightToLeft + source: attachmentOptionsFlickable + slope: 1 + 6 * (chatPage.width) / Screen.width + offset: 1 - 1 / slope + } + + + Row { + id: attachmentOptionsRow + + height: attachImageIconButton.height + + anchors.right: parent.right + layoutDirection: Qt.RightToLeft + spacing: Theme.paddingMedium + leftPadding: Theme.horizontalPageMargin + rightPadding: Theme.horizontalPageMargin + + IconButton { + id: attachImageIconButton + visible: chatPage.hasSendPrivilege("can_send_media_messages") + icon.source: "image://theme/icon-m-image" + onClicked: { + var picker = pageStack.push("Sailfish.Pickers.ImagePickerPage", { + allowedOrientations: chatPage.allowedOrientations + }) + picker.selectedContentPropertiesChanged.connect(function(){ + attachmentOptionsFlickable.isNeeded = false; + Debug.log("Selected document: ", picker.selectedContentProperties.filePath ); + attachmentPreviewRow.fileProperties = picker.selectedContentProperties; + attachmentPreviewRow.isPicture = true; + controlSendButton(); + }) + } + } + IconButton { + visible: chatPage.hasSendPrivilege("can_send_media_messages") + icon.source: "image://theme/icon-m-video" + onClicked: { + var picker = pageStack.push("Sailfish.Pickers.VideoPickerPage", { + allowedOrientations: chatPage.allowedOrientations + }) + picker.selectedContentPropertiesChanged.connect(function(){ + attachmentOptionsFlickable.isNeeded = false; + Debug.log("Selected video: ", picker.selectedContentProperties.filePath ); + attachmentPreviewRow.fileProperties = picker.selectedContentProperties; + attachmentPreviewRow.isVideo = true; + controlSendButton(); + }) + } + } + IconButton { + visible: chatPage.hasSendPrivilege("can_send_media_messages") + icon.source: "image://theme/icon-m-mic" + icon.sourceSize { + width: Theme.iconSizeMedium + height: Theme.iconSizeMedium + } + highlighted: down || voiceNoteOverlayLoader.active + onClicked: { + voiceNoteOverlayLoader.active = !voiceNoteOverlayLoader.active; + stickerPickerLoader.active = false; + } + } + IconButton { + visible: chatPage.hasSendPrivilege("can_send_media_messages") + icon.source: "image://theme/icon-m-document" + onClicked: { + var picker = pageStack.push("Sailfish.Pickers.FilePickerPage", { + allowedOrientations: chatPage.allowedOrientations + }) + picker.selectedContentPropertiesChanged.connect(function(){ + attachmentOptionsFlickable.isNeeded = false; + Debug.log("Selected document: ", picker.selectedContentProperties.filePath ); + attachmentPreviewRow.fileProperties = picker.selectedContentProperties; + attachmentPreviewRow.isDocument = true; + controlSendButton(); + }) + } + } + IconButton { + visible: chatPage.hasSendPrivilege("can_send_other_messages") + icon.source: "../../images/icon-m-sticker.svg" + icon.sourceSize { + width: Theme.iconSizeMedium + height: Theme.iconSizeMedium + } + highlighted: down || stickerPickerLoader.active + onClicked: { + stickerPickerLoader.active = !stickerPickerLoader.active; + voiceNoteOverlayLoader.active = false; + } + } + IconButton { + visible: !(chatPage.isPrivateChat || chatPage.isSecretChat) && chatPage.hasSendPrivilege("can_send_polls") + icon.source: "image://theme/icon-m-question" + onClicked: { + pageStack.push(Qt.resolvedUrl("../pages/PollCreationPage.qml"), { "chatId" : chatInformation.id, groupName: chatInformation.title}); + attachmentOptionsFlickable.isNeeded = false; + } + } + IconButton { + visible: fernschreiberUtils.supportsGeoLocation() && newMessageTextField.text === "" + icon.source: "image://theme/icon-m-location" + icon.sourceSize { + width: Theme.iconSizeMedium + height: Theme.iconSizeMedium + } + onClicked: { + fernschreiberUtils.startGeoLocationUpdates(); + attachmentOptionsFlickable.isNeeded = false; + attachmentPreviewRow.isLocation = true; + attachmentPreviewRow.attachmentDescription = qsTr("Location: Obtaining position..."); + controlSendButton(); + } + } + } + } Row { - id: attachmentOptionsRow - - height: attachImageIconButton.height - - anchors.right: parent.right - layoutDirection: Qt.RightToLeft + id: attachmentPreviewRow + visible: (!!locationData || !!fileProperties) && !inlineQuery.userNameIsValid spacing: Theme.paddingMedium - leftPadding: Theme.horizontalPageMargin - rightPadding: Theme.horizontalPageMargin + width: parent.width + layoutDirection: Qt.RightToLeft + anchors.right: parent.right + + property bool isPicture: false; + property bool isVideo: false; + property bool isDocument: false; + property bool isVoiceNote: false; + property bool isLocation: false; + property var locationData: null; + property var fileProperties: null; + property string attachmentDescription: ""; + + Connections { + target: fernschreiberUtils + onNewPositionInformation: { + attachmentPreviewRow.locationData = positionInformation; + if (attachmentPreviewRow.isLocation) { + attachmentPreviewRow.attachmentDescription = qsTr("Location (%1/%2)").arg(attachmentPreviewRow.locationData.latitude).arg(attachmentPreviewRow.locationData.longitude); + } + } + } IconButton { - id: attachImageIconButton - visible: chatPage.hasSendPrivilege("can_send_media_messages") - icon.source: "image://theme/icon-m-image" + id: removeAttachmentsIconButton + icon.source: "image://theme/icon-m-clear" onClicked: { - var picker = pageStack.push("Sailfish.Pickers.ImagePickerPage", { - allowedOrientations: chatPage.allowedOrientations - }) - picker.selectedContentPropertiesChanged.connect(function(){ - attachmentOptionsFlickable.isNeeded = false; - Debug.log("Selected document: ", picker.selectedContentProperties.filePath ); - attachmentPreviewRow.fileProperties = picker.selectedContentProperties; - attachmentPreviewRow.isPicture = true; - controlSendButton(); - }) - } - } - IconButton { - visible: chatPage.hasSendPrivilege("can_send_media_messages") - icon.source: "image://theme/icon-m-video" - onClicked: { - var picker = pageStack.push("Sailfish.Pickers.VideoPickerPage", { - allowedOrientations: chatPage.allowedOrientations - }) - picker.selectedContentPropertiesChanged.connect(function(){ - attachmentOptionsFlickable.isNeeded = false; - Debug.log("Selected video: ", picker.selectedContentProperties.filePath ); - attachmentPreviewRow.fileProperties = picker.selectedContentProperties; - attachmentPreviewRow.isVideo = true; - controlSendButton(); - }) - } - } - IconButton { - visible: chatPage.hasSendPrivilege("can_send_media_messages") - icon.source: "image://theme/icon-m-mic" - icon.sourceSize { - width: Theme.iconSizeMedium - height: Theme.iconSizeMedium - } - highlighted: down || voiceNoteOverlayLoader.active - onClicked: { - voiceNoteOverlayLoader.active = !voiceNoteOverlayLoader.active; - stickerPickerLoader.active = false; - } - } - IconButton { - visible: chatPage.hasSendPrivilege("can_send_media_messages") - icon.source: "image://theme/icon-m-document" - onClicked: { - var picker = pageStack.push("Sailfish.Pickers.FilePickerPage", { - allowedOrientations: chatPage.allowedOrientations - }) - picker.selectedContentPropertiesChanged.connect(function(){ - attachmentOptionsFlickable.isNeeded = false; - Debug.log("Selected document: ", picker.selectedContentProperties.filePath ); - attachmentPreviewRow.fileProperties = picker.selectedContentProperties; - attachmentPreviewRow.isDocument = true; - controlSendButton(); - }) - } - } - IconButton { - visible: chatPage.hasSendPrivilege("can_send_other_messages") - icon.source: "../../images/icon-m-sticker.svg" - icon.sourceSize { - width: Theme.iconSizeMedium - height: Theme.iconSizeMedium - } - highlighted: down || stickerPickerLoader.active - onClicked: { - stickerPickerLoader.active = !stickerPickerLoader.active; - voiceNoteOverlayLoader.active = false; - } - } - IconButton { - visible: !(chatPage.isPrivateChat || chatPage.isSecretChat) && chatPage.hasSendPrivilege("can_send_polls") - icon.source: "image://theme/icon-m-question" - onClicked: { - pageStack.push(Qt.resolvedUrl("../pages/PollCreationPage.qml"), { "chatId" : chatInformation.id, groupName: chatInformation.title}); - attachmentOptionsFlickable.isNeeded = false; - } - } - IconButton { - visible: fernschreiberUtils.supportsGeoLocation() && newMessageTextField.text === "" - icon.source: "image://theme/icon-m-location" - icon.sourceSize { - width: Theme.iconSizeMedium - height: Theme.iconSizeMedium - } - onClicked: { - fernschreiberUtils.startGeoLocationUpdates(); - attachmentOptionsFlickable.isNeeded = false; - attachmentPreviewRow.isLocation = true; - attachmentPreviewRow.attachmentDescription = qsTr("Location: Obtaining position..."); + clearAttachmentPreviewRow(); controlSendButton(); } } + + Thumbnail { + id: attachmentPreviewImage + width: Theme.itemSizeMedium + height: Theme.itemSizeMedium + sourceSize.width: width + sourceSize.height: height + + fillMode: Thumbnail.PreserveAspectCrop + mimeType: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.mimeType || "" : "" + source: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.url || "" : "" + visible: attachmentPreviewRow.isPicture || attachmentPreviewRow.isVideo + } + + Label { + id: attachmentPreviewText + font.pixelSize: Theme.fontSizeSmall + text: ( attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation ) ? attachmentPreviewRow.attachmentDescription : ( !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.fileName || "" : "" ); + anchors.verticalCenter: parent.verticalCenter + + maximumLineCount: 1 + truncationMode: TruncationMode.Fade + color: Theme.secondaryColor + visible: attachmentPreviewRow.isDocument || attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation + } } - } + Row { + id: uploadStatusRow + visible: false + spacing: Theme.paddingMedium + width: parent.width + anchors.right: parent.right + Text { + id: uploadingText + font.pixelSize: Theme.fontSizeSmall + text: qsTr("Uploading...") + anchors.verticalCenter: parent.verticalCenter + color: Theme.secondaryColor + visible: uploadStatusRow.visible + } - Row { - id: attachmentPreviewRow - visible: (!!locationData || !!fileProperties) && !inlineQuery.userNameIsValid - spacing: Theme.paddingMedium - width: parent.width - layoutDirection: Qt.RightToLeft - anchors.right: parent.right + ProgressBar { + id: uploadingProgressBar + minimumValue: 0 + maximumValue: 100 + value: 0 + visible: uploadStatusRow.visible + width: parent.width - uploadingText.width - Theme.paddingMedium + } - property bool isPicture: false; - property bool isVideo: false; - property bool isDocument: false; - property bool isVoiceNote: false; - property bool isLocation: false; - property var locationData: null; - property var fileProperties: null; - property string attachmentDescription: ""; + } - Connections { - target: fernschreiberUtils - onNewPositionInformation: { - attachmentPreviewRow.locationData = positionInformation; - if (attachmentPreviewRow.isLocation) { - attachmentPreviewRow.attachmentDescription = qsTr("Location (%1/%2)").arg(attachmentPreviewRow.locationData.latitude).arg(attachmentPreviewRow.locationData.longitude); + Column { + id: emojiColumn + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + visible: emojiProposals ? ( emojiProposals.length > 0 ? true : false ) : false + opacity: emojiProposals ? ( emojiProposals.length > 0 ? 1 : 0 ) : 0 + Behavior on opacity { NumberAnimation {} } + spacing: Theme.paddingMedium + + Flickable { + width: parent.width + height: emojiResultRow.height + Theme.paddingSmall + anchors.horizontalCenter: parent.horizontalCenter + contentWidth: emojiResultRow.width + clip: true + Row { + id: emojiResultRow + spacing: Theme.paddingMedium + Repeater { + model: emojiProposals + + Item { + height: singleEmojiRow.height + width: singleEmojiRow.width + + Row { + id: singleEmojiRow + spacing: Theme.paddingSmall + + Image { + id: emojiPicture + source: "../js/emoji/" + modelData.file_name + width: Theme.fontSizeLarge + height: Theme.fontSizeLarge + } + + } + + MouseArea { + anchors.fill: parent + onClicked: { + replaceMessageText(newMessageTextField.text, newMessageTextField.cursorPosition, modelData.emoji); + emojiProposals = null; + } + } + } + + } } } } - IconButton { - id: removeAttachmentsIconButton - icon.source: "image://theme/icon-m-clear" - onClicked: { - clearAttachmentPreviewRow(); - controlSendButton(); + Column { + id: atMentionColumn + width: parent.width + anchors.horizontalCenter: parent.horizontalCenter + visible: opacity > 0 + opacity: knownUsersRepeater.count > 0 ? 1 : 0 + Behavior on opacity { NumberAnimation {} } + height: knownUsersRepeater.count > 0 ? childrenRect.height : 0 + Behavior on height { SmoothedAnimation { duration: 200 } } + spacing: Theme.paddingMedium + + Flickable { + width: parent.width + height: atMentionResultRow.height + Theme.paddingSmall + anchors.horizontalCenter: parent.horizontalCenter + contentWidth: atMentionResultRow.width + clip: true + Row { + id: atMentionResultRow + spacing: Theme.paddingMedium + Repeater { + id: knownUsersRepeater + + Item { + id: knownUserItem + height: singleAtMentionRow.height + width: singleAtMentionRow.width + + property string atMentionText: "@" + (user_name ? user_name : user_id + "(" + title + ")"); + + Row { + id: singleAtMentionRow + spacing: Theme.paddingSmall + + Item { + width: Theme.fontSizeHuge + height: Theme.fontSizeHuge + anchors.verticalCenter: parent.verticalCenter + ProfileThumbnail { + id: atMentionThumbnail + replacementStringHint: title + width: parent.width + height: parent.width + photoData: photo_small + } + } + + Column { + Text { + text: Emoji.emojify(title, Theme.fontSizeExtraSmall) + textFormat: Text.StyledText + color: Theme.primaryColor + font.pixelSize: Theme.fontSizeExtraSmall + font.bold: true + } + Text { + id: userHandleText + text: user_handle + textFormat: Text.StyledText + color: Theme.primaryColor + font.pixelSize: Theme.fontSizeExtraSmall + } + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + replaceMessageText(newMessageTextField.text, newMessageTextField.cursorPosition, knownUserItem.atMentionText); + knownUsersRepeater.model = undefined; + } + } + } + + } + } } } - Thumbnail { - id: attachmentPreviewImage - width: Theme.itemSizeMedium - height: Theme.itemSizeMedium - sourceSize.width: width - sourceSize.height: height - - fillMode: Thumbnail.PreserveAspectCrop - mimeType: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.mimeType || "" : "" - source: !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.url || "" : "" - visible: attachmentPreviewRow.isPicture || attachmentPreviewRow.isVideo - } - - Label { - id: attachmentPreviewText - font.pixelSize: Theme.fontSizeSmall - text: ( attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation ) ? attachmentPreviewRow.attachmentDescription : ( !!attachmentPreviewRow.fileProperties ? attachmentPreviewRow.fileProperties.fileName || "" : "" ); - anchors.verticalCenter: parent.verticalCenter - - maximumLineCount: 1 - truncationMode: TruncationMode.Fade - color: Theme.secondaryColor - visible: attachmentPreviewRow.isDocument || attachmentPreviewRow.isVoiceNote || attachmentPreviewRow.isLocation - } - } - - Row { - id: uploadStatusRow - visible: false - spacing: Theme.paddingMedium - width: parent.width - anchors.right: parent.right - - Text { - id: uploadingText - font.pixelSize: Theme.fontSizeSmall - text: qsTr("Uploading...") - anchors.verticalCenter: parent.verticalCenter - color: Theme.secondaryColor - visible: uploadStatusRow.visible - } - - ProgressBar { - id: uploadingProgressBar - minimumValue: 0 - maximumValue: 100 - value: 0 - visible: uploadStatusRow.visible - width: parent.width - uploadingText.width - Theme.paddingMedium - } - - } - - Column { - id: emojiColumn - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - visible: emojiProposals ? ( emojiProposals.length > 0 ? true : false ) : false - opacity: emojiProposals ? ( emojiProposals.length > 0 ? 1 : 0 ) : 0 - Behavior on opacity { NumberAnimation {} } - spacing: Theme.paddingMedium - - Flickable { + Row { + width: parent.width + spacing: Theme.paddingSmall + visible: newMessageColumn.editMessageId !== "0" + + Text { + width: parent.width - Theme.paddingSmall - removeEditMessageIconButton.width + + anchors.verticalCenter: parent.verticalCenter + + id: editMessageText + font.pixelSize: Theme.fontSizeSmall + font.bold: true + text: qsTr("Edit Message") + color: Theme.secondaryColor + } + + IconButton { + id: removeEditMessageIconButton + icon.source: "image://theme/icon-m-clear" + onClicked: { + newMessageColumn.editMessageId = "0"; + newMessageTextField.text = ""; + } + } + } + + Row { + id: newMessageRow width: parent.width - height: emojiResultRow.height + Theme.paddingSmall anchors.horizontalCenter: parent.horizontalCenter - contentWidth: emojiResultRow.width - clip: true - Row { - id: emojiResultRow - spacing: Theme.paddingMedium - Repeater { - model: emojiProposals - Item { - height: singleEmojiRow.height - width: singleEmojiRow.width - - Row { - id: singleEmojiRow - spacing: Theme.paddingSmall - - Image { - id: emojiPicture - source: "../js/emoji/" + modelData.file_name - width: Theme.fontSizeLarge - height: Theme.fontSizeLarge - } - - } - - MouseArea { - anchors.fill: parent - onClicked: { - replaceMessageText(newMessageTextField.text, newMessageTextField.cursorPosition, modelData.emoji); - emojiProposals = null; - } + TextArea { + id: newMessageTextField + width: parent.width - (attachmentIconButton.visible ? attachmentIconButton.width : 0) - (newMessageSendButton.visible ? newMessageSendButton.width : 0) - (cancelInlineQueryButton.visible ? cancelInlineQueryButton.width : 0) + height: Math.min(chatContainer.height / 3, implicitHeight) + anchors.verticalCenter: parent.verticalCenter + font.pixelSize: Theme.fontSizeSmall + placeholderText: qsTr("Your message") + labelVisible: false + textLeftMargin: 0 + textTopMargin: 0 + enabled: !attachmentPreviewRow.isLocation + EnterKey.onClicked: { + if (appSettings.sendByEnter) { + sendMessage(); + newMessageTextField.text = ""; + if(!appSettings.focusTextAreaAfterSend) { + newMessageTextField.focus = false; } } + } + EnterKey.enabled: !inlineQuery.userNameIsValid && (!appSettings.sendByEnter || text.length) + EnterKey.iconSource: appSettings.sendByEnter ? "image://theme/icon-m-chat" : "image://theme/icon-m-enter" + + onTextChanged: { + controlSendButton(); + textReplacementTimer.restart(); } } - } - } - Column { - id: atMentionColumn - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - visible: opacity > 0 - opacity: knownUsersRepeater.count > 0 ? 1 : 0 - Behavior on opacity { NumberAnimation {} } - height: knownUsersRepeater.count > 0 ? childrenRect.height : 0 - Behavior on height { SmoothedAnimation { duration: 200 } } - spacing: Theme.paddingMedium - - Flickable { - width: parent.width - height: atMentionResultRow.height + Theme.paddingSmall - anchors.horizontalCenter: parent.horizontalCenter - contentWidth: atMentionResultRow.width - clip: true - Row { - id: atMentionResultRow - spacing: Theme.paddingMedium - Repeater { - id: knownUsersRepeater - - Item { - id: knownUserItem - height: singleAtMentionRow.height - width: singleAtMentionRow.width - - property string atMentionText: "@" + (user_name ? user_name : user_id + "(" + title + ")"); - - Row { - id: singleAtMentionRow - spacing: Theme.paddingSmall - - Item { - width: Theme.fontSizeHuge - height: Theme.fontSizeHuge - anchors.verticalCenter: parent.verticalCenter - ProfileThumbnail { - id: atMentionThumbnail - replacementStringHint: title - width: parent.width - height: parent.width - photoData: photo_small - } - } - - Column { - Text { - text: Emoji.emojify(title, Theme.fontSizeExtraSmall) - textFormat: Text.StyledText - color: Theme.primaryColor - font.pixelSize: Theme.fontSizeExtraSmall - font.bold: true - } - Text { - id: userHandleText - text: user_handle - textFormat: Text.StyledText - color: Theme.primaryColor - font.pixelSize: Theme.fontSizeExtraSmall - } - } - } - - MouseArea { - anchors.fill: parent - onClicked: { - replaceMessageText(newMessageTextField.text, newMessageTextField.cursorPosition, knownUserItem.atMentionText); - knownUsersRepeater.model = undefined; - } - } + IconButton { + id: attachmentIconButton + icon.source: "image://theme/icon-m-attach?" + (attachmentOptionsFlickable.isNeeded ? Theme.highlightColor : Theme.primaryColor) + anchors.bottom: parent.bottom + anchors.bottomMargin: Theme.paddingSmall + enabled: !attachmentPreviewRow.visible && !stickerSetOverlayLoader.item + visible: !inlineQuery.userNameIsValid + onClicked: { + if (attachmentOptionsFlickable.isNeeded) { + attachmentOptionsFlickable.isNeeded = false; + stickerPickerLoader.active = false; + voiceNoteOverlayLoader.active = false; + } else { + attachmentOptionsFlickable.isNeeded = true; } - } } - } - } - Row { - width: parent.width - spacing: Theme.paddingSmall - visible: newMessageColumn.editMessageId !== "0" - - Text { - width: parent.width - Theme.paddingSmall - removeEditMessageIconButton.width - - anchors.verticalCenter: parent.verticalCenter - - id: editMessageText - font.pixelSize: Theme.fontSizeSmall - font.bold: true - text: qsTr("Edit Message") - color: Theme.secondaryColor - } - - IconButton { - id: removeEditMessageIconButton - icon.source: "image://theme/icon-m-clear" - onClicked: { - newMessageColumn.editMessageId = "0"; - newMessageTextField.text = ""; - } - } - } - - Row { - id: newMessageRow - width: parent.width - anchors.horizontalCenter: parent.horizontalCenter - - TextArea { - id: newMessageTextField - width: parent.width - (attachmentIconButton.visible ? attachmentIconButton.width : 0) - (newMessageSendButton.visible ? newMessageSendButton.width : 0) - (cancelInlineQueryButton.visible ? cancelInlineQueryButton.width : 0) - height: Math.min(chatContainer.height / 3, implicitHeight) - anchors.verticalCenter: parent.verticalCenter - font.pixelSize: Theme.fontSizeSmall - placeholderText: qsTr("Your message") - labelVisible: false - textLeftMargin: 0 - textTopMargin: 0 - enabled: !attachmentPreviewRow.isLocation - EnterKey.onClicked: { - if (appSettings.sendByEnter) { + IconButton { + id: newMessageSendButton + icon.source: "image://theme/icon-m-chat" + anchors.bottom: parent.bottom + anchors.bottomMargin: Theme.paddingSmall + visible: !inlineQuery.userNameIsValid && (!appSettings.sendByEnter || attachmentPreviewRow.visible) + enabled: false + onClicked: { sendMessage(); newMessageTextField.text = ""; if(!appSettings.focusTextAreaAfterSend) { @@ -1764,89 +1896,50 @@ Page { } } - EnterKey.enabled: !inlineQuery.userNameIsValid && (!appSettings.sendByEnter || text.length) - EnterKey.iconSource: appSettings.sendByEnter ? "image://theme/icon-m-chat" : "image://theme/icon-m-enter" + Item { + width: cancelInlineQueryButton.width + height: cancelInlineQueryButton.height + visible: inlineQuery.userNameIsValid + anchors.bottom: parent.bottom + anchors.bottomMargin: Theme.paddingSmall - onTextChanged: { - controlSendButton(); - textReplacementTimer.restart(); - } - } - - IconButton { - id: attachmentIconButton - icon.source: "image://theme/icon-m-attach?" + (attachmentOptionsFlickable.isNeeded ? Theme.highlightColor : Theme.primaryColor) - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.paddingSmall - enabled: !attachmentPreviewRow.visible && !stickerSetOverlayLoader.item - visible: !inlineQuery.userNameIsValid - onClicked: { - if (attachmentOptionsFlickable.isNeeded) { - attachmentOptionsFlickable.isNeeded = false; - stickerPickerLoader.active = false; - voiceNoteOverlayLoader.active = false; - } else { - attachmentOptionsFlickable.isNeeded = true; - } - } - } - - IconButton { - id: newMessageSendButton - icon.source: "image://theme/icon-m-chat" - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.paddingSmall - visible: !inlineQuery.userNameIsValid && (!appSettings.sendByEnter || attachmentPreviewRow.visible) - enabled: false - onClicked: { - sendMessage(); - newMessageTextField.text = ""; - if(!appSettings.focusTextAreaAfterSend) { - newMessageTextField.focus = false; - } - } - } - - Item { - width: cancelInlineQueryButton.width - height: cancelInlineQueryButton.height - visible: inlineQuery.userNameIsValid - anchors.bottom: parent.bottom - anchors.bottomMargin: Theme.paddingSmall - - IconButton { - id: cancelInlineQueryButton - icon.source: "image://theme/icon-m-cancel" - visible: parent.visible - opacity: inlineQuery.isLoading ? 0.2 : 1 - Behavior on opacity { FadeAnimation {} } - onClicked: { - if(inlineQuery.query !== "") { - newMessageTextField.text = "@" + inlineQuery.userName + " " - newMessageTextField.cursorPosition = newMessageTextField.text.length - lostFocusTimer.start(); - } else { + IconButton { + id: cancelInlineQueryButton + icon.source: "image://theme/icon-m-cancel" + visible: parent.visible + opacity: inlineQuery.isLoading ? 0.2 : 1 + Behavior on opacity { FadeAnimation {} } + onClicked: { + if(inlineQuery.query !== "") { + newMessageTextField.text = "@" + inlineQuery.userName + " " + newMessageTextField.cursorPosition = newMessageTextField.text.length + lostFocusTimer.start(); + } else { + newMessageTextField.text = "" + } + } + onPressAndHold: { newMessageTextField.text = "" } } - onPressAndHold: { - newMessageTextField.text = "" + + BusyIndicator { + size: BusyIndicatorSize.Small + anchors.centerIn: parent + running: inlineQuery.isLoading } } - BusyIndicator { - size: BusyIndicatorSize.Small - anchors.centerIn: parent - running: inlineQuery.isLoading - } + } - - } } } + + } + Loader { id: selectedMessagesActions asynchronous: true diff --git a/rpm/harbour-fernschreiber.spec b/rpm/harbour-fernschreiber.spec index 8b97fa8..999885f 100644 --- a/rpm/harbour-fernschreiber.spec +++ b/rpm/harbour-fernschreiber.spec @@ -12,7 +12,7 @@ Name: harbour-fernschreiber Summary: Fernschreiber is a Telegram client for Sailfish OS Version: 0.7.1 -Release: 2 +Release: 3 Group: Qt/Qt License: LICENSE URL: http://werkwolf.eu/ diff --git a/rpm/harbour-fernschreiber.yaml b/rpm/harbour-fernschreiber.yaml index b8168df..b1a564d 100644 --- a/rpm/harbour-fernschreiber.yaml +++ b/rpm/harbour-fernschreiber.yaml @@ -1,7 +1,7 @@ Name: harbour-fernschreiber Summary: Fernschreiber is a Telegram client for Sailfish OS Version: 0.7.1 -Release: 2 +Release: 3 # The contents of the Group field should be one of the groups listed here: # https://github.com/mer-tools/spectacle/blob/master/data/GROUPS Group: Qt/Qt diff --git a/translations/harbour-fernschreiber-de.ts b/translations/harbour-fernschreiber-de.ts index 1e7fac7..f15679a 100644 --- a/translations/harbour-fernschreiber-de.ts +++ b/translations/harbour-fernschreiber-de.ts @@ -435,6 +435,14 @@ Location (%1/%2) Standort (%1/%2) + + Copy Message to Clipboard + Nachricht in die Zwischenablage kopieren + + + Message Options + + ChatSelectionPage @@ -991,6 +999,10 @@ Unpin Message Nachricht losheften + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-en.ts b/translations/harbour-fernschreiber-en.ts index cbd94b1..4785223 100644 --- a/translations/harbour-fernschreiber-en.ts +++ b/translations/harbour-fernschreiber-en.ts @@ -435,6 +435,14 @@ Location (%1/%2) Location (%1/%2) + + Copy Message to Clipboard + Copy Message to Clipboard + + + Message Options + + ChatSelectionPage @@ -993,6 +1001,10 @@ messages Unpin Message Unpin Message + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-es.ts b/translations/harbour-fernschreiber-es.ts index 3e216ce..aa9b741 100644 --- a/translations/harbour-fernschreiber-es.ts +++ b/translations/harbour-fernschreiber-es.ts @@ -435,6 +435,14 @@ Location (%1/%2) Ubicación (%1/%2) + + Copy Message to Clipboard + Copiar + + + Message Options + + ChatSelectionPage @@ -991,6 +999,10 @@ Unpin Message Desanclar mensaje + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-fi.ts b/translations/harbour-fernschreiber-fi.ts index 2dbffc2..093bc77 100644 --- a/translations/harbour-fernschreiber-fi.ts +++ b/translations/harbour-fernschreiber-fi.ts @@ -435,6 +435,14 @@ Location (%1/%2) Sijainti (%1/%2) + + Copy Message to Clipboard + Kopioi viesti leikepöydälle + + + Message Options + + ChatSelectionPage @@ -992,6 +1000,10 @@ Unpin Message Poista viestin kiinnitys + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-hu.ts b/translations/harbour-fernschreiber-hu.ts index de21a42..31173e4 100644 --- a/translations/harbour-fernschreiber-hu.ts +++ b/translations/harbour-fernschreiber-hu.ts @@ -425,6 +425,14 @@ Location (%1/%2) + + Copy Message to Clipboard + + + + Message Options + + ChatSelectionPage @@ -977,6 +985,10 @@ Unpin Message + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-it.ts b/translations/harbour-fernschreiber-it.ts index 63eec71..366d1a7 100644 --- a/translations/harbour-fernschreiber-it.ts +++ b/translations/harbour-fernschreiber-it.ts @@ -435,6 +435,14 @@ Location (%1/%2) Posizione(%1/%2) + + Copy Message to Clipboard + Copia messaggio nella clipboard + + + Message Options + + ChatSelectionPage @@ -991,6 +999,10 @@ Unpin Message Togli messaggio in evidenza + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-pl.ts b/translations/harbour-fernschreiber-pl.ts index dfc6fdf..f0acce1 100644 --- a/translations/harbour-fernschreiber-pl.ts +++ b/translations/harbour-fernschreiber-pl.ts @@ -445,6 +445,14 @@ Location (%1/%2) Lokalizacja (%1/%2) + + Copy Message to Clipboard + Skopiuj wiadomość do schowka + + + Message Options + + ChatSelectionPage @@ -1005,6 +1013,10 @@ Unpin Message Odepnij wiadomość + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-ru.ts b/translations/harbour-fernschreiber-ru.ts index f054407..84182ef 100644 --- a/translations/harbour-fernschreiber-ru.ts +++ b/translations/harbour-fernschreiber-ru.ts @@ -445,6 +445,14 @@ Location (%1/%2) Местоположение (%1/%2) + + Copy Message to Clipboard + Скопировать в буфер обмена + + + Message Options + + ChatSelectionPage @@ -1008,6 +1016,10 @@ Unpin Message Открепить сообщение + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-sk.ts b/translations/harbour-fernschreiber-sk.ts index 5bbc498..56cf8f9 100644 --- a/translations/harbour-fernschreiber-sk.ts +++ b/translations/harbour-fernschreiber-sk.ts @@ -445,6 +445,14 @@ Location (%1/%2) Poloha (%1/%2) + + Copy Message to Clipboard + Kopírovať správu do schránky + + + Message Options + + ChatSelectionPage @@ -1005,6 +1013,10 @@ Unpin Message Odopnúť správu + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-sv.ts b/translations/harbour-fernschreiber-sv.ts index fb90049..910c4b9 100644 --- a/translations/harbour-fernschreiber-sv.ts +++ b/translations/harbour-fernschreiber-sv.ts @@ -435,6 +435,14 @@ Location (%1/%2) Plats (%1/%2) + + Copy Message to Clipboard + Kopiera meddelandet till urklipp + + + Message Options + + ChatSelectionPage @@ -991,6 +999,10 @@ Unpin Message Lösgör meddelandet + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber-zh_CN.ts b/translations/harbour-fernschreiber-zh_CN.ts index cc64d84..127afe2 100644 --- a/translations/harbour-fernschreiber-zh_CN.ts +++ b/translations/harbour-fernschreiber-zh_CN.ts @@ -425,6 +425,14 @@ Location (%1/%2) 位置 (%1/%2) + + Copy Message to Clipboard + 复制消息到剪切板 + + + Message Options + + ChatSelectionPage @@ -978,6 +986,10 @@ Unpin Message 取消置顶 + + More Options... + + MessageListViewItemSimple diff --git a/translations/harbour-fernschreiber.ts b/translations/harbour-fernschreiber.ts index a3c7cdd..7160831 100644 --- a/translations/harbour-fernschreiber.ts +++ b/translations/harbour-fernschreiber.ts @@ -435,6 +435,14 @@ Location (%1/%2) + + Copy Message to Clipboard + Copy Message to Clipboard + + + Message Options + + ChatSelectionPage @@ -991,6 +999,10 @@ Unpin Message + + More Options... + + MessageListViewItemSimple