diff --git a/harbour-fernschreiber.pro b/harbour-fernschreiber.pro index 75db4e6..6efc7aa 100644 --- a/harbour-fernschreiber.pro +++ b/harbour-fernschreiber.pro @@ -34,13 +34,27 @@ SOURCES += src/harbour-fernschreiber.cpp \ DISTFILES += qml/harbour-fernschreiber.qml \ qml/components/AudioPreview.qml \ + qml/components/ChatListViewItem.qml \ qml/components/DocumentPreview.qml \ qml/components/ImagePreview.qml \ qml/components/InReplyToRow.qml \ qml/components/LocationPreview.qml \ qml/components/StickerPicker.qml \ + qml/components/PhotoTextsListItem.qml \ qml/components/WebPagePreview.qml \ + qml/components/chatInformationPage/ChatInformationEditArea.qml \ + qml/components/chatInformationPage/ChatInformationProfilePicture.qml \ + qml/components/chatInformationPage/ChatInformationProfilePictureList.qml \ + qml/components/chatInformationPage/ChatInformationTabItemBase.qml \ + qml/components/chatInformationPage/ChatInformationTabItemDebug.qml \ + qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml \ + qml/components/chatInformationPage/ChatInformationTabItemSettings.qml \ + qml/components/chatInformationPage/ChatInformationTabView.qml \ + qml/components/chatInformationPage/ChatInformationTextItem.qml \ + qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml \ + qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml \ qml/js/functions.js \ + qml/pages/ChatInformationPage.qml \ qml/pages/ChatPage.qml \ qml/pages/CoverPage.qml \ qml/pages/InitializationPage.qml \ diff --git a/qml/components/ChatListViewItem.qml b/qml/components/ChatListViewItem.qml new file mode 100644 index 0000000..a7ca8f6 --- /dev/null +++ b/qml/components/ChatListViewItem.qml @@ -0,0 +1,54 @@ +import QtQuick 2.5 +import Sailfish.Silica 1.0 + +import "../js/twemoji.js" as Emoji +import "../js/functions.js" as Functions + +PhotoTextsListItem { + id: listItem + pictureThumbnail { +// forceElementUpdate: overviewPage.chatListCreated + photoData: photo_small +// replacementStringHint: primaryText.text + } + property int ownUserId + + // chat title + primaryText.text: title ? Emoji.emojify(title, Theme.fontSizeMedium) + ( display.notification_settings.mute_for > 0 ? Emoji.emojify(" 🔇", Theme.fontSizeMedium) : "" ) : qsTr("Unknown") + // last user + prologSecondaryText.text: is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), primaryText.font.pixelSize) : qsTr("You") ) : qsTr("Unknown") ) + // last message + secondaryText.text: last_message_text ? Emoji.emojify(last_message_text, Theme.fontSizeExtraSmall) : qsTr("Unknown") + // message date + tertiaryText.text: last_message_date ? Functions.getDateTimeElapsed(last_message_date) : qsTr("Unknown") + unreadCount: unread_count + + openMenuOnPressAndHold: true//chat_id != overviewPage.ownUserId + menu: ContextMenu { + MenuItem { + visible: chat_id != listItem.ownUserId + onClicked: { + var newNotificationSettings = display.notification_settings; + if (newNotificationSettings.mute_for > 0) { + newNotificationSettings.mute_for = 0; + } else { + newNotificationSettings.mute_for = 6666666; + } + tdLibWrapper.setChatNotificationSettings(chat_id, newNotificationSettings); + } + text: display.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat") + } + + MenuItem { + onClicked: { + if(pageStack.depth > 2) { + pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate); + } + + pageStack.push(Qt.resolvedUrl("../pages/ChatInformationPage.qml"), { "chatInformation" : display}); + } + text: model.display.type['@type'] === "chatTypePrivate" ? qsTr("User Info") : qsTr("Group Info") + } + } + +} diff --git a/qml/components/PhotoTextsListItem.qml b/qml/components/PhotoTextsListItem.qml new file mode 100644 index 0000000..e2ae4da --- /dev/null +++ b/qml/components/PhotoTextsListItem.qml @@ -0,0 +1,153 @@ +import QtQuick 2.5 +import Sailfish.Silica 1.0 +ListItem { + + id: chatListViewItem + + property alias primaryText: primaryText //usually chat name + property alias prologSecondaryText: prologSecondaryText //usually last sender name + property alias secondaryText: secondaryText //usually last message + property alias tertiaryText: tertiaryText //usually last message date + + property int unreadCount + property alias pictureThumbnail: pictureThumbnail + + contentHeight: mainRow.height + separator.height + 2 * Theme.paddingMedium + contentWidth: parent.width + + + + Column { + id: mainColumn + width: parent.width - ( 2 * Theme.horizontalPageMargin ) + spacing: Theme.paddingSmall + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + + Row { + id: mainRow + width: parent.width + height: contentColumn.height + spacing: Theme.paddingMedium + + Column { + id: pictureColumn + width: contentColumn.height - Theme.paddingSmall + height: contentColumn.height - Theme.paddingSmall + anchors.verticalCenter: parent.verticalCenter + + Item { + id: chatListPictureItem + width: parent.width + height: parent.width + + ProfileThumbnail { + id: pictureThumbnail + replacementStringHint: primaryText.text + width: parent.width + height: parent.width + } + + Rectangle { + id: chatUnreadMessagesCountBackground + color: Theme.highlightBackgroundColor + width: Theme.fontSizeLarge + height: Theme.fontSizeLarge + anchors.right: parent.right + anchors.bottom: parent.bottom + radius: parent.width / 2 + visible: chatListViewItem.unreadCount > 0 + } + + Text { + id: chatUnreadMessagesCount + font.pixelSize: Theme.fontSizeExtraSmall + font.bold: true + color: Theme.primaryColor + anchors.centerIn: chatUnreadMessagesCountBackground + visible: chatUnreadMessagesCountBackground.visible + text: chatListViewItem.unreadCount > 99 ? "99+" : chatListViewItem.unreadCount + } + } + } + + Column { + id: contentColumn + width: parent.width * 5 / 6 - Theme.horizontalPageMargin + spacing: Theme.paddingSmall + + Text { + id: primaryText + textFormat: Text.StyledText + font.pixelSize: Theme.fontSizeMedium + color: Theme.primaryColor + elide: Text.ElideRight + width: parent.width + onTruncatedChanged: { + // There is obviously a bug in QML in truncating text with images. + // We simply remove Emojis then... + if (truncated) { + text = text.replace(/\]+\/\>/g, ""); + } + } + } + + Row { + id: additionalTextRow + width: parent.width + spacing: Theme.paddingSmall + Text { + id: prologSecondaryText + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.highlightColor + textFormat: Text.StyledText + onTruncatedChanged: { + // There is obviously a bug in QML in truncating text with images. + // We simply remove Emojis then... + if (truncated) { + text = text.replace(/\]+\/\>/g, ""); + } + } + } + Text { + id: secondaryText + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.primaryColor + width: parent.width - Theme.paddingMedium - prologSecondaryText.width + elide: Text.ElideRight + textFormat: Text.StyledText + onTruncatedChanged: { + // There is obviously a bug in QML in truncating text with images. + // We simply remove Emojis then... + if (truncated) { + text = text.replace(/\]+\/\>/g, ""); + } + } + } + } + + Text { + id: tertiaryText + width: parent.width + font.pixelSize: Theme.fontSizeTiny + color: Theme.secondaryColor + } + } + } + } + + Separator { + id: separator + anchors { + top: mainColumn.bottom + topMargin: Theme.paddingMedium + } + + width: parent.width + color: Theme.primaryColor + horizontalAlignment: Qt.AlignHCenter + } + +} diff --git a/qml/components/ProfileThumbnail.qml b/qml/components/ProfileThumbnail.qml index c22f194..e8d2221 100644 --- a/qml/components/ProfileThumbnail.qml +++ b/qml/components/ProfileThumbnail.qml @@ -27,6 +27,8 @@ Item { property variant photoData; property string replacementStringHint: "X" property bool forceElementUpdate: false + property int radius: width / 2 + property int imageStatus: -1 function getReplacementString() { if (replacementStringHint.length > 2) { @@ -109,6 +111,9 @@ Item { autoTransform: true asynchronous: true visible: false + onStatusChanged: { + profileThumbnail.imageStatus = status + } } Rectangle { @@ -116,7 +121,7 @@ Item { width: parent.width - Theme.paddingSmall height: parent.height - Theme.paddingSmall color: Theme.primaryColor - radius: parent.width / 2 + radius: profileThumbnail.radius anchors.centerIn: singleImage visible: false } diff --git a/qml/components/chatInformationPage/ChatInformationEditArea.qml b/qml/components/chatInformationPage/ChatInformationEditArea.qml new file mode 100644 index 0000000..fc37aad --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationEditArea.qml @@ -0,0 +1,102 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +Column { + id: editAreaColumn + visible: canEdit || text !== "" + property bool canEdit + property alias headerText: editAreaHeader.text + property string emptyPlaceholderText + property string text + property bool multiLine + + property bool isEditing + property Item editItem: multiLine ? editAreaTextArea : editAreaTextField + + signal saveButtonClicked(string textValue) + signal editButtonClicked() + signal textEdited(string textValue) + width: parent.width + + + SectionHeader { + id: editAreaHeader + font.pixelSize: Theme.fontSizeExtraSmall + height: parent.visible && text !== "" ? Theme.itemSizeExtraSmall : 0 + x: 0 + } + Row { + id: editAreaTextRow + width: parent.width + + TextArea { + id: editAreaTextArea + visible: editAreaColumn.isEditing && editAreaColumn.multiLine + width: parent.width - editAreaButton.width + anchors.verticalCenter: parent.verticalCenter + } + TextField { + id: editAreaTextField + visible: editAreaColumn.isEditing && !editAreaColumn.multiLine + width: parent.width - editAreaButton.width + anchors.verticalCenter: parent.verticalCenter + EnterKey.onClicked: { + editAreaColumn.isEditing = false; + editAreaColumn.saveButtonClicked(editAreaColumn.editItem.text); + } + EnterKey.iconSource: editAreaButton.icon.source + } + ChatInformationTextItem { + id: editAreaTextItem + visible: !editAreaColumn.isEditing + anchors.verticalCenter: parent.verticalCenter + text: editAreaColumn.text || editAreaColumn.emptyPlaceholderText + width: parent.width - editAreaButton.width + } + IconButton { + id: editAreaButton + visible: editAreaColumn.canEdit + width: visible ? Theme.itemSizeSmall : 0 + icon.source: editAreaColumn.isEditing ? "image://theme/icon-m-accept" : "image://theme/icon-m-edit" + anchors.verticalCenter: parent.verticalCenter + onClicked: { + if(editAreaColumn.isEditing) { + editAreaColumn.isEditing = false; + editAreaColumn.saveButtonClicked(editAreaColumn.editItem.text); + } else { + editAreaColumn.isEditing = true; + editAreaColumn.editItem.text = editAreaColumn.text; + editAreaColumn.editItem.forceActiveFocus(); + editAreaColumn.editItem.cursorPosition = editAreaColumn.editItem.text.length; + editAreaColumn.editButtonClicked(); + } + } + } + } + Connections { + target: editItem + onTextChanged: { + if(editItem.focus) { + editAreaColumn.textEdited(editItem.text) + } + } + } +} diff --git a/qml/components/chatInformationPage/ChatInformationProfilePicture.qml b/qml/components/chatInformationPage/ChatInformationProfilePicture.qml new file mode 100644 index 0000000..ad04316 --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationProfilePicture.qml @@ -0,0 +1,44 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ + +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import "../" + +Item { + visible: imageContainer.tweenFactor > 0.8 && chatPictureDetail.imageStatus === Image.Ready + property bool isActive: imageContainer.tweenFactor === 1.0 + opacity: isActive ? 1.0 : 0.0 + Behavior on opacity { NumberAnimation {} } + ProfileThumbnail { + id: chatPictureDetail + anchors.fill: parent + photoData: (typeof chatInformation.photo !== "undefined") ? chatInformation.photo.big : "" + replacementStringHint: "" + radius: chatPictureThumbnail.radius + } + + MouseArea { + anchors.fill: parent + onClicked: { + var preparedPhotoData = {sizes:[{width:640,height: 640,photo:chatPictureDetail.photoData}]}; + pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), { "photoData" : preparedPhotoData }); + } + } +} diff --git a/qml/components/chatInformationPage/ChatInformationProfilePictureList.qml b/qml/components/chatInformationPage/ChatInformationProfilePictureList.qml new file mode 100644 index 0000000..3fa4f0d --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationProfilePictureList.qml @@ -0,0 +1,73 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import "../" + +Item { + visible: imageContainer.tweenFactor > 0.8 && bigProfilePictureList.count > 0 + property bool isActive: imageContainer.tweenFactor === 1.0 + + opacity: isActive ? 1.0 : 0.0 + Behavior on opacity { NumberAnimation {} } + + SlideshowView { + id: bigProfilePictureList + property bool isActive: imageContainer.tweenFactor === 1.0 + width: parent.width + height: parent.height + clip: true + itemWidth: width + itemHeight: height + interactive: parent.isActive + model: chatInformationPage.chatPartnerProfilePhotos + delegate: Item { + width: bigProfilePictureList.itemWidth + height: bigProfilePictureList.itemHeight + ProfileThumbnail { + id: chatPictureDetail + photoData: modelData.sizes[modelData.sizes.length - 1].photo + replacementStringHint: "" + radius: chatPictureThumbnail.radius + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + onClicked: { + pageStack.push(Qt.resolvedUrl("../../pages/ImagePage.qml"), { "photoData" : modelData }); + } + } + } + } + + Text { + visible: bigProfilePictureList.count > 1 + width: parent.width + anchors { + bottomMargin: Theme.paddingSmall + bottom: parent.bottom + } + horizontalAlignment: Text.AlignHCenter + property var baseString: new Array(bigProfilePictureList.count+1).join(" ○ ") + text: baseString.substring(0,bigProfilePictureList.currentIndex*3) + " ● " + baseString.substring((bigProfilePictureList.currentIndex+1)*3) + color: Theme.primaryColor + style: Text.Raised + styleColor: Theme.highlightDimmerColor + } +} diff --git a/qml/components/chatInformationPage/ChatInformationTabItemBase.qml b/qml/components/chatInformationPage/ChatInformationTabItemBase.qml new file mode 100644 index 0000000..a9f5cfd --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTabItemBase.qml @@ -0,0 +1,74 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import "../../pages" +import "../" + +Item { + id: tabItem + property string title + property url image + property bool loading + //overrideable: + property alias loadingVisible: loadingColumn.loadingVisible + property string loadingText + + property int tabIndex: tabItem.VisualItemModel.index + property bool active: tabItem.ListView.isCurrentItem + + default property alias _data: contentItem.data + + + width: parent.width + height: tabView.maxHeight//Math.max(contentItem.height, loadingColumn.height) + opacity: active ? 1.0 : 0.0 + Behavior on opacity { PropertyAnimation {duration: 300}} + + Column { + id: loadingColumn + property bool loadingVisible: tabItem.loading + width: tabItem.width + height: loadingLabel.height + loadingBusyIndicator.height + Theme.paddingMedium + spacing: Theme.paddingMedium + topPadding: Theme.paddingLarge + anchors.top: parent.top + opacity: loadingVisible ? 1.0 : 0.0 + Behavior on opacity { NumberAnimation {} } + visible: tabItem.loading + + InfoLabel { + id: loadingLabel + text: tabItem.loadingText + } + + BusyIndicator { + id: loadingBusyIndicator + anchors.horizontalCenter: parent.horizontalCenter + running: parent.loadingVisible + size: BusyIndicatorSize.Large + } + } + Item { + id: contentItem + width: parent.width + height: childrenRect.height + } + +} diff --git a/qml/components/chatInformationPage/ChatInformationTabItemDebug.qml b/qml/components/chatInformationPage/ChatInformationTabItemDebug.qml new file mode 100644 index 0000000..400ca76 --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTabItemDebug.qml @@ -0,0 +1,59 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import QtQml.Models 2.3 + +import "../" +import "../../pages" +import "../../js/twemoji.js" as Emoji +import "../../js/functions.js" as Functions + +ChatInformationTabItemBase { + id: tabBase + title: "debug" + image: "image://theme/icon-m-diagnostic" + SilicaFlickable { + height: tabBase.height + width: tabBase.width + contentHeight: contentColumn.height + Column { + id: contentColumn + width: tabBase.width - Theme.horizontalPageMargin * 2 + x: Theme.horizontalPageMargin + + ChatInformationTextItem { + headerText: "chatInformation" + text:chatInformationPage.chatInformation ? JSON.stringify(chatInformationPage.chatInformation, null, 2) : "" + isLinkedLabel: true + } + ChatInformationTextItem { + headerText: "groupInformation" + text: chatInformationPage.groupInformation ? JSON.stringify(chatInformationPage.groupInformation, null, 2) : "" + isLinkedLabel: true + } + + ChatInformationTextItem { + headerText: "groupFullInformation" + text: chatInformationPage.groupFullInformation ? JSON.stringify(chatInformationPage.groupFullInformation, null, 2) : "" + isLinkedLabel: true + } + } + } +} diff --git a/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml b/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml new file mode 100644 index 0000000..8ee4ae2 --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTabItemMembersGroups.qml @@ -0,0 +1,231 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import QtQml.Models 2.3 + +import "../" +import "../../pages" +import "../../js/twemoji.js" as Emoji +import "../../js/functions.js" as Functions + +ChatInformationTabItemBase { + id: tabBase + title: chatInformationPage.isPrivateChat ? qsTr("Groups", "Button: groups in common (short)") : qsTr("Members", "Button: Group Members") + image: "image://theme/icon-m-people" + loadingText: isPrivateChat ? qsTr("Loading common chats…", "chats you have in common with a user") : qsTr("Loading group members…") + loading: chatInformationPage.isSuperGroup || chatInformationPage.isPrivateChat + loadingVisible: loading && membersView.count === 0 + + property variant chatPartnerCommonGroupsIds: ([]); + + + SilicaListView { + id: membersView + model: isPrivateChat ? delegateModel : chatInformationPage.membersList + clip: true + height: tabBase.height + width: tabBase.width + opacity: tabBase.loading ? (count > 0 ? 0.5 : 0.0) : 1.0 + Behavior on opacity { NumberAnimation {} } + function handleScrollIntoView(force){ + if(!tabBase.loading && !dragging && !quickScrollAnimating ) { + if(!atYBeginning) { + chatInformationPage.scrollDown() + } else { + chatInformationPage.scrollUp(force); + } + } + } + onDraggingChanged: { + handleScrollIntoView() + } + onAtYBeginningChanged: { + handleScrollIntoView() + } + onAtYEndChanged: { + if(tabBase.active && !tabBase.loading && chatInformationPage.isSuperGroup && (groupInformation.member_count > membersView.count) && membersView.atYEnd) { + tabBase.loading = true; + fetchMoreMembersTimer.start() + } + } + onQuickScrollAnimatingChanged: { + handleScrollIntoView(true) + } + + delegate: PhotoTextsListItem { + pictureThumbnail { + photoData: (typeof user.profile_photo !== "undefined") ? user.profile_photo.small : "" + } + width: parent.width + + // chat title isPrivateChat ? () : + primaryText.text: Emoji.emojify(Functions.getUserName(user), primaryText.font.pixelSize) + // last user + prologSecondaryText.text: "@"+(user.username !== "" ? user.username : user_id) + (user_id === chatInformationPage.myUserId ? " " + qsTr("You") : "") + secondaryText { + horizontalAlignment: Text.AlignRight + property string statusText: Functions.getChatMemberStatusText(model.status["@type"]) + property string customText: model.status.custom_title ? Emoji.emojify(model.status.custom_title, secondaryText.font.pixelSize) : "" + text: (statusText !== "" && customText !== "") ? statusText + ", " + customText : statusText + customText + } + tertiaryText { + maximumLineCount: 1 + text: user.type["@type"] === "userTypeBot" ? (Emoji.emojify("🤖 "+bot_info.description, tertiaryText.font.pixelSize)) : Functions.getChatPartnerStatusText(user.status["@type"], user.status.was_online); + elide: Text.ElideRight + } + + onClicked: { + tdLibWrapper.createPrivateChat(user_id); + } + } + footer: Component { + Item { + property bool active: tabBase.active && chatInformationPage.isSuperGroup && (groupInformation.member_count > membersView.count) + width: tabBase.width + height: active ? Theme.itemSizeLarge : Theme.paddingMedium + + BusyIndicator { + id: loadMoreIndicator + anchors.centerIn: parent + size: BusyIndicatorSize.Small + running: parent.active + } + } + } + + VerticalScrollDecorator {} + } + + + DelegateModel { + id: delegateModel + model: chatListModel + groups: [ + DelegateModelGroup { + name: "filterGroup"; includeByDefault: true + } + ] + filterOnGroup: "filterGroup" + function hasMatch(searchInArray) { + for (var i = 0; i < searchInArray.length; i++) { + if(searchInArray[i].toLowerCase().indexOf(chatInformationPage.searchString) > -1) { + return true; + } + } + return false; + } + + function applyFilter(){ + var numberOfEntries = chatListModel.rowCount(); + var hasFilterString = !!chatInformationPage.searchString && chatInformationPage.searchString !== "" + for (var i = 0; i < numberOfEntries; i++){ + var metadata = chatListModel.get(i); + if(tabBase.chatPartnerCommonGroupsIds.indexOf(metadata.chat_id) > -1) { + items.addGroups(i, 1, "filterGroup"); + } else { + items.removeGroups(i, 1, "filterGroup"); + } + + } + } + + delegate: ChatListViewItem { + ownUserId: chatInformationPage.myUserId + + unreadCount: unread_count + onClicked: { + pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate); + pageStack.push(Qt.resolvedUrl("../../pages/ChatPage.qml"), { "chatInformation" : display }); + } + Connections { + target: chatListModel + onChatChanged: { + if (changedChatId === chat_id) { + // Force update of some list item elements (currently only last message text seems to create problems). dataChanged() doesn't seem to trigger them all :( + secondaryText.text = last_message_text ? Emoji.emojify(last_message_text, Theme.fontSizeExtraSmall) : qsTr("Unknown") + } + } + } + } + } + + Timer { + id: fetchMoreMembersTimer + interval: 600 + property int fetchLimit: 50 + onTriggered: { + if(isSuperGroup) { + tabBase.loading = true + tdLibWrapper.getSupergroupMembers(chatInformationPage.chatPartnerGroupId, fetchLimit, membersList.count); + fetchLimit = 200 + interval = 400 + } + } + } + + Connections { + target: tdLibWrapper + + onChatMembersReceived: { + if (isSuperGroup && chatInformationPage.chatPartnerGroupId === extra) { + if(members && members.length > 0) { + for(var memberIndex in members) { + var memberData = members[memberIndex]; + var userInfo = tdLibWrapper.getUserInformation(memberData.user_id) || {user:{}, bot_info:{}}; + memberData.user = userInfo; + memberData.bot_info = memberData.bot_info || {}; + membersList.append(memberData); + } + groupInformation.member_count = totalMembers + updateGroupStatusText(); + if(membersList.count < totalMembers) { +// fetchMoreMembersTimer.start() + } + } + // if we set it directly, the views start scrolling + loadedTimer.start(); + } + } + onChatsReceived: {// common chats with user + if(isPrivateChat && chats["@extra"] === chatInformationPage.chatPartnerGroupId) { + tabBase.chatPartnerCommonGroupsIds = chats.chat_ids; + delegateModel.applyFilter(); + // if we set it directly, the views start scrolling + loadedTimer.start(); + } + } + } + Timer { + id: loadedTimer + interval: 50 + onTriggered: { + tabBase.loading = false + } + } + + Component.onCompleted: { + if(isPrivateChat) { + tdLibWrapper.getGroupsInCommon(chatInformationPage.chatPartnerGroupId, 200, 0); // we only use the first 200 + } else if(isSuperGroup) { + fetchMoreMembersTimer.start(); + } + } + +} diff --git a/qml/components/chatInformationPage/ChatInformationTabItemSettings.qml b/qml/components/chatInformationPage/ChatInformationTabItemSettings.qml new file mode 100644 index 0000000..05b2454 --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTabItemSettings.qml @@ -0,0 +1,70 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import QtQml.Models 2.3 + +import "../" +import "../../pages" +import "../../js/twemoji.js" as Emoji +import "../../js/functions.js" as Functions + +ChatInformationTabItemBase { + id: tabBase + title: qsTr("Settings", "Button: Chat Settings") + image: "image://theme/icon-m-developer-mode" + + SilicaFlickable { + height: tabBase.height + width: tabBase.width + contentHeight: contentColumn.height + Column { + id: contentColumn + width: tabBase.width + + //permissions + + // if chatInformationPage.chatInformation.permissions.can_change_info + // - upload/change chat photo/VIDEO (hahaha) + // - description change + // - toggleSupergroupIsAllHistoryAvailable + // if ?????? can_promote_members ???? can_restrict_members + // - setChatMemberStatus + // if creator (BasicGroup) + // - upgradeBasicGroupChatToSupergroupChat + // if creator (supergroup/channel) + // - canTransferOwnership? + // - transferChatOwnership + Loader { + active: (chatInformationPage.isBasicGroup || chatInformationPage.isSuperGroup) && chatInformationPage.groupInformation && (chatInformationPage.groupInformation.status.can_restrict_members || chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator") + asynchronous: true + source: "./EditGroupChatPermissionsColumn.qml" + width: parent.width + } + + Loader { + active: chatInformationPage.isSuperGroup && chatInformationPage.groupInformation && chatInformationPage.groupInformation.status.can_restrict_members || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator" + asynchronous: true + source: "./EditSuperGroupSlowModeColumn.qml" + width: parent.width + } + + } + } +} diff --git a/qml/components/chatInformationPage/ChatInformationTabView.qml b/qml/components/chatInformationPage/ChatInformationTabView.qml new file mode 100644 index 0000000..6d4467c --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTabView.qml @@ -0,0 +1,169 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +import "./" +import "../" +import "../../pages" + +Item { + id: tabViewItem + property alias count: tabView.count + height: Screen.width + opacity: count > 0 ? 1.0 : 0.0 + Behavior on height { PropertyAnimation {duration: 300}} + Behavior on opacity { PropertyAnimation {duration: 300}} + + Item { + id: tabViewHeader + /* + * Tab view is prepared, but "disabled" for now + * to view shared media/links/…, + * we need message search with filters + */ + + // START: change this to enable + height: visible ? headerGrid.height : 0 +// height: 0 + clip: true + visible: tabView.count > 1 + // END: change this to enable + + anchors { + left: parent.left + right: parent.right + top: parent.top + } + + Grid { + id: headerGrid + width: parent.width + columns: tabView.count + Repeater { + model: tabView.count + delegate: BackgroundItem { + id: headerItem + property bool loaded: tabItem.image !== "" && tabItem.title !== "" + width: loaded ? (headerGrid.width / tabView.count) : 0 + opacity: loaded ? 1.0 : 0.0 + + Behavior on width { PropertyAnimation {duration: 300}} + Behavior on opacity { PropertyAnimation {duration: 300}} + height: Theme.itemSizeLarge + property ChatInformationTabItemBase tabItem: tabView.model.get(index) + property int itemIndex: index + property bool itemIsActive: tabItem.active + Icon { + id: headerIcon + source: headerItem.tabItem.image + highlighted: headerItem.pressed || headerItem.itemIsActive + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + } + Label { + text: headerItem.tabItem.title// + headerItem.itemIsActive + width: parent.width + horizontalAlignment: Text.AlignHCenter + anchors.top: headerIcon.bottom + highlighted: headerItem.pressed || headerItem.itemIsActive + font.pixelSize: Theme.fontSizeTiny + } + onClicked: { + chatInformationPage.scrollDown() + tabView.openTab(itemIndex) + } + } + } + } + } + + ListView { + id: tabView + orientation: ListView.Horizontal + clip: true + snapMode: ListView.SnapOneItem + highlightRangeMode: ListView.StrictlyEnforceRange + highlightFollowsCurrentItem: true + boundsBehavior: Flickable.StopAtBounds + currentIndex: 0 + highlightMoveDuration: 500 + property int maxHeight: tabViewItem.height - tabViewHeader.height + + + anchors { + top: tabViewHeader.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + + function openTab(index) { + currentIndex = index; + } + model: VisualItemModel { + id: tabModel + } + } + Component { + id: membersGroupComponent + ChatInformationTabItemMembersGroups{ + width: tabView.width + } + } + Component { + id: settingsComponent + ChatInformationTabItemSettings { + width: tabView.width + } + } + Component { + id: debugComponent + ChatInformationTabItemDebug { + width: tabView.width + } + } + property var tabItems: { + var items = []; + if(!(isPrivateChat && chatPartnerGroupId === myUserId.toString())) { + items.push(membersGroupComponent); + } + if(!isPrivateChat && (groupInformation.status.can_restrict_members || groupInformation.status["@type"] === "chatMemberStatusCreator")) { + items.push(settingsComponent); + } +// items.push(debugComponent); + + return items; + } + onTabItemsChanged: fillTabItems() + + function fillTabItems() { + tabModel.clear() + for(var i in tabItems) { + tabModel.append(tabItems[i].createObject(tabModel)); + } + } + + Component.onCompleted: { + fillTabItems() + } + +} diff --git a/qml/components/chatInformationPage/ChatInformationTextItem.qml b/qml/components/chatInformationPage/ChatInformationTextItem.qml new file mode 100644 index 0000000..46c250c --- /dev/null +++ b/qml/components/chatInformationPage/ChatInformationTextItem.qml @@ -0,0 +1,74 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + +import "../../js/twemoji.js" as Emoji +import "../../js/functions.js" as Functions + +Column { + id: textItem + property alias headerText: headerItem.text + property string text + property bool isLinkedLabel // for telephone number + width: parent.width + visible: !!text + SectionHeader { + id: headerItem + visible: text !== "" && labelLoader.status === Loader.Ready && labelLoader.item.text !== "" + height: visible ? Theme.itemSizeSmall : 0 + x: 0 + } + Loader { + id: labelLoader + active: true + asynchronous: true + sourceComponent: textItem.isLinkedLabel ? linkedLabelComponent : labelComponent + width: textItem.width + } + + Component { + id: labelComponent + Label { + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + font.pixelSize: Theme.fontSizeExtraSmall + textFormat: Text.StyledText + color: Theme.highlightColor + text: Emoji.emojify( Functions.replaceUrlsWithLinks(textItem.text).replace(/\n/g, "
"), Theme.fontSizeExtraSmall).replace(/\.\.\/js/g, "../../js") + linkColor: Theme.primaryColor + visible: text !== "" + onLinkActivated: { + Functions.handleLink(link); + } + } + } + Component { + id: linkedLabelComponent + LinkedLabel { + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + font.pixelSize: Theme.fontSizeExtraSmall + textFormat: Text.StyledText + plainText: textItem.text + visible: textItem.text !== "" + onLinkActivated: { + Functions.handleLink(link); + } + } + } +} diff --git a/qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml b/qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml new file mode 100644 index 0000000..b085ae4 --- /dev/null +++ b/qml/components/chatInformationPage/EditGroupChatPermissionsColumn.qml @@ -0,0 +1,148 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + + +Column { + id: chatPermissionsColumn + + function setChatPermissions(textSwitchItem) { + if(textSwitchItem.busy) {return;} + var messageSubItems = ["can_send_media_messages", "can_send_polls", "can_send_other_messages", "can_add_web_page_previews"]; + var permissionName = textSwitchItem.permissionName; + var permissionValue = !textSwitchItem.checked + textSwitchItem.busy = true; + var newPermissions = chatInformationPage.chatInformation.permissions; + if(permissionName in newPermissions) { + newPermissions[permissionName] = permissionValue; + // some permissions infer can_send_messages: + if(permissionName === "can_send_messages" && !permissionValue) { + for(var i in messageSubItems) { + newPermissions[messageSubItems[i]] = false; + } + } else if(messageSubItems.indexOf(permissionName) > -1 && permissionValue) { + newPermissions.can_send_message = true; + } + } + tdLibWrapper.setChatPermissions(chatInformationPage.chatInformation.id, newPermissions); + } + + Column { + visible: chatInformationPage.groupInformation.status.can_restrict_members || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator" + width: parent.width + + SectionHeader { + text: qsTr("Group Member Permissions", "what can normal group members do") + } + TextSwitch { + automaticCheck: false + property string permissionName: "can_send_messages" + text: qsTr("Send Messages", "member permission") + checked: chatInformationPage.chatInformation.permissions[permissionName] + onCheckedChanged: {busy = false;} + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + TextSwitch { + automaticCheck: false + property string permissionName: "can_send_media_messages" + text: qsTr("Send Media Messages", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + + TextSwitch { + automaticCheck: false + property string permissionName: "can_send_other_messages" + text: qsTr("Send Other Messages", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + + TextSwitch { + automaticCheck: false + property string permissionName: "can_add_web_page_previews" + text: qsTr("Add Web Page Previews", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + + TextSwitch { + automaticCheck: false + property string permissionName: "can_change_info" + text: qsTr("Change Chat Info", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + + TextSwitch { + automaticCheck: false + property string permissionName: "can_invite_users" + text: qsTr("Invite Users", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + + TextSwitch { + automaticCheck: false + property string permissionName: "can_pin_messages" + text: qsTr("Pin Messages", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.chatInformation.permissions[permissionName] + onClicked: { + chatPermissionsColumn.setChatPermissions(this) + } + } + } + + SectionHeader { + visible: historyAvailableSwitch.visible + text: qsTr("New Members", "what can new group members do") + } + + + TextSwitch { + id: historyAvailableSwitch + visible: chatInformationPage.isSuperGroup && chatInformationPage.groupInformation.status && chatInformationPage.groupInformation.status.can_change_info + automaticCheck: false + text: qsTr("New members can see older messages", "member permission") + onCheckedChanged: {busy = false;} + checked: chatInformationPage.groupFullInformation.is_all_history_available + onClicked: { + tdLibWrapper.toggleSupergroupIsAllHistoryAvailable(chatInformationPage.chatPartnerGroupId, !checked); + } + } +} diff --git a/qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml b/qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml new file mode 100644 index 0000000..bada085 --- /dev/null +++ b/qml/components/chatInformationPage/EditSuperGroupSlowModeColumn.qml @@ -0,0 +1,52 @@ +/* + Copyright (C) 2020 Sebastian J. Wolf + + 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 . +*/ +import QtQuick 2.6 +import Sailfish.Silica 1.0 + + +Column { + SectionHeader { + text: qsTr("Slow Mode") + } + + Slider { + width: parent.width + Theme.horizontalPageMargin * 2 + x: -Theme.horizontalPageMargin + property var presetValues: [0, 10, 30, 60, 300, 900, 3600] + property int realValue: chatInformationPage.groupFullInformation.slow_mode_delay + property int realValueIndex: presetValues.indexOf(realValue) > -1 ? presetValues.indexOf(realValue) : 0 + value: realValueIndex + minimumValue: 0 + maximumValue: presetValues.length - 1 + stepSize: 1 + valueText: value === 0 ? qsTr("Off") : Format.formatDuration(presetValues[value], presetValues[value] < 3600 ? Formatter.DurationShort : Formatter.DurationLong); + onPressedChanged: { + if(!pressed && value !== realValueIndex) { + tdLibWrapper.setChatSlowModeDelay(chatInformationPage.chatInformation.id, presetValues[value]); + } + } + } + Label { + text: qsTr("Set how long every chat member has to wait between Messages") + width: parent.width - Theme.horizontalPageMargin * 2 + x: Theme.horizontalPageMargin + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryHighlightColor + } +} diff --git a/qml/js/functions.js b/qml/js/functions.js index ccf66f0..b8a795c 100644 --- a/qml/js/functions.js +++ b/qml/js/functions.js @@ -94,8 +94,46 @@ function getMessageText(message, simple, myself) { if (message.content['@type'] === 'messageChatDeleteMember') { return myself ? qsTr("left this chat", "myself") : qsTr("left this chat"); } + if (message.content['@type'] === 'messageChatChangeTitle') { + return myself ? qsTr("changed the chat title to %1", "myself").arg(message.content.title) : qsTr("changed the chat title to %1").arg(message.content.title); + } return qsTr("Unsupported message: %1").arg(message.content['@type'].substring(7)); } + +function getChatPartnerStatusText(statusType, was_online) { + switch(statusType) { + case "userStatusEmpty": + return qsTr("was never online"); + case "userStatusLastMonth": + return qsTr("offline, last online: last month"); + case "userStatusLastWeek": + return qsTr("offline, last online: last week"); + case "userStatusOffline": + return qsTr("offline, last online: %1").arg(getDateTimeElapsed(was_online)); + case "userStatusOnline": + return qsTr("online"); + case "userStatusRecently": + return qsTr("offline, was recently online"); + } +} +function getChatMemberStatusText(statusType) { +// chatMemberStatusAdministrator, chatMemberStatusBanned, chatMemberStatusCreator, chatMemberStatusLeft, chatMemberStatusMember, and chatMemberStatusRestricted. + switch(statusType) { + case "chatMemberStatusAdministrator": + return qsTr("Admin", "channel user role"); + case "chatMemberStatusBanned": + return qsTr("Banned", "channel user role"); + case "chatMemberStatusCreator": + return qsTr("Creator", "channel user role"); + case "chatMemberStatusRestricted": + return qsTr("Restricted", "channel user role"); + case "chatMemberStatusLeft": + case "chatMemberStatusMember": + return "" + } + return statusType || ""; +} + function getShortenedCount(count) { if (count >= 1000000) { return qsTr("%1M").arg((count / 1000000).toLocaleString(Qt.locale(), 'f', 0)); @@ -226,3 +264,6 @@ function getVideoHeight(videoWidth, videoData) { return 1; } } +function replaceUrlsWithLinks(string) { + return string.replace(/((\w+):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, "$1"); +} diff --git a/qml/pages/ChatInformationPage.qml b/qml/pages/ChatInformationPage.qml new file mode 100644 index 0000000..79e3376 --- /dev/null +++ b/qml/pages/ChatInformationPage.qml @@ -0,0 +1,463 @@ +import QtQuick 2.6 +import Sailfish.Silica 1.0 +import "../components" +import "../components/chatInformationPage" +import "../js/twemoji.js" as Emoji +import "../js/functions.js" as Functions + +Page { + id: chatInformationPage + + allowedOrientations: Orientation.All + property string searchString + + property int chatOnlineMemberCount: 0; + property int myUserId: tdLibWrapper.getUserInformation().id; + + property bool isPrivateChat: false + property bool isBasicGroup: false + property bool isSuperGroup: false + property bool isChannel: false + + property string chatPartnerGroupId + + property bool userIsMember: (isPrivateChat && chatInformation["@type"]) || // should be optimized + (isBasicGroup || isSuperGroup) && ( + (groupInformation.status["@type"] === "chatMemberStatusMember") + || (groupInformation.status["@type"] === "chatMemberStatusAdministrator") + || (groupInformation.status["@type"] === "chatMemberStatusRestricted" && groupInformation.status.is_member) + || (groupInformation.status["@type"] === "chatMemberStatusCreator" && groupInformation.status.is_member) + ) + + property variant chatInformation:({}); + property variant privateChatUserInformation:({}); + property variant chatPartnerFullInformation:({}); + property variant chatPartnerProfilePhotos:([]); + property variant groupInformation: ({}); + property variant groupFullInformation: ({}); + + property alias membersList: membersList + + function initializePage() { + console.log("[ChatInformationPage] Initializing chat info page..."); + membersList.clear(); + var chatType = chatInformation.type["@type"]; + switch(chatType) { + case "chatTypePrivate": + isPrivateChat = true; + chatInformationPage.chatPartnerGroupId = chatInformation.type.user_id.toString(); + if(!privateChatUserInformation.id) { + privateChatUserInformation = tdLibWrapper.getUserInformation(chatInformationPage.chatPartnerGroupId); + } + tdLibWrapper.getUserFullInfo(chatInformationPage.chatPartnerGroupId); + tdLibWrapper.getUserProfilePhotos(chatInformationPage.chatPartnerGroupId, 100, 0); + break; + case "chatTypeBasicGroup": + isBasicGroup = true; + chatInformationPage.chatPartnerGroupId = chatInformation.type.basic_group_id.toString(); + if(!groupInformation.id) { + groupInformation = tdLibWrapper.getBasicGroup(chatInformationPage.chatPartnerGroupId); + } + tdLibWrapper.getGroupFullInfo(chatInformationPage.chatPartnerGroupId, false); + break; + case "chatTypeSupergroup": + isSuperGroup = true; + chatInformationPage.chatPartnerGroupId = chatInformation.type.supergroup_id.toString(); + if(!groupInformation.id) { + groupInformation = tdLibWrapper.getSuperGroup(chatInformationPage.chatPartnerGroupId); + } + + tdLibWrapper.getGroupFullInfo(chatInformationPage.chatPartnerGroupId, true); + isChannel = groupInformation.is_channel; + break; + } + if(!isPrivateChat) { + updateGroupStatusText(); + } + } + function scrollUp(force) { + if(force) { + // animation does not always work while quick scrolling + scrollUpTimer.start() + } else { + scrollUpAnimation.start() + } + } + function scrollDown(force) { + if(force) { + scrollDownTimer.start() + } else { + scrollDownAnimation.start() + } + } + function handleBasicGroupFullInfo(groupFullInfo) { + groupFullInformation = groupFullInfo; + membersList.clear(); + if(groupFullInfo.members && groupFullInfo.members.length > 0) { + for(var memberIndex in groupFullInfo.members) { + var memberData = groupFullInfo.members[memberIndex]; + var userInfo = tdLibWrapper.getUserInformation(memberData.user_id) || {user:{}, bot_info:{}}; + memberData.user = userInfo; + memberData.bot_info = memberData.bot_info || {}; + membersList.append(memberData); + } + groupInformation.member_count = groupFullInfo.members.length + updateGroupStatusText(); + } + } + + Connections { + target: tdLibWrapper + + onChatOnlineMemberCountUpdated: { + if ((isSuperGroup || isBasicGroup) && chatInformation.id.toString() === chatId) { + chatOnlineMemberCount = onlineMemberCount; + updateGroupStatusText(); + } + } + onSupergroupFullInfoReceived: { + if(isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) { + groupFullInformation = groupFullInfo; + } + } + onSupergroupFullInfoUpdated: { + if(isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) { + groupFullInformation = groupFullInfo; + } + } + onBasicGroupFullInfoReceived: { + if(isBasicGroup && chatInformationPage.chatPartnerGroupId === groupId) { + handleBasicGroupFullInfo(groupFullInfo) + } + } + + onBasicGroupFullInfoUpdated: { + if(isBasicGroup && chatInformationPage.chatPartnerGroupId === groupId) { + handleBasicGroupFullInfo(groupFullInfo) + } + } + onUserFullInfoReceived: { + if(isPrivateChat && userFullInfo["@extra"] === chatInformationPage.chatPartnerGroupId) { + chatPartnerFullInformation = userFullInfo; + } + } + onUserFullInfoUpdated: { + if(isPrivateChat && userId === chatInformationPage.chatPartnerGroupId) { + chatPartnerFullInformation = userFullInfo; + } + } + + onUserProfilePhotosReceived: { + if(isPrivateChat && extra === chatInformationPage.chatPartnerGroupId) { + chatPartnerProfilePhotos = photos; + } + } + onChatPermissionsUpdated: { + if (chatInformation.id.toString() === chatId) { + // set whole object to trigger change + var newInformation = chatInformation; + newInformation.permissions = permissions + chatInformation = newInformation + } + } + onChatTitleUpdated: { + if (chatInformation.id.toString() === chatId) { + // set whole object to trigger change + var newInformation = chatInformation; + newInformation.title = title + chatInformation = newInformation + } + } + } + Component.onCompleted: initializePage(); + + ListModel { + id: membersList + } + + AppNotification { + id: infoNotification + } + SilicaFlickable { + id: pageFlickable + anchors.fill: parent + + PullDownMenu { + MenuItem { + visible: (isBasicGroup || isSuperGroup) && userIsMember + text: qsTr("Leave Group") + onClicked: { + // ensure it's done even if the page is closed: + var remorse = Remorse.popupAction(appWindow, qsTr("Leaving chat"), (function(chatid) { + return 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)} )); + }; + }(chatInformation.id.toString()))) + } + } + MenuItem { + visible: userIsMember + onClicked: { + var newNotificationSettings = chatInformation.notification_settings; + if (newNotificationSettings.mute_for > 0) { + newNotificationSettings.mute_for = 0; + } else { + newNotificationSettings.mute_for = 6666666; + } + tdLibWrapper.setChatNotificationSettings(chat_id, newNotificationSettings); + } + text: chatInformation.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat") + } + // MenuItem { //TODO Implement + // visible: !userIsMember + // onClicked: { + // tdLibWrapper.joinChat(chat_id); + // } + // text: qsTr("Join Chat") + // } + } + // header + PageHeader { + id: headerItem + z: 5 + Item { + id: imageContainer + property bool hasImage: typeof chatInformation.photo !== "undefined" + property int minDimension: chatInformationPage.isLandscape ? Theme.itemSizeSmall : Theme.itemSizeMedium + property int maxDimension: Screen.width / 2 + property int minX: Theme.horizontalPageMargin + property int maxX: (chatInformationPage.width - maxDimension)/2 + property int minY: (parent.height - minDimension)/2 + property int maxY: parent.height + property double tweenFactor: { + if(!hasImage) { + return 0 + } + return 1 - Math.max(0, Math.min(1, contentFlickable.contentY / maxDimension)) + } + + function getEased(min,max,factor) { + return min + (max-min)*factor + } + width: getEased(minDimension,maxDimension, tweenFactor) + height: width + x: getEased(minX,maxX, tweenFactor) + y: getEased(minY,maxY, tweenFactor) + + ProfileThumbnail { + id: chatPictureThumbnail + photoData: imageContainer.hasImage ? chatInformation.photo.small : "" + replacementStringHint: headerItem.title + width: parent.width + height: width + radius: imageContainer.minDimension / 2 + opacity: profilePictureLoader.status !== Loader.Ready || profilePictureLoader.item.opacity < 1 ? 1.0 : 0.0 + } + Loader { + id: profilePictureLoader + active: imageContainer.hasImage + asynchronous: true + anchors.fill: chatPictureThumbnail + source: chatInformationPage.isPrivateChat + ? "../components/chatInformationPage/ChatInformationProfilePictureList.qml" + : "../components/chatInformationPage/ChatInformationProfilePicture.qml" + } + } + leftMargin: imageContainer.minDimension + Theme.horizontalPageMargin + Theme.paddingMedium + title: chatInformation.title !== "" ? Emoji.emojify(chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown") + description: chatInformationPage.isPrivateChat ? ("@"+(chatInformationPage.privateChatUserInformation.username || chatInformationPage.chatPartnerGroupId)) : "" + } + + SilicaFlickable { + id: contentFlickable + contentHeight: groupInfoItem.height + tabViewLoader.height + clip: true + interactive: true//groupInfoItem.height > pageFlickable.height * 0.5 + + anchors { + top: headerItem.bottom + bottom: parent.bottom + left: parent.left + right: parent.right + } + NumberAnimation { + id: scrollDownAnimation + target: contentFlickable + to: groupInfoItem.height + property: "contentY" + duration: 500 + easing.type: Easing.InOutCubic + } + NumberAnimation { + id: scrollUpAnimation + target: contentFlickable + to: 0 + property: "contentY" + duration: 500 + easing.type: Easing.InOutCubic + property Timer scrollUpTimer: Timer { + id: scrollUpTimer + interval: 50 + onTriggered: { + contentFlickable.scrollToTop() + } + } + property Timer scrollDownTimer: Timer { + id: scrollDownTimer + interval: 50 + onTriggered: { + contentFlickable.scrollToBottom() + } + } + } + + Column { + id: groupInfoItem + bottomPadding: Theme.paddingLarge + topPadding: Theme.paddingLarge + anchors { + top: parent.top + left: parent.left + leftMargin: Theme.horizontalPageMargin + right: parent.right + rightMargin: Theme.horizontalPageMargin + } + + Item { //large image placeholder + width: parent.width + height: imageContainer.hasImage ? imageContainer.maxDimension : 0 + } + + ChatInformationEditArea { + visible: canEdit + canEdit: !chatInformationPage.isPrivateChat && chatInformationPage.groupInformation.status && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator") + headerText: qsTr("Chat Title", "group title header") + text: chatInformation.title + + onSaveButtonClicked: { + if(!editItem.errorHighlight) { + tdLibWrapper.setChatTitle(chatInformationPage.chatInformation.id, textValue); + } else { + isEditing = true + } + } + + onTextEdited: { + if(textValue.length > 0 && textValue.length < 129) { + editItem.errorHighlight = false + editItem.label = "" + editItem.placeholderText = "" + } else { + editItem.label = qsTr("Enter 1-128 characters") + editItem.placeholderText = editItem.label + editItem.errorHighlight = true + } + } + } + ChatInformationEditArea { + canEdit: (chatInformationPage.isPrivateChat && chatInformationPage.privateChatUserInformation.id === chatInformationPage.myUserId) || ((chatInformationPage.isBasicGroup || chatInformationPage.isSuperGroup) && chatInformationPage.groupInformation && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator")) + emptyPlaceholderText: qsTr("There is no information text available, yet.") + headerText: qsTr("Info", "group or user infotext header") + multiLine: true + text: (chatInformationPage.isPrivateChat ? chatInformationPage.chatPartnerFullInformation.bio : chatInformationPage.groupFullInformation.description) || "" + onSaveButtonClicked: { + if(chatInformationPage.isPrivateChat) { // own bio + tdLibWrapper.setBio(textValue); + } else { // group info + tdLibWrapper.setChatDescription(chatInformationPage.chatInformation.id, textValue); + } + } + } + + ChatInformationTextItem { + headerText: qsTr("Phone Number", "user phone number header") + text: (chatInformationPage.isPrivateChat && chatInformationPage.privateChatUserInformation.phone_number ? "+"+chatInformationPage.privateChatUserInformation.phone_number : "") || "" + isLinkedLabel: true + } + + SectionHeader { + font.pixelSize: Theme.fontSizeExtraSmall + visible: !!inviteLinkItem.text + height: visible ? Theme.itemSizeExtraSmall : 0 + text: qsTr("Invite Link", "header") + x: 0 + } + + Row { + width: parent.width + visible: !!inviteLinkItem.text + ChatInformationTextItem { + id: inviteLinkItem + text: !isPrivateChat ? groupFullInformation.invite_link : "" + width: parent.width - inviteLinkButton.width + } + IconButton { + id: inviteLinkButton + icon.source: "image://theme/icon-m-clipboard" + anchors.verticalCenter: inviteLinkItem.verticalCenter + onClicked: { + inviteLinkField.selectAll(); + inviteLinkField.copy(); + inviteLinkField.select(0,0); + infoNotification.show(qsTr("The Invite Link has been copied to the clipboard.")); + } + TextField { + id: inviteLinkField + width: 0 + height: 0 + text: groupFullInformation.invite_link ? groupFullInformation.invite_link : "" + visible: false + readOnly: true + opacity: 0 + } + } + } + + Item { + width: parent.width + height: Theme.paddingLarge + } + + Separator { + width: parent.width + color: Theme.primaryColor + horizontalAlignment: Qt.AlignHCenter + opacity: (tabViewLoader.status === Loader.Ready && tabViewLoader.item.count > 0) ? 1.0 : 0.0 + + Behavior on opacity { PropertyAnimation {duration: 500}} + } + } + + Loader { + id: tabViewLoader + asynchronous: true + active: true + anchors { + left: parent.left + right: parent.right + top: groupInfoItem.bottom + } + sourceComponent: Component { + ChatInformationTabView { + id: tabView + height: tabView.count > 0 ? chatInformationPage.height - headerItem.height : 0 + } + } + } + } + } + function updateGroupStatusText() { + if (chatOnlineMemberCount > 0) { + headerItem.description = qsTr("%1 members, %2 online").arg(Functions.getShortenedCount(groupInformation.member_count)).arg(Functions.getShortenedCount(chatOnlineMemberCount)); + } else { + if (isChannel) { + headerItem.description = qsTr("%1 subscribers").arg(Functions.getShortenedCount(groupInformation.member_count)); + } else { + headerItem.description = qsTr("%1 members").arg(Functions.getShortenedCount(groupInformation.member_count)); + } + } + } + +} diff --git a/qml/pages/ChatPage.qml b/qml/pages/ChatPage.qml index c108784..ac5da91 100644 --- a/qml/pages/ChatPage.qml +++ b/qml/pages/ChatPage.qml @@ -46,23 +46,9 @@ Page { property variant emojiProposals; function updateChatPartnerStatusText() { - if (chatPartnerInformation.status['@type'] === "userStatusEmpty" ) { - chatStatusText.text = qsTr("was never online"); - } - if (chatPartnerInformation.status['@type'] === "userStatusLastMonth" ) { - chatStatusText.text = qsTr("offline, last online: last month"); - } - if (chatPartnerInformation.status['@type'] === "userStatusLastWeek" ) { - chatStatusText.text = qsTr("offline, last online: last week"); - } - if (chatPartnerInformation.status['@type'] === "userStatusOffline" ) { - chatStatusText.text = qsTr("offline, last online: %1").arg(Functions.getDateTimeElapsed(chatPartnerInformation.status.was_online)); - } - if (chatPartnerInformation.status['@type'] === "userStatusOnline" ) { - chatStatusText.text = qsTr("online"); - } - if (chatPartnerInformation.status['@type'] === "userStatusRecently" ) { - chatStatusText.text = qsTr("offline, was recently online"); + var statusText = Functions.getChatPartnerStatusText(chatPartnerInformation.status['@type'], chatPartnerInformation.status.was_online); + if(statusText) { + chatStatusText.text = statusText; } } @@ -109,6 +95,9 @@ Page { function getMessageStatusText(message, listItemIndex, lastReadSentIndex) { var messageStatusSuffix = ""; + if(!message) { + return ""; + } if (message.edit_date > 0) { messageStatusSuffix += " - " + qsTr("edited"); @@ -221,19 +210,26 @@ Page { initializePage(); } + Component.onDestruction: { + tdLibWrapper.closeChat(chatInformation.id); + } + onStatusChanged: { - if (status === PageStatus.Activating) { + switch(status) { + case PageStatus.Activating: tdLibWrapper.openChat(chatInformation.id); - } - if (status === PageStatus.Active) { + break; + case PageStatus.Active: + console.log("CHAT opendirectly?", chatPage.isInitialized) if (!chatPage.isInitialized) { chatModel.initialize(chatInformation); chatPage.isInitialized = true; } + break; +// case PageStatus.Deactivating: +// tdLibWrapper.closeChat(chatInformation.id); } - if (status === PageStatus.Deactivating) { - tdLibWrapper.closeChat(chatInformation.id); - } + } Connections { @@ -277,6 +273,14 @@ Page { target: chatModel onMessagesReceived: { console.log("[ChatPage] Messages received, view has " + chatView.count + " messages, setting view to index " + modelIndex + ", own messages were read before index " + lastReadSentIndex); + if(totalCount === 0) { + console.log("[ChatPage] actually, skipping that: No Messages in Chat."); + + chatView.positionViewAtEnd(); + chatPage.loading = false; + return; + } + chatView.lastReadSentIndex = lastReadSentIndex; if (modelIndex === (chatView.count - 1)) { chatView.positionViewAtEnd(); @@ -336,7 +340,7 @@ Page { Timer { id: chatContactTimeUpdater interval: 60000 - running: true + running: isPrivateChat repeat: true onTriggered: { updateChatPartnerStatusText(); @@ -373,7 +377,14 @@ Page { muteChatMenuItem.text = chatInformation.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat"); } } - + BackgroundItem { + id: headerMouseArea + height: headerRow.height + width: parent.width + onClicked: { + pageStack.push(Qt.resolvedUrl("../pages/ChatInformationPage.qml"), { "chatInformation" : chatInformation, "privateChatUserInformation": chatPartnerInformation, "groupInformation": chatGroupInformation, "chatOnlineMemberCount": chatOnlineMemberCount}); + } + } Column { id: chatColumn width: parent.width @@ -427,7 +438,7 @@ Page { textFormat: Text.StyledText font.pixelSize: Theme.fontSizeExtraSmall font.family: Theme.fontFamilyHeading - color: Theme.secondaryColor + color: headerMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.secondaryColor elide: Text.ElideRight width: parent.width maximumLineCount: 1 @@ -958,6 +969,11 @@ Page { } VerticalScrollDecorator {} + + ViewPlaceholder { + enabled: chatView.count === 0 + text: qsTr("This chat is empty.") + } } Column { @@ -1157,7 +1173,7 @@ Page { property bool isPicture: false; property bool isVideo: false; property bool isDocument: false; - property variant fileProperties; + property variant fileProperties:({}); IconButton { id: removeAttachmentsIconButton diff --git a/qml/pages/OverviewPage.qml b/qml/pages/OverviewPage.qml index bcc452c..67eea4c 100644 --- a/qml/pages/OverviewPage.qml +++ b/qml/pages/OverviewPage.qml @@ -152,6 +152,16 @@ Page { chatListCreatedTimer.restart(); } } + onChatReceived: { + if(chat["@extra"] === "openDirectly") { + console.log("ON CHAT RECEIVED", JSON.stringify(chat, null, 2)); + if (status !== PageStatus.Active) { + pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ), PageStackAction.Immediate); + } + // if we get a new chat (no messages?), we can not use the provided data + pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : tdLibWrapper.getChat(chat.id) }); + } + } } Component.onCompleted: { @@ -219,31 +229,12 @@ Page { Behavior on opacity { NumberAnimation {} } model: chatListModel - delegate: ListItem { - - id: chatListViewItem - - contentHeight: chatListRow.height + chatListSeparator.height + 2 * Theme.paddingMedium - contentWidth: parent.width + delegate: ChatListViewItem { + pictureThumbnail.forceElementUpdate: overviewPage.chatListCreated + ownUserId: overviewPage.ownUserId onClicked: { - pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : display }); - } - - showMenuOnPressAndHold: chat_id != overviewPage.ownUserId - menu: ContextMenu { - MenuItem { - onClicked: { - var newNotificationSettings = display.notification_settings; - if (newNotificationSettings.mute_for > 0) { - newNotificationSettings.mute_for = 0; - } else { - newNotificationSettings.mute_for = 6666666; - } - tdLibWrapper.setChatNotificationSettings(chat_id, newNotificationSettings); - } - text: display.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat") - } + pageStack.push(Qt.resolvedUrl("../pages/ChatPage.qml"), { "chatInformation" : display }); } Connections { @@ -251,151 +242,10 @@ Page { onChatChanged: { if (overviewPage.chatListCreated && changedChatId === chat_id) { // Force update of some list item elements (currently only last message text seems to create problems). dataChanged() doesn't seem to trigger them all :( - chatListLastMessageText.text = last_message_text ? Emoji.emojify(last_message_text, Theme.fontSizeExtraSmall) : qsTr("Unknown") + secondaryText.text = last_message_text ? Emoji.emojify(last_message_text, Theme.fontSizeExtraSmall) : qsTr("Unknown") } } } - - Column { - id: chatListColumn - width: parent.width - ( 2 * Theme.horizontalPageMargin ) - spacing: Theme.paddingSmall - anchors { - horizontalCenter: parent.horizontalCenter - verticalCenter: parent.verticalCenter - } - - Row { - id: chatListRow - width: parent.width - height: chatListContentColumn.height - spacing: Theme.paddingMedium - - Column { - id: chatListPictureColumn - width: chatListContentColumn.height - Theme.paddingSmall - height: chatListContentColumn.height - Theme.paddingSmall - anchors.verticalCenter: parent.verticalCenter - - Item { - id: chatListPictureItem - width: parent.width - height: parent.width - - ProfileThumbnail { - id: chatListPictureThumbnail - photoData: photo_small - replacementStringHint: chatListNameText.text - width: parent.width - height: parent.width - forceElementUpdate: overviewPage.chatListCreated - } - - Rectangle { - id: chatUnreadMessagesCountBackground - color: Theme.highlightBackgroundColor - width: Theme.fontSizeLarge - height: Theme.fontSizeLarge - anchors.right: parent.right - anchors.bottom: parent.bottom - radius: parent.width / 2 - visible: unread_count > 0 - } - - Text { - id: chatUnreadMessagesCount - font.pixelSize: Theme.fontSizeExtraSmall - font.bold: true - color: Theme.primaryColor - anchors.centerIn: chatUnreadMessagesCountBackground - visible: chatUnreadMessagesCountBackground.visible - text: unread_count > 99 ? "99+" : unread_count - } - } - } - - Column { - id: chatListContentColumn - width: parent.width * 5 / 6 - Theme.horizontalPageMargin - spacing: Theme.paddingSmall - - Text { - id: chatListNameText - text: title ? Emoji.emojify(title, Theme.fontSizeMedium) + ( display.notification_settings.mute_for > 0 ? Emoji.emojify(" 🔇", Theme.fontSizeMedium) : "" ) : qsTr("Unknown") - textFormat: Text.StyledText - font.pixelSize: Theme.fontSizeMedium - color: Theme.primaryColor - elide: Text.ElideRight - width: parent.width - onTruncatedChanged: { - // There is obviously a bug in QML in truncating text with images. - // We simply remove Emojis then... - if (truncated) { - text = text.replace(/\]+\/\>/g, ""); - } - } - } - - Row { - id: chatListLastMessageRow - width: parent.width - spacing: Theme.paddingSmall - Text { - id: chatListLastUserText - text: is_channel ? "" : ( last_message_sender_id ? ( last_message_sender_id !== overviewPage.ownUserId ? Emoji.emojify(Functions.getUserName(tdLibWrapper.getUserInformation(last_message_sender_id)), font.pixelSize) : qsTr("You") ) : qsTr("Unknown") ) - font.pixelSize: Theme.fontSizeExtraSmall - color: Theme.highlightColor - textFormat: Text.StyledText - onTruncatedChanged: { - // There is obviously a bug in QML in truncating text with images. - // We simply remove Emojis then... - if (truncated) { - text = text.replace(/\]+\/\>/g, ""); - } - } - } - Text { - id: chatListLastMessageText - text: last_message_text ? Emoji.emojify(last_message_text, Theme.fontSizeExtraSmall) : qsTr("Unknown") - font.pixelSize: Theme.fontSizeExtraSmall - color: Theme.primaryColor - width: parent.width - Theme.paddingMedium - chatListLastUserText.width - elide: Text.ElideRight - textFormat: Text.StyledText - onTruncatedChanged: { - // There is obviously a bug in QML in truncating text with images. - // We simply remove Emojis then... - if (truncated) { - text = text.replace(/\]+\/\>/g, ""); - } - } - } - } - - Text { - id: messageContactTimeElapsedText - text: last_message_date ? Functions.getDateTimeElapsed(last_message_date) : qsTr("Unknown") - font.pixelSize: Theme.fontSizeTiny - color: Theme.secondaryColor - } - } - } - - } - - Separator { - id: chatListSeparator - - anchors { - top: chatListColumn.bottom - topMargin: Theme.paddingMedium - } - - width: parent.width - color: Theme.primaryColor - horizontalAlignment: Qt.AlignHCenter - } - } ViewPlaceholder { diff --git a/src/chatlistmodel.cpp b/src/chatlistmodel.cpp index ec33dde..70da9e2 100644 --- a/src/chatlistmodel.cpp +++ b/src/chatlistmodel.cpp @@ -352,6 +352,21 @@ void ChatListModel::redrawModel() layoutChanged(); } +QVariantMap ChatListModel::get(int row) +{ + + QHash names = roleNames(); + QHashIterator i(names); + QVariantMap res; + QModelIndex idx = index(row, 0); + while (i.hasNext()) { + i.next(); + QVariant data = idx.data(i.key()); + res[i.value()] = data; + } + return res; +} + int ChatListModel::updateChatOrder(int chatIndex) { ChatData *chat = chatList.at(chatIndex); diff --git a/src/chatlistmodel.h b/src/chatlistmodel.h index 3f0945d..00aed07 100644 --- a/src/chatlistmodel.h +++ b/src/chatlistmodel.h @@ -37,6 +37,7 @@ public: virtual QVariant data(const QModelIndex &index, int role) const override; Q_INVOKABLE void redrawModel(); + Q_INVOKABLE QVariantMap get(int row); bool showAllChats() const; void setShowAllChats(bool showAll); diff --git a/src/chatmodel.cpp b/src/chatmodel.cpp index 2eb9963..09dfea0 100644 --- a/src/chatmodel.cpp +++ b/src/chatmodel.cpp @@ -28,7 +28,7 @@ ChatModel::ChatModel(TDLibWrapper *tdLibWrapper) this->tdLibWrapper = tdLibWrapper; this->inReload = false; this->inIncrementalUpdate = false; - connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList)), this, SLOT(handleMessagesReceived(QVariantList))); + connect(this->tdLibWrapper, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int))); connect(this->tdLibWrapper, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap))); connect(this->tdLibWrapper, SIGNAL(chatReadInboxUpdated(QString, QString, int)), this, SLOT(handleChatReadInboxUpdated(QString, QString, int))); connect(this->tdLibWrapper, SIGNAL(chatReadOutboxUpdated(QString, QString)), this, SLOT(handleChatReadOutboxUpdated(QString, QString))); @@ -72,9 +72,11 @@ void ChatModel::initialize(const QVariantMap &chatInformation) { qDebug() << "[ChatModel] Initializing chat model..."; this->chatInformation = chatInformation; + beginResetModel(); this->messages.clear(); this->messageIndexMap.clear(); this->messagesToBeAdded.clear(); + endResetModel(); this->chatId = chatInformation.value("id").toString(); tdLibWrapper->getChatHistory(this->chatId); } @@ -113,7 +115,7 @@ bool compareMessages(const QVariant &message1, const QVariant &message2) } } -void ChatModel::handleMessagesReceived(const QVariantList &messages) +void ChatModel::handleMessagesReceived(const QVariantList &messages, const int &totalCount) { qDebug() << "[ChatModel] Receiving new messages :)" << messages.size(); @@ -126,7 +128,7 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages) this->inIncrementalUpdate = false; emit messagesIncrementalUpdate(listInboxPosition, listOutboxPosition); } else { - emit messagesReceived(listInboxPosition, listOutboxPosition); + emit messagesReceived(listInboxPosition, listOutboxPosition, totalCount); } } else { this->messagesMutex.lock(); @@ -157,7 +159,7 @@ void ChatModel::handleMessagesReceived(const QVariantList &messages) this->inIncrementalUpdate = false; emit messagesIncrementalUpdate(listInboxPosition, listOutboxPosition); } else { - emit messagesReceived(listInboxPosition, listOutboxPosition); + emit messagesReceived(listInboxPosition, listOutboxPosition, totalCount); } } } diff --git a/src/chatmodel.h b/src/chatmodel.h index 7f57c7b..2d317e0 100644 --- a/src/chatmodel.h +++ b/src/chatmodel.h @@ -42,7 +42,7 @@ public: Q_INVOKABLE QVariantMap getMessage(const int &index); signals: - void messagesReceived(const int &modelIndex, const int &lastReadSentIndex); + void messagesReceived(const int &modelIndex, const int &lastReadSentIndex, const int &totalCount); void messagesIncrementalUpdate(const int &modelIndex, const int &lastReadSentIndex); void newMessageReceived(const QVariantMap &message); void unreadCountUpdated(const int &unreadCount, const QString &lastReadInboxMessageId); @@ -52,7 +52,7 @@ signals: void messagesDeleted(); public slots: - void handleMessagesReceived(const QVariantList &messages); + void handleMessagesReceived(const QVariantList &messages, const int &totalCount); void handleNewMessageReceived(const QString &chatId, const QVariantMap &message); void handleChatReadInboxUpdated(const QString &chatId, const QString &lastReadInboxMessageId, const int &unreadCount); void handleChatReadOutboxUpdated(const QString &chatId, const QString &lastReadOutboxMessageId); diff --git a/src/fernschreiberutils.cpp b/src/fernschreiberutils.cpp index 2a9ed3d..b52122e 100644 --- a/src/fernschreiberutils.cpp +++ b/src/fernschreiberutils.cpp @@ -51,5 +51,8 @@ QString FernschreiberUtils::getMessageShortText(const QVariantMap &messageConten if (contentType == "messageChatDeleteMember") { return myself ? tr("left this chat", "myself") : tr("left this chat"); } + if (contentType == "messageChatChangeTitle") { + return myself ? tr("changed the chat title", "myself") : tr("changed the chat title"); + } return tr("Unsupported message: %1").arg(contentType.mid(7)); } diff --git a/src/tdlibreceiver.cpp b/src/tdlibreceiver.cpp index 407e633..2debac2 100644 --- a/src/tdlibreceiver.cpp +++ b/src/tdlibreceiver.cpp @@ -41,6 +41,7 @@ namespace { const QString LAST_READ_OUTBOX_MESSAGE_ID("last_read_outbox_message_id"); const QString TYPE("@type"); + const QString EXTRA("@extra"); const QString TYPE_CHAT_POSITION("chatPosition"); const QString TYPE_CHAT_LIST_MAIN("chatListMain"); } @@ -99,11 +100,22 @@ TDLibReceiver::TDLibReceiver(void *tdLibClient, QObject *parent) : QThread(paren handlers.insert("updateMessageContent", &TDLibReceiver::processUpdateMessageContent); handlers.insert("updateDeleteMessages", &TDLibReceiver::processUpdateDeleteMessages); handlers.insert("chats", &TDLibReceiver::processChats); + handlers.insert("chat", &TDLibReceiver::processChat); handlers.insert("updateRecentStickers", &TDLibReceiver::processUpdateRecentStickers); handlers.insert("stickers", &TDLibReceiver::processStickers); handlers.insert("updateInstalledStickerSets", &TDLibReceiver::processUpdateInstalledStickerSets); handlers.insert("stickerSets", &TDLibReceiver::processStickerSets); handlers.insert("stickerSet", &TDLibReceiver::processStickerSet); + handlers.insert("chatMembers", &TDLibReceiver::processChatMembers); + handlers.insert("userFullInfo", &TDLibReceiver::processUserFullInfo); + handlers.insert("updateUserFullInfo", &TDLibReceiver::processUpdateUserFullInfo); + handlers.insert("basicGroupFullInfo", &TDLibReceiver::processBasicGroupFullInfo); + handlers.insert("updateBasicGroupFullInfo", &TDLibReceiver::processUpdateBasicGroupFullInfo); + handlers.insert("supergroupFullInfo", &TDLibReceiver::processSupergroupFullInfo); + handlers.insert("updateSupergroupFullInfo", &TDLibReceiver::processUpdateSupergroupFullInfo); + handlers.insert("userProfilePhotos", &TDLibReceiver::processUserProfilePhotos); + handlers.insert("updateChatPermissions", &TDLibReceiver::processUpdateChatPermissions); + handlers.insert("updateChatTitle", &TDLibReceiver::processUpdateChatTitle); } void TDLibReceiver::setActive(const bool &active) @@ -302,7 +314,7 @@ void TDLibReceiver::processChatOnlineMemberCountUpdated(const QVariantMap &recei void TDLibReceiver::processMessages(const QVariantMap &receivedInformation) { LOG("Received new messages, amount: " << receivedInformation.value("total_count").toString()); - emit messagesReceived(receivedInformation.value("messages").toList()); + emit messagesReceived(receivedInformation.value("messages").toList(), receivedInformation.value("total_count").toInt()); } void TDLibReceiver::processUpdateNewMessage(const QVariantMap &receivedInformation) @@ -375,6 +387,11 @@ void TDLibReceiver::processChats(const QVariantMap &receivedInformation) emit chats(receivedInformation); } +void TDLibReceiver::processChat(const QVariantMap &receivedInformation) +{ + emit chat(receivedInformation); +} + void TDLibReceiver::processUpdateRecentStickers(const QVariantMap &receivedInformation) { LOG("Recent stickers updated"); @@ -404,3 +421,76 @@ void TDLibReceiver::processStickerSet(const QVariantMap &receivedInformation) LOG("Received a sticker set..."); emit stickerSet(receivedInformation); } +void TDLibReceiver::processChatMembers(const QVariantMap &receivedInformation) +{ + LOG("Received super group members"); + const QString extra = receivedInformation.value(EXTRA).toString(); + emit chatMembers(extra, receivedInformation.value("members").toList(), receivedInformation.value("total_count").toInt()); +} + +void TDLibReceiver::processUserFullInfo(const QVariantMap &receivedInformation) +{ + + LOG("Received UserFullInfo"); + + emit userFullInfo(receivedInformation); +} + +void TDLibReceiver::processUpdateUserFullInfo(const QVariantMap &receivedInformation) +{ + + LOG("Received UserFullInfoUpdate"); + + emit userFullInfoUpdated(receivedInformation.value("user_id").toString(), receivedInformation.value("user_full_info").toMap()); +} + +void TDLibReceiver::processBasicGroupFullInfo(const QVariantMap &receivedInformation) +{ + + LOG("Received BasicGroupFullInfo"); + const QString groupId = receivedInformation.value(EXTRA).toString(); + + emit basicGroupFullInfo(groupId, receivedInformation); +} +void TDLibReceiver::processUpdateBasicGroupFullInfo(const QVariantMap &receivedInformation) +{ + LOG("Received BasicGroupFullInfoUpdate"); + const QString groupId = receivedInformation.value("basic_group_id").toString(); + + emit basicGroupFullInfoUpdated(groupId, receivedInformation.value("basic_group_full_info").toMap()); +} + +void TDLibReceiver::processSupergroupFullInfo(const QVariantMap &receivedInformation) +{ + LOG("Received SuperGroupFullInfoUpdate"); + const QString groupId = receivedInformation.value(EXTRA).toString(); + + emit supergroupFullInfo(groupId, receivedInformation); +} + +void TDLibReceiver::processUpdateSupergroupFullInfo(const QVariantMap &receivedInformation) +{ + + LOG("Received SuperGroupFullInfoUpdate"); + const QString groupId = receivedInformation.value("supergroup_id").toString(); + + emit supergroupFullInfoUpdated(groupId, receivedInformation.value("supergroup_full_info").toMap()); +} + +void TDLibReceiver::processUserProfilePhotos(const QVariantMap &receivedInformation) +{ + const QString extra = receivedInformation.value(EXTRA).toString(); + emit userProfilePhotos(extra, receivedInformation.value("photos").toList(), receivedInformation.value("total_count").toInt()); +} + +void TDLibReceiver::processUpdateChatPermissions(const QVariantMap &receivedInformation) +{ + emit chatPermissionsUpdated(receivedInformation.value("chat_id").toString(), receivedInformation.value("permissions").toMap()); +} + +void TDLibReceiver::processUpdateChatTitle(const QVariantMap &receivedInformation) +{ + + LOG("Received UpdateChatTitle"); + emit chatTitleUpdated(receivedInformation.value("chat_id").toString(), receivedInformation.value("title").toString()); +} diff --git a/src/tdlibreceiver.h b/src/tdlibreceiver.h index 8aac1ba..511520b 100644 --- a/src/tdlibreceiver.h +++ b/src/tdlibreceiver.h @@ -53,7 +53,7 @@ signals: void basicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void superGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void messagesReceived(const QVariantList &messages); + void messagesReceived(const QVariantList &messages, const int &totalCount); void newMessageReceived(const QString &chatId, const QVariantMap &message); void messageInformation(const QString &messageId, const QVariantMap &message); void messageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message); @@ -64,12 +64,22 @@ signals: void messageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent); void messagesDeleted(const QString &chatId, const QVariantList &messageIds); void chats(const QVariantMap &chats); + void chat(const QVariantMap &chats); void recentStickersUpdated(const QVariantList &stickerIds); void stickers(const QVariantList &stickers); void installedStickerSetsUpdated(const QVariantList &stickerSetIds); void stickerSets(const QVariantList &stickerSets); void stickerSet(const QVariantMap &stickerSet); - + void chatMembers(const QString &extra, const QVariantList &members, const int &totalMembers); + void userFullInfo(const QVariantMap &userFullInfo); + void userFullInfoUpdated(const QString &userId,const QVariantMap &userFullInfo); + void basicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); + void basicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void supergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); + void supergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void userProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos); + void chatPermissionsUpdated(const QString &chatId, const QVariantMap &chatPermissions); + void chatTitleUpdated(const QString &chatId, const QString &title); private: typedef void (TDLibReceiver::*Handler)(const QVariantMap &); @@ -108,11 +118,22 @@ private: void processUpdateMessageContent(const QVariantMap &receivedInformation); void processUpdateDeleteMessages(const QVariantMap &receivedInformation); void processChats(const QVariantMap &receivedInformation); + void processChat(const QVariantMap &receivedInformation); void processUpdateRecentStickers(const QVariantMap &receivedInformation); void processStickers(const QVariantMap &receivedInformation); void processUpdateInstalledStickerSets(const QVariantMap &receivedInformation); void processStickerSets(const QVariantMap &receivedInformation); void processStickerSet(const QVariantMap &receivedInformation); + void processChatMembers(const QVariantMap &receivedInformation); + void processUserFullInfo(const QVariantMap &receivedInformation); + void processUpdateUserFullInfo(const QVariantMap &receivedInformation); + void processBasicGroupFullInfo(const QVariantMap &receivedInformation); + void processUpdateBasicGroupFullInfo(const QVariantMap &receivedInformation); + void processSupergroupFullInfo(const QVariantMap &receivedInformation); + void processUpdateSupergroupFullInfo(const QVariantMap &receivedInformation); + void processUserProfilePhotos(const QVariantMap &receivedInformation); + void processUpdateChatPermissions(const QVariantMap &receivedInformation); + void processUpdateChatTitle(const QVariantMap &receivedInformation); }; #endif // TDLIBRECEIVER_H diff --git a/src/tdlibwrapper.cpp b/src/tdlibwrapper.cpp index d694ad4..05d014d 100644 --- a/src/tdlibwrapper.cpp +++ b/src/tdlibwrapper.cpp @@ -42,6 +42,7 @@ namespace { const QString STATUS("status"); const QString _TYPE("@type"); + const QString _EXTRA("@extra"); } TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) @@ -76,7 +77,7 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) connect(this->tdLibReceiver, SIGNAL(basicGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleBasicGroupUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(superGroupUpdated(qlonglong, QVariantMap)), this, SLOT(handleSuperGroupUpdated(qlonglong, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(chatOnlineMemberCountUpdated(QString, int)), this, SLOT(handleChatOnlineMemberCountUpdated(QString, int))); - connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList)), this, SLOT(handleMessagesReceived(QVariantList))); + connect(this->tdLibReceiver, SIGNAL(messagesReceived(QVariantList, int)), this, SLOT(handleMessagesReceived(QVariantList, int))); connect(this->tdLibReceiver, SIGNAL(newMessageReceived(QString, QVariantMap)), this, SLOT(handleNewMessageReceived(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageInformation(QString, QVariantMap)), this, SLOT(handleMessageInformation(QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messageSendSucceeded(QString, QString, QVariantMap)), this, SLOT(handleMessageSendSucceeded(QString, QString, QVariantMap))); @@ -87,11 +88,24 @@ TDLibWrapper::TDLibWrapper(QObject *parent) : QObject(parent) connect(this->tdLibReceiver, SIGNAL(messageContentUpdated(QString, QString, QVariantMap)), this, SLOT(handleMessageContentUpdated(QString, QString, QVariantMap))); connect(this->tdLibReceiver, SIGNAL(messagesDeleted(QString, QVariantList)), this, SLOT(handleMessagesDeleted(QString, QVariantList))); connect(this->tdLibReceiver, SIGNAL(chats(QVariantMap)), this, SLOT(handleChats(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chat(QVariantMap)), this, SLOT(handleChat(QVariantMap))); connect(this->tdLibReceiver, SIGNAL(recentStickersUpdated(QVariantList)), this, SLOT(handleRecentStickersUpdated(QVariantList))); connect(this->tdLibReceiver, SIGNAL(stickers(QVariantList)), this, SLOT(handleStickers(QVariantList))); connect(this->tdLibReceiver, SIGNAL(installedStickerSetsUpdated(QVariantList)), this, SLOT(handleInstalledStickerSetsUpdated(QVariantList))); connect(this->tdLibReceiver, SIGNAL(stickerSets(QVariantList)), this, SLOT(handleStickerSets(QVariantList))); connect(this->tdLibReceiver, SIGNAL(stickerSet(QVariantMap)), this, SLOT(handleStickerSet(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(chatMembers(QString, QVariantList, int)), this, SLOT(handleChatMembers(QString, QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(userFullInfo(QVariantMap)), this, SLOT(handleUserFullInfo(QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(userFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleUserFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfo(QString, QVariantMap)), this, SLOT(handleBasicGroupFullInfo(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(basicGroupFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleBasicGroupFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(supergroupFullInfo(QString, QVariantMap)), this, SLOT(handleSupergroupFullInfo(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(supergroupFullInfoUpdated(QString, QVariantMap)), this, SLOT(handleSupergroupFullInfoUpdated(QString, QVariantMap))); + connect(this->tdLibReceiver, SIGNAL(userProfilePhotos(QString, QVariantList, int)), this, SLOT(handleUserProfilePhotos(QString, QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(userProfilePhotos(QString, QVariantList, int)), this, SLOT(handleUserProfilePhotos(QString, QVariantList, int))); + connect(this->tdLibReceiver, SIGNAL(chatPermissionsUpdated(QString, QVariantMap)), this, SLOT(handleChatPermissionsUpdated(QString, QVariantMap))); + + connect(this->tdLibReceiver, SIGNAL(chatTitleUpdated(QString, QString)), this, SLOT(handleChatTitleUpdated(QString, QString))); connect(&emojiSearchWorker, SIGNAL(searchCompleted(QString, QVariantList)), this, SLOT(handleEmojiSearchCompleted(QString, QVariantList))); @@ -222,6 +236,15 @@ void TDLibWrapper::closeChat(const QString &chatId) this->sendRequest(requestObject); } +void TDLibWrapper::leaveChat(const QString &chatId) +{ + LOG("Leaving chat " << chatId); + QVariantMap requestObject; + requestObject.insert(_TYPE, "leaveChat"); + requestObject.insert("chat_id", chatId); + this->sendRequest(requestObject); +} + void TDLibWrapper::getChatHistory(const QString &chatId, const qlonglong &fromMessageId, const int &offset, const int &limit, const bool &onlyLocal) { LOG("Retrieving chat history" << chatId << fromMessageId << offset << limit << onlyLocal); @@ -468,6 +491,137 @@ void TDLibWrapper::getStickerSet(const QString &setId) requestObject.insert("set_id", setId); this->sendRequest(requestObject); } +void TDLibWrapper::getSupergroupMembers(const QString &groupId, const int &limit = 200, const int &offset = 0) +{ + LOG("Retrieving SupergroupMembers"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "getSupergroupMembers"); + requestObject.insert(_EXTRA, groupId); + requestObject.insert("supergroup_id", groupId); + requestObject.insert("offset", offset); + requestObject.insert("limit", limit); + this->sendRequest(requestObject); +} + +void TDLibWrapper::getGroupFullInfo(const QString &groupId, const bool &isSuperGroup) +{ + LOG("Retrieving GroupFullInfo"); + QVariantMap requestObject; + if(isSuperGroup) { + requestObject.insert(_TYPE, "getSupergroupFullInfo"); + requestObject.insert("supergroup_id", groupId); + } else { + requestObject.insert(_TYPE, "getBasicGroupFullInfo"); + requestObject.insert("basic_group_id", groupId); + } + requestObject.insert(_EXTRA, groupId); + this->sendRequest(requestObject); +} + +void TDLibWrapper::getUserFullInfo(const QString &userId) +{ + LOG("Retrieving UserFullInfo"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "getUserFullInfo"); + requestObject.insert(_EXTRA, userId); + requestObject.insert("user_id", userId); + this->sendRequest(requestObject); +} + +void TDLibWrapper::createPrivateChat(const QString &userId) +{ + LOG("Creating Private Chat"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "createPrivateChat"); + requestObject.insert("user_id", userId); + requestObject.insert(_EXTRA, "openDirectly"); //gets matched in qml + this->sendRequest(requestObject); +} + +void TDLibWrapper::getGroupsInCommon(const QString &userId, const int &limit, const int &offset) +{ + LOG("Retrieving Groups in Common"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "getGroupsInCommon"); + requestObject.insert(_EXTRA, userId); + requestObject.insert("user_id", userId); + requestObject.insert("offset", offset); + requestObject.insert("limit", limit); + this->sendRequest(requestObject); +} + +void TDLibWrapper::getUserProfilePhotos(const QString &userId, const int &limit, const int &offset) +{ + LOG("Retrieving User Profile Photos"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "getUserProfilePhotos"); + requestObject.insert(_EXTRA, userId); + requestObject.insert("user_id", userId); + requestObject.insert("offset", offset); + requestObject.insert("limit", limit); + this->sendRequest(requestObject); +} + +void TDLibWrapper::setChatPermissions(const QString &chatId, const QVariantMap &chatPermissions) +{ + LOG("Setting Chat Permissions"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setChatPermissions"); + requestObject.insert(_EXTRA, chatId); + requestObject.insert("chat_id", chatId); + requestObject.insert("permissions", chatPermissions); + this->sendRequest(requestObject); +} + +void TDLibWrapper::setChatSlowModeDelay(const QString &chatId, const int &delay) +{ + + LOG("Setting Chat Slow Mode Delay"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setChatSlowModeDelay"); + requestObject.insert("chat_id", chatId); + requestObject.insert("slow_mode_delay", delay); + this->sendRequest(requestObject); +} + +void TDLibWrapper::setChatDescription(const QString &chatId, const QString &description) +{ + LOG("Setting Chat Description"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setChatDescription"); + requestObject.insert("chat_id", chatId); + requestObject.insert("description", description); + this->sendRequest(requestObject); +} + +void TDLibWrapper::setChatTitle(const QString &chatId, const QString &title) +{ + LOG("Setting Chat Title"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setChatTitle"); + requestObject.insert("chat_id", chatId); + requestObject.insert("title", title); + this->sendRequest(requestObject); +} + +void TDLibWrapper::setBio(const QString &bio) +{ + LOG("Setting Bio"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "setBio"); + requestObject.insert("bio", bio); + this->sendRequest(requestObject); +} + +void TDLibWrapper::toggleSupergroupIsAllHistoryAvailable(const QString &groupId, const bool &isAllHistoryAvailable) +{ + LOG("Toggling SupergroupIsAllHistoryAvailable"); + QVariantMap requestObject; + requestObject.insert(_TYPE, "toggleSupergroupIsAllHistoryAvailable"); + requestObject.insert("supergroup_id", groupId); + requestObject.insert("is_all_history_available", isAllHistoryAvailable); + this->sendRequest(requestObject); +} void TDLibWrapper::searchEmoji(const QString &queryString) { @@ -759,9 +913,9 @@ void TDLibWrapper::handleChatOnlineMemberCountUpdated(const QString &chatId, con emit chatOnlineMemberCountUpdated(chatId, onlineMemberCount); } -void TDLibWrapper::handleMessagesReceived(const QVariantList &messages) +void TDLibWrapper::handleMessagesReceived(const QVariantList &messages, const int &totalCount) { - emit messagesReceived(messages); + emit messagesReceived(messages, totalCount); } void TDLibWrapper::handleNewMessageReceived(const QString &chatId, const QVariantMap &message) @@ -814,6 +968,11 @@ void TDLibWrapper::handleChats(const QVariantMap &chats) emit this->chatsReceived(chats); } +void TDLibWrapper::handleChat(const QVariantMap &chat) +{ + emit this->chatReceived(chat); +} + void TDLibWrapper::handleRecentStickersUpdated(const QVariantList &stickerIds) { emit this->recentStickersUpdated(stickerIds); @@ -850,6 +1009,56 @@ void TDLibWrapper::handleEmojiSearchCompleted(const QString &queryString, const emit emojiSearchSuccessful(resultList); } +void TDLibWrapper::handleChatMembers(const QString &extra, const QVariantList &members, const int &totalMembers) +{ + emit this->chatMembersReceived(extra, members, totalMembers); +} + +void TDLibWrapper::handleUserFullInfo(const QVariantMap &userFullInfo) +{ + emit this->userFullInfoReceived(userFullInfo); +} + +void TDLibWrapper::handleUserFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo) +{ + emit this->userFullInfoUpdated(userId, userFullInfo); +} + +void TDLibWrapper::handleBasicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo) +{ + emit this->basicGroupFullInfoReceived(groupId, groupFullInfo); +} + +void TDLibWrapper::handleBasicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo) +{ + emit this->basicGroupFullInfoUpdated(groupId, groupFullInfo); +} + +void TDLibWrapper::handleSupergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo) +{ + emit this->supergroupFullInfoReceived(groupId, groupFullInfo); +} + +void TDLibWrapper::handleSupergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo) +{ + emit this->supergroupFullInfoUpdated(groupId, groupFullInfo); +} + +void TDLibWrapper::handleUserProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos) +{ + emit this->userProfilePhotosReceived(extra, photos, totalPhotos); +} + +void TDLibWrapper::handleChatPermissionsUpdated(const QString &chatId, const QVariantMap permissions) +{ + emit this->chatPermissionsUpdated(chatId, permissions); +} + +void TDLibWrapper::handleChatTitleUpdated(const QString &chatId, const QString title) +{ + emit this->chatTitleUpdated(chatId, title); +} + void TDLibWrapper::setInitialParameters() { LOG("Sending initial parameters to TD Lib"); diff --git a/src/tdlibwrapper.h b/src/tdlibwrapper.h index 6723470..cca025f 100644 --- a/src/tdlibwrapper.h +++ b/src/tdlibwrapper.h @@ -113,6 +113,7 @@ public: Q_INVOKABLE void downloadFile(const QString &fileId); Q_INVOKABLE void openChat(const QString &chatId); Q_INVOKABLE void closeChat(const QString &chatId); + Q_INVOKABLE void leaveChat(const QString &chatId); Q_INVOKABLE void getChatHistory(const QString &chatId, const qlonglong &fromMessageId = 0, const int &offset = 0, const int &limit = 50, const bool &onlyLocal = false); Q_INVOKABLE void viewMessage(const QString &chatId, const QString &messageId); Q_INVOKABLE void sendTextMessage(const QString &chatId, const QString &message, const QString &replyToMessageId = "0"); @@ -129,6 +130,18 @@ public: Q_INVOKABLE void getRecentStickers(); Q_INVOKABLE void getInstalledStickerSets(); Q_INVOKABLE void getStickerSet(const QString &setId); + Q_INVOKABLE void getSupergroupMembers(const QString &groupId, const int &limit, const int &offset); + Q_INVOKABLE void getGroupFullInfo(const QString &groupId, const bool &isSuperGroup); + Q_INVOKABLE void getUserFullInfo(const QString &userId); + Q_INVOKABLE void createPrivateChat(const QString &userId); + Q_INVOKABLE void getGroupsInCommon(const QString &userId, const int &limit, const int &offset); + Q_INVOKABLE void getUserProfilePhotos(const QString &userId, const int &limit, const int &offset); + Q_INVOKABLE void setChatPermissions(const QString &chatId, const QVariantMap &chatPermissions); + Q_INVOKABLE void setChatSlowModeDelay(const QString &chatId, const int &delay); + Q_INVOKABLE void setChatDescription(const QString &chatId, const QString &description); + Q_INVOKABLE void setChatTitle(const QString &chatId, const QString &title); + Q_INVOKABLE void setBio(const QString &bio); + Q_INVOKABLE void toggleSupergroupIsAllHistoryAvailable(const QString &groupId, const bool &isAllHistoryAvailable); // Others (candidates for extraction ;)) Q_INVOKABLE void searchEmoji(const QString &queryString); @@ -155,7 +168,7 @@ signals: void basicGroupUpdated(qlonglong groupId); void superGroupUpdated(qlonglong groupId); void chatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void messagesReceived(const QVariantList &messages); + void messagesReceived(const QVariantList &messages, const int &totalCount); void newMessageReceived(const QString &chatId, const QVariantMap &message); void copyToDownloadsSuccessful(const QString &fileName, const QString &filePath); void copyToDownloadsError(const QString &fileName, const QString &filePath); @@ -168,12 +181,23 @@ signals: void messageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent); void messagesDeleted(const QString &chatId, const QVariantList &messageIds); void chatsReceived(const QVariantMap &chats); + void chatReceived(const QVariantMap &chat); void recentStickersUpdated(const QVariantList &stickerIds); void stickersReceived(const QVariantList &stickers); void installedStickerSetsUpdated(const QVariantList &stickerSetIds); void stickerSetsReceived(const QVariantList &stickerSets); void stickerSetReceived(const QVariantMap &stickerSet); void emojiSearchSuccessful(const QVariantList &result); + void chatMembersReceived(const QString &extra, const QVariantList &members, const int &totalMembers); + void userFullInfoReceived(const QVariantMap &userFullInfo); + void userFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo); + void basicGroupFullInfoReceived(const QString &groupId, const QVariantMap &groupFullInfo); + void supergroupFullInfoReceived(const QString &groupId, const QVariantMap &groupFullInfo); + void basicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void supergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void userProfilePhotosReceived(const QString &extra, const QVariantList &photos, const int &totalPhotos); + void chatPermissionsUpdated(const QString &chatId, const QVariantMap &permissions); + void chatTitleUpdated(const QString &chatId, const QString &title); public slots: void handleVersionDetected(const QString &version); @@ -193,7 +217,7 @@ public slots: void handleBasicGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleSuperGroupUpdated(qlonglong groupId, const QVariantMap &groupInformation); void handleChatOnlineMemberCountUpdated(const QString &chatId, const int &onlineMemberCount); - void handleMessagesReceived(const QVariantList &messages); + void handleMessagesReceived(const QVariantList &messages, const int &totalCount); void handleNewMessageReceived(const QString &chatId, const QVariantMap &message); void handleMessageInformation(const QString &messageId, const QVariantMap &message); void handleMessageSendSucceeded(const QString &messageId, const QString &oldMessageId, const QVariantMap &message); @@ -204,12 +228,23 @@ public slots: void handleMessageContentUpdated(const QString &chatId, const QString &messageId, const QVariantMap &newContent); void handleMessagesDeleted(const QString &chatId, const QVariantList &messageIds); void handleChats(const QVariantMap &chats); + void handleChat(const QVariantMap &chat); void handleRecentStickersUpdated(const QVariantList &stickerIds); void handleStickers(const QVariantList &stickers); void handleInstalledStickerSetsUpdated(const QVariantList &stickerSetIds); void handleStickerSets(const QVariantList &stickerSets); void handleStickerSet(const QVariantMap &stickerSet); void handleEmojiSearchCompleted(const QString &queryString, const QVariantList &resultList); + void handleChatMembers(const QString &extra, const QVariantList &members, const int &totalMembers); + void handleUserFullInfo(const QVariantMap &userFullInfo); + void handleUserFullInfoUpdated(const QString &userId, const QVariantMap &userFullInfo); + void handleBasicGroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); + void handleBasicGroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void handleSupergroupFullInfo(const QString &groupId, const QVariantMap &groupFullInfo); + void handleSupergroupFullInfoUpdated(const QString &groupId, const QVariantMap &groupFullInfo); + void handleUserProfilePhotos(const QString &extra, const QVariantList &photos, const int &totalPhotos); + void handleChatPermissionsUpdated(const QString &chatId, const QVariantMap permissions); + void handleChatTitleUpdated(const QString &chatId, const QString title); private: void setInitialParameters(); diff --git a/translations/harbour-fernschreiber-de.ts b/translations/harbour-fernschreiber-de.ts index 90804d6..5b61b86 100644 --- a/translations/harbour-fernschreiber-de.ts +++ b/translations/harbour-fernschreiber-de.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + Stummschaltung des Chats aufheben + + + Mute Chat + Chat stummschalten + + + Unknown + Unbekannt + + + The Invite Link has been copied to the clipboard. + Der Einladungslink wurde in die Zwischenablage kopiert. + + + %1 members, %2 online + %1 Mitglieder, %2 online + + + %1 subscribers + %1 Abonnenten + + + %1 members + %1 Mitglieder + + + Leave Group + Gruppe verlassen + + + Leaving chat + Verlasse Gruppe + + + Info + group or user infotext header + Info + + + Phone Number + user phone number header + Telefonnummer + + + Invite Link + header + Einladungslink + + + There is no information text available, yet. + Es gibt noch keinen Informationstext. + + + Chat Title + group title header + Chattitel + + + Enter 1-128 characters + Geben Sie 1-126 Zeichen ein + + + + ChatInformationTabItemMembersGroups + + You + Sie + + + Loading common chats… + chats you have in common with a user + Lade gemeinsame Chats… + + + Unknown + Unbekannt + + + Groups + Button: groups in common (short) + Gruppen + + + Members + Button: Group Members + Mitglieder + + + Loading group members… + Lade Gruppenmitglieder… + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Einstellungen + + + + ChatListViewItem + + Unknown + Unbekannt + + + You + Sie + + + Unmute Chat + Stummschaltung des Chats aufheben + + + Mute Chat + Chat stummschalten + + + User Info + Benutzerinfos + + + Group Info + Gruppeninfos + + ChatPage @@ -97,30 +229,6 @@ Your message Ihre Nachricht - - was never online - war niemals online - - - offline, last online: last month - offline, zuletzt online im letzten Monat - - - offline, last online: last week - offline, zuletzt online in der letzten Woche - - - offline, last online: %1 - offline, zuletzt online: %1 - - - online - online - - - offline, was recently online - offline, war neulich online - %1 members, %2 online %1 Mitglieder, %2 online @@ -177,6 +285,10 @@ Forwarded Message Weitergeleitete Nachricht + + This chat is empty. + Dieser Chat ist leer. + CoverPage @@ -232,6 +344,74 @@ Dokument öffnen + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + Berechtigungen der Gruppenmitglieder + + + Send Messages + member permission + Nachrichten senden + + + Send Media Messages + member permission + Medien senden + + + Send Other Messages + member permission + Andere Nachrichten senden + + + Add Web Page Previews + member permission + Webseiten-Vorschau hinzufügen + + + Change Chat Info + member permission + Chatinformation ändern + + + Invite Users + member permission + Benutzer einladen + + + Pin Messages + member permission + Nachrichten anpinnen + + + New Members + what can new group members do + Neue Mitglieder + + + New members can see older messages + member permission + Neue Mitglieder können ältere Nachrichten sehen + + + + EditSuperGroupSlowModeColumn + + Slow Mode + Langsamer Modus + + + Off + Aus + + + Set how long every chat member has to wait between Messages + Legen Sie fest, wie lange jedes Mitglied zwischen zwei Nachrichten warten muss + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue hat einen Ort geschickt + + changed the chat title + myself + haben den Chattitel geändert + + + changed the chat title + hat den Chattitel geändert + ImagePage @@ -467,22 +656,10 @@ Unknown Unbekannt - - You - Sie - Loading chat list... Lade Chatliste... - - Unmute Chat - Stummschaltung des Chats aufheben - - - Mute Chat - Chat stummschalten - Settings Einstellungen @@ -718,5 +895,58 @@ myself haben diesen Chat verlassen + + was never online + war niemals online + + + offline, last online: last month + offline, zuletzt online im letzten Monat + + + offline, last online: last week + offline, zuletzt online in der letzten Woche + + + offline, last online: %1 + offline, zuletzt online: %1 + + + online + online + + + offline, was recently online + offline, war neulich online + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + haben den Chattitel zu %1 geändert + + + changed the chat title to %1 + hat den Chattitel zu %1 geändert + diff --git a/translations/harbour-fernschreiber-es.ts b/translations/harbour-fernschreiber-es.ts index 0398fdc..804501a 100644 --- a/translations/harbour-fernschreiber-es.ts +++ b/translations/harbour-fernschreiber-es.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + habilitar notificación + + + Mute Chat + deshabilitar notificación + + + Unknown + + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 miembros, %2 en línea + + + %1 subscribers + %1 suscriptores + + + %1 members + %1 miembros + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Ajustes + + + + ChatListViewItem + + Unknown + + + + You + + + + Unmute Chat + habilitar notificación + + + Mute Chat + deshabilitar notificación + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Escribir mensaje - - was never online - nunca estuvo en línea - - - offline, last online: last month - sin línea, hace en línea: hace 1 mes - - - offline, last online: last week - sin línea, hace en línea: hace 1 semana - - - offline, last online: %1 - sin línea, hace en línea: %1 - - - online - en línea - - - offline, was recently online - sin línea, estuvo en línea - %1 members, %2 online %1 miembros, %2 en línea @@ -177,6 +285,10 @@ Forwarded Message Mensaje reenviado + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Abrir Documento + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue envió un lugar + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown desconocido - - You - Usted - Loading chat list... cargando lista de charla... - - Unmute Chat - Habilitar notificación - - - Mute Chat - Deshabilitar notificación - Settings Ajustes @@ -718,5 +895,58 @@ myself dejé esta charla + + was never online + nunca estuvo en línea + + + offline, last online: last month + sin línea, hace en línea: hace 1 mes + + + offline, last online: last week + sin línea, hace en línea: hace 1 semana + + + offline, last online: %1 + sin línea, hace en línea: %1 + + + online + en línea + + + offline, was recently online + sin línea, estuvo en línea + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-fi.ts b/translations/harbour-fernschreiber-fi.ts index b03cc86..72629fc 100644 --- a/translations/harbour-fernschreiber-fi.ts +++ b/translations/harbour-fernschreiber-fi.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + Poista keskustelun vaimennus + + + Mute Chat + Vaimenna keskustelu + + + Unknown + Tuntematon + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 jäsentä, %2 paikalla + + + %1 subscribers + %1 tilaajaa + + + %1 members + %1 jäsentä + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + Tuntematon + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + Sinä + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Asetukset + + + + ChatListViewItem + + Unknown + Tuntematon + + + You + Sinä + + + Unmute Chat + Poista keskustelun vaimennus + + + Mute Chat + Vaimenna keskustelu + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Viestisi - - was never online - Ei ole ollut koskaan paikalla - - - offline, last online: last month - Poissa. Nähty viimeksi: viime kuussa - - - offline, last online: last week - Poissa. Nähty viimeksi: viime viikolla - - - offline, last online: %1 - Poissa. Nähty viimeksi: %1 - - - online - paikalla - - - offline, was recently online - poissa, oli hetki sitten paikalla - %1 members, %2 online %1 jäsentä, %2 paikalla @@ -177,6 +285,10 @@ Forwarded Message + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Avaa dokumentti + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ Unsupported message: %1 Viestityyppiä ei tueta: %1 + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown Tuntematon - - You - Sinä - Loading chat list... Ladataan keskustelulistaa... - - Unmute Chat - Poista keskustelun vaimennus - - - Mute Chat - Vaimenna keskustelu - Settings Asetukset @@ -718,5 +895,58 @@ myself poistuit keskustelusta + + was never online + Ei ole ollut koskaan paikalla + + + offline, last online: last month + Poissa. Nähty viimeksi: viime kuussa + + + offline, last online: last week + Poissa. Nähty viimeksi: viime viikolla + + + offline, last online: %1 + Poissa. Nähty viimeksi: %1 + + + online + paikalla + + + offline, was recently online + poissa, oli hetki sitten paikalla + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-hu.ts b/translations/harbour-fernschreiber-hu.ts index 37d8ddf..c065b0c 100644 --- a/translations/harbour-fernschreiber-hu.ts +++ b/translations/harbour-fernschreiber-hu.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + Csevegés némítás feloldása + + + Mute Chat + Csevegés némítása + + + Unknown + Ismeretlen + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 tag, %2 online + + + %1 subscribers + %1 feliratkozott + + + %1 members + %1 tag + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + Ismeretlen + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + Te + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Beállítások + + + + ChatListViewItem + + Unknown + Ismeretlen + + + You + Te + + + Unmute Chat + Csevegés némítás feloldása + + + Mute Chat + Csevegés némítása + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Üzeneted - - was never online - soha nem volt online - - - offline, last online: last month - offline, utoljára online: múlt hónapban - - - offline, last online: last week - offline, utoljára online: múlt héten - - - offline, last online: %1 - offline, utoljára online: %1 - - - online - online - - - offline, was recently online - offline, nemrégen volt online - %1 members, %2 online %1 tag, %2 online @@ -177,6 +285,10 @@ Forwarded Message + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Dokumentum megyitása + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown Ismeretlen - - You - Te - Loading chat list... Csevegés lista betöltése... - - Unmute Chat - Csevegés némítás feloldása - - - Mute Chat - Csevegés némítása - Settings Beállítások @@ -718,5 +895,58 @@ myself kilépett a csevegésből + + was never online + soha nem volt online + + + offline, last online: last month + offline, utoljára online: múlt hónapban + + + offline, last online: last week + offline, utoljára online: múlt héten + + + offline, last online: %1 + offline, utoljára online: %1 + + + online + online + + + offline, was recently online + offline, nemrégen volt online + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-it.ts b/translations/harbour-fernschreiber-it.ts index f738048..2ae9096 100644 --- a/translations/harbour-fernschreiber-it.ts +++ b/translations/harbour-fernschreiber-it.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Leave Group + + + + Leaving chat + + + + Unmute Chat + Riattiva suoni chat + + + Mute Chat + Silenzia chat + + + Unknown + Sconosciuto + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 membri, %2 online + + + %1 subscribers + %1 abbonati + + + %1 members + %1 membri + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading common chats… + chats you have in common with a user + + + + Loading group members… + + + + You + Tu + + + Unknown + Sconosciuto + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Impostazioni + + + + ChatListViewItem + + Unknown + Sconosciuto + + + You + Tu + + + Unmute Chat + Riattiva suoni chat + + + Mute Chat + Silenzia chat + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Tuo messaggio - - was never online - mai online - - - offline, last online: last month - offline, ultimo accesso il mese scorso - - - offline, last online: last week - offline, ultimo accesso la settimana scorsa - - - offline, last online: %1 - offline, ultimo accesso: %1 - - - online - online - - - offline, was recently online - offline, online di recente - %1 members, %2 online %1 membri, %2 online @@ -177,6 +285,10 @@ Forwarded Message Messaggio inoltrato + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Apri documento + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue ha inviato la posizione + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown Sconosciuto - - You - Tu - Loading chat list... Carica lista chat... - - Unmute Chat - Riattiva suoni chat - - - Mute Chat - Silenzia chat - Settings Impostazioni @@ -718,5 +895,58 @@ myself hanno lasciato questa chat + + was never online + mai online + + + offline, last online: last month + offline, ultimo accesso il mese scorso + + + offline, last online: last week + offline, ultimo accesso la settimana scorsa + + + offline, last online: %1 + offline, ultimo accesso: %1 + + + online + online + + + offline, was recently online + offline, online di recente + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-pl.ts b/translations/harbour-fernschreiber-pl.ts index 2bd2d43..e083601 100644 --- a/translations/harbour-fernschreiber-pl.ts +++ b/translations/harbour-fernschreiber-pl.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + Wyłącz wyciszenie czatu + + + Mute Chat + Wycisz czat + + + Unknown + Nieznany + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + $1 członków, %2 online + + + %1 subscribers + %1 subskrybentów + + + %1 members + %1 czlonków + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + Nieznany + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + Ty + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Ustawienia + + + + ChatListViewItem + + Unknown + Nieznany + + + You + Ty + + + Unmute Chat + Wyłącz wyciszenie czatu + + + Mute Chat + Wycisz czat + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Twoja wiadomość - - was never online - nigdy nie był online - - - offline, last online: last month - offline, ostatnio online: w zeszłym miesiącu - - - offline, last online: last week - offline, ostatnio online: w zeszłym tygodniu - - - offline, last online: %1 - offline, ostatnio online: %1 - - - online - online - - - offline, was recently online - offline, był niedawno online - %1 members, %2 online $1 członków, %2 online @@ -177,6 +285,10 @@ Forwarded Message + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Otwórz dokument + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown Nieznany - - You - Ty - Loading chat list... Ładowanie listy czatu... - - Unmute Chat - Wyłącz wyciszenie czatu - - - Mute Chat - Wycisz czat - Settings Ustawienia @@ -718,5 +895,58 @@ myself opuścił ten czat + + was never online + nigdy nie był online + + + offline, last online: last month + offline, ostatnio online: w zeszłym miesiącu + + + offline, last online: last week + offline, ostatnio online: w zeszłym tygodniu + + + offline, last online: %1 + offline, ostatnio online: %1 + + + online + online + + + offline, was recently online + offline, był niedawno online + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-ru.ts b/translations/harbour-fernschreiber-ru.ts index 7b1f303..99e7f7a 100644 --- a/translations/harbour-fernschreiber-ru.ts +++ b/translations/harbour-fernschreiber-ru.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + Включить уведомления + + + Mute Chat + Выключить уведомления + + + Unknown + + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 участников, %2 онлайн + + + %1 subscribers + %1 подписчиков + + + %1 members + %1 участников + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + Вы + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + Настройки + + + + ChatListViewItem + + Unknown + + + + You + Вы + + + Unmute Chat + Включить уведомления + + + Mute Chat + Выключить уведомления + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message Ваше сообщение - - was never online - никогда не был(а) онлайн - - - offline, last online: last month - офлайн, был(а) онлайн: в прошлом месяце - - - offline, last online: last week - офлайн, был(а) онлайн: на прошлой неделе - - - offline, last online: %1 - офлайн, был(а) онлайн: %1 - - - online - онлайн - - - offline, was recently online - офлайн, недавно был(а) онлайн - %1 members, %2 online %1 участников, %2 онлайн @@ -177,6 +285,10 @@ Forwarded Message Пересланное сообщение + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ Открыть документ + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue отправил(а) место встречи + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown Неизвестный - - You - Вы - Loading chat list... Загрузка чатов... - - Unmute Chat - Включить уведомления - - - Mute Chat - Выключить уведомления - Settings Настройки @@ -718,5 +895,58 @@ myself покинул(а) чат + + was never online + никогда не был(а) онлайн + + + offline, last online: last month + офлайн, был(а) онлайн: в прошлом месяце + + + offline, last online: last week + офлайн, был(а) онлайн: на прошлой неделе + + + offline, last online: %1 + офлайн, был(а) онлайн: %1 + + + online + онлайн + + + offline, was recently online + офлайн, недавно был(а) онлайн + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber-zh_CN.ts b/translations/harbour-fernschreiber-zh_CN.ts index 25b5912..76e2755 100644 --- a/translations/harbour-fernschreiber-zh_CN.ts +++ b/translations/harbour-fernschreiber-zh_CN.ts @@ -87,6 +87,138 @@ %1 + + ChatInformationPage + + Unmute Chat + 取消对话静音 + + + Mute Chat + 对话静音 + + + Unknown + 未知 + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + %1 位成员, %2 在线 + + + %1 subscribers + %1 位订阅者 + + + %1 members + %1 位成员 + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + 未知 + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + 设置 + + + + ChatListViewItem + + Unknown + 未知 + + + You + + + + Unmute Chat + 取消对话静音 + + + Mute Chat + 对话静音 + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message 你的消息 - - was never online - 完全离线 - - - offline, last online: last month - 离线,上次在线时间:上月 - - - offline, last online: last week - 离线,上次在线时间:上周 - - - offline, last online: %1 - 离线,上次在线时间: %1 - - - online - 在线 - - - offline, was recently online - 离线,最近在线 - %1 members, %2 online %1 位成员, %2 在线 @@ -177,6 +285,10 @@ Forwarded Message + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ 打开文档 + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue 发送地点 + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown 未知 - - You - - Loading chat list... 正在加载对话列表…… - - Unmute Chat - 取消静音对话 - - - Mute Chat - 静音对话 - Settings 设置 @@ -718,5 +895,58 @@ myself 离开此对话 + + was never online + 完全离线 + + + offline, last online: last month + 离线,上次在线时间:上月 + + + offline, last online: last week + 离线,上次在线时间:上周 + + + offline, last online: %1 + 离线,上次在线时间: %1 + + + online + 在线 + + + offline, was recently online + 离线,最近在线 + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + + diff --git a/translations/harbour-fernschreiber.ts b/translations/harbour-fernschreiber.ts index 9ba73fe..845015c 100644 --- a/translations/harbour-fernschreiber.ts +++ b/translations/harbour-fernschreiber.ts @@ -87,6 +87,138 @@ + + ChatInformationPage + + Unmute Chat + + + + Mute Chat + + + + Unknown + + + + The Invite Link has been copied to the clipboard. + + + + %1 members, %2 online + + + + %1 subscribers + + + + %1 members + + + + Leave Group + + + + Leaving chat + + + + Info + group or user infotext header + + + + Phone Number + user phone number header + + + + Invite Link + header + + + + There is no information text available, yet. + + + + Chat Title + group title header + + + + Enter 1-128 characters + + + + + ChatInformationTabItemMembersGroups + + Loading common chats… + chats you have in common with a user + + + + Unknown + + + + Groups + Button: groups in common (short) + + + + Members + Button: Group Members + + + + Loading group members… + + + + You + + + + + ChatInformationTabItemSettings + + Settings + Button: Chat Settings + + + + + ChatListViewItem + + Unknown + + + + You + + + + Unmute Chat + + + + Mute Chat + + + + User Info + + + + Group Info + + + ChatPage @@ -97,30 +229,6 @@ Your message - - was never online - - - - offline, last online: last month - - - - offline, last online: last week - - - - offline, last online: %1 - - - - online - - - - offline, was recently online - - %1 members, %2 online @@ -177,6 +285,10 @@ Forwarded Message + + This chat is empty. + + CoverPage @@ -232,6 +344,74 @@ + + EditGroupChatPermissionsColumn + + Group Member Permissions + what can normal group members do + + + + Send Messages + member permission + + + + Send Media Messages + member permission + + + + Send Other Messages + member permission + + + + Add Web Page Previews + member permission + + + + Change Chat Info + member permission + + + + Invite Users + member permission + + + + Pin Messages + member permission + + + + New Members + what can new group members do + + + + New members can see older messages + member permission + + + + + EditSuperGroupSlowModeColumn + + Slow Mode + + + + Off + + + + Set how long every chat member has to wait between Messages + + + FernschreiberUtils @@ -341,6 +521,15 @@ sent a venue + + changed the chat title + myself + + + + changed the chat title + + ImagePage @@ -467,22 +656,10 @@ Unknown - - You - - Loading chat list... - - Unmute Chat - - - - Mute Chat - - Settings @@ -718,5 +895,58 @@ myself + + was never online + + + + offline, last online: last month + + + + offline, last online: last week + + + + offline, last online: %1 + + + + online + + + + offline, was recently online + + + + Admin + channel user role + + + + Banned + channel user role + + + + Creator + channel user role + + + + Restricted + channel user role + + + + changed the chat title to %1 + myself + + + + changed the chat title to %1 + +