harbour-fernschreiber/qml/components/chatInformationPage/ChatInformationPageContent.qml
2023-11-19 21:49:00 +01:00

494 lines
22 KiB
QML

/*
Copyright (C) 2020 Sebastian J. Wolf and other contributors
This file is part of Fernschreiber.
Fernschreiber is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Fernschreiber is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fernschreiber. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.6
import Sailfish.Silica 1.0
import "../"
import "../../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
import "../../js/debug.js" as Debug
SilicaFlickable {
id: pageContent
property alias membersList: membersList
function initializePage() {
membersList.clear();
var chatType = chatInformation.type["@type"];
switch(chatType) {
case "chatTypePrivate":
chatInformationPage.isPrivateChat = true;
chatInformationPage.chatPartnerGroupId = chatInformationPage.chatInformation.type.user_id.toString();
if(!chatInformationPage.privateChatUserInformation.id) {
chatInformationPage.privateChatUserInformation = tdLibWrapper.getUserInformation(chatInformationPage.chatPartnerGroupId);
}
tdLibWrapper.getUserFullInfo(chatInformationPage.chatPartnerGroupId);
tdLibWrapper.getUserProfilePhotos(chatInformationPage.chatPartnerGroupId, 100, 0);
break;
case "chatTypeSecret":
chatInformationPage.isSecretChat = true;
chatInformationPage.chatPartnerGroupId = chatInformationPage.chatInformation.type.user_id.toString();
if(!chatInformationPage.privateChatUserInformation.id) {
chatInformationPage.privateChatUserInformation = tdLibWrapper.getUserInformation(chatInformationPage.chatPartnerGroupId);
}
tdLibWrapper.getUserFullInfo(chatInformationPage.chatPartnerGroupId);
tdLibWrapper.getUserProfilePhotos(chatInformationPage.chatPartnerGroupId, 100, 0);
break;
case "chatTypeBasicGroup":
chatInformationPage.isBasicGroup = true;
chatInformationPage.chatPartnerGroupId = chatInformation.type.basic_group_id.toString();
if(!chatInformationPage.groupInformation.id) {
chatInformationPage.groupInformation = tdLibWrapper.getBasicGroup(chatInformationPage.chatPartnerGroupId);
}
tdLibWrapper.getGroupFullInfo(chatInformationPage.chatPartnerGroupId, false);
break;
case "chatTypeSupergroup":
chatInformationPage.isSuperGroup = true;
chatInformationPage.chatPartnerGroupId = chatInformation.type.supergroup_id.toString();
if(!chatInformationPage.groupInformation.id) {
chatInformationPage.groupInformation = tdLibWrapper.getSuperGroup(chatInformationPage.chatPartnerGroupId);
}
tdLibWrapper.getGroupFullInfo(chatInformationPage.chatPartnerGroupId, true);
chatInformationPage.isChannel = chatInformationPage.groupInformation.is_channel;
break;
}
Debug.log("is set up", chatInformationPage.isPrivateChat, chatInformationPage.isSecretChat, chatInformationPage.isBasicGroup, chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId)
if(!(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat)) {
updateGroupStatusText();
}
tabViewLoader.active = true;
}
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) {
chatInformationPage.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.member_id.user_id) || {user:{}, bot_info:{}};
memberData.user = userInfo;
memberData.bot_info = memberData.bot_info || {};
membersList.append(memberData);
}
chatInformationPage.groupInformation.member_count = groupFullInfo.members.length
updateGroupStatusText();
}
}
function updateGroupStatusText() {
if (chatInformationPage.chatOnlineMemberCount > 0) {
headerItem.description = qsTr("%1, %2", "combination of '[x members], [y online]', which are separate translations")
.arg(qsTr("%1 members", "", chatInformationPage.groupInformation.member_count)
.arg(Functions.getShortenedCount(chatInformationPage.groupInformation.member_count)))
.arg(qsTr("%1 online", "", chatInformationPage.chatOnlineMemberCount)
.arg(Functions.getShortenedCount(chatInformationPage.chatOnlineMemberCount)));
} else {
if (isChannel) {
headerItem.description = qsTr("%1 subscribers", "", chatInformationPage.groupInformation.member_count ).arg(Functions.getShortenedCount(chatInformationPage.groupInformation.member_count));
} else {
headerItem.description = qsTr("%1 members", "", chatInformationPage.groupInformation.member_count).arg(Functions.getShortenedCount(chatInformationPage.groupInformation.member_count));
}
}
}
Connections {
target: tdLibWrapper
onChatOnlineMemberCountUpdated: {
if ((chatInformationPage.isSuperGroup || chatInformationPage.isBasicGroup) && chatInformationPage.chatInformation.id.toString() === chatId) {
chatInformationPage.chatOnlineMemberCount = onlineMemberCount;
updateGroupStatusText();
}
}
onSupergroupFullInfoReceived: {
Debug.log("onSupergroupFullInfoReceived", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
if(chatInformationPage.isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) {
chatInformationPage.groupFullInformation = groupFullInfo;
}
}
onSupergroupFullInfoUpdated: {
Debug.log("onSupergroupFullInfoUpdated", chatInformationPage.isSuperGroup, chatInformationPage.chatPartnerGroupId, groupId)
if(chatInformationPage.isSuperGroup && chatInformationPage.chatPartnerGroupId === groupId) {
chatInformationPage.groupFullInformation = groupFullInfo;
}
}
onBasicGroupFullInfoReceived: {
if(chatInformationPage.isBasicGroup && chatInformationPage.chatPartnerGroupId === groupId) {
handleBasicGroupFullInfo(groupFullInfo)
}
}
onBasicGroupFullInfoUpdated: {
if(chatInformationPage.isBasicGroup && chatInformationPage.chatPartnerGroupId === groupId) {
handleBasicGroupFullInfo(groupFullInfo)
}
}
onUserFullInfoReceived: {
if((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && userFullInfo["@extra"] === chatInformationPage.chatPartnerGroupId) {
chatInformationPage.chatPartnerFullInformation = userFullInfo;
}
}
onUserFullInfoUpdated: {
if((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && userId === chatInformationPage.chatPartnerGroupId) {
chatInformationPage.chatPartnerFullInformation = userFullInfo;
}
}
onUserProfilePhotosReceived: {
if((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && extra === chatInformationPage.chatPartnerGroupId) {
chatInformationPage.chatPartnerProfilePhotos = photos;
}
}
onChatPermissionsUpdated: {
if (chatInformationPage.chatInformation.id.toString() === chatId) {
// set whole object to trigger change
var newInformation = chatInformation;
newInformation.permissions = permissions
chatInformationPage.chatInformation = newInformation
}
}
onChatTitleUpdated: {
if (chatInformationPage.chatInformation.id.toString() === chatId) {
// set whole object to trigger change
var newInformation = chatInformation;
newInformation.title = title
chatInformationPage.chatInformation = newInformation
}
}
onChatNotificationSettingsUpdated: {
if (chatInformationPage.chatInformation.id.toString() === chatId) {
// set whole object to trigger change
var newInformation = chatInformation;
newInformation.notification_settings = chatNotificationSettings;
chatInformationPage.chatInformation = newInformation;
}
}
}
Component.onCompleted: {
initializePage();
}
ListModel {
id: membersList
}
PullDownMenu {
MenuItem {
visible: (chatInformationPage.isSuperGroup || chatInformationPage.isBasicGroup) && chatInformationPage.groupInformation && chatInformationPage.groupInformation.status["@type"] !== "chatMemberStatusBanned"
text: chatInformationPage.userIsMember ? qsTr("Leave Chat") : qsTr("Join Chat")
onClicked: {
// ensure it's done even if the page is closed:
if (chatInformationPage.userIsMember) {
var chatId = chatInformationPage.chatInformation.id;
Remorse.popupAction(chatInformationPage, qsTr("Leaving chat"), function() {
tdLibWrapper.leaveChat(chatId);
// this does not care about the response (ideally type "ok" without further reference) for now
pageStack.pop(pageStack.find( function(page){ return(page._depth === 0)} ));
});
} else {
tdLibWrapper.joinChat(chatInformationPage.chatInformation.id);
}
}
}
MenuItem {
visible: chatInformationPage.userIsMember
onClicked: {
var newNotificationSettings = chatInformationPage.chatInformation.notification_settings;
if (newNotificationSettings.mute_for > 0) {
newNotificationSettings.mute_for = 0;
} else {
newNotificationSettings.mute_for = 6666666;
}
newNotificationSettings.use_default_mute_for = false;
tdLibWrapper.setChatNotificationSettings(chatInformationPage.chatInformation.id, newNotificationSettings);
}
text: chatInformation.notification_settings.mute_for > 0 ? qsTr("Unmute Chat") : qsTr("Mute Chat")
}
MenuItem {
visible: chatInformationPage.isPrivateChat
onClicked: {
tdLibWrapper.createNewSecretChat(chatInformationPage.chatPartnerGroupId, "openDirectly");
}
text: qsTr("New Secret Chat")
}
}
// header
PageHeader {
id: headerItem
z: 5
Item {
id: imageContainer
property bool hasImage: typeof chatInformationPage.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: Theme.paddingMedium
property int maxY: parent.height
property double tweenFactor: {
if(!hasImage) {
return 0
}
return 1 - Math.max(0, Math.min(1, contentFlickable.contentY / maxDimension))
}
property bool thumbnailVisible: imageContainer.tweenFactor > 0.8
property bool thumbnailActive: imageContainer.tweenFactor === 1.0
property var thumbnailModel: chatInformationPage.chatPartnerProfilePhotos
property int thumbnailRadius: imageContainer.minDimension / 2
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 ? chatInformationPage.chatInformation.photo.small : ""
replacementStringHint: headerItem.title
width: parent.width
height: width
radius: imageContainer.thumbnailRadius
opacity: profilePictureLoader.status !== Loader.Ready || profilePictureLoader.item.opacity < 1 ? 1.0 : 0.0
optimizeImageSize: false
}
Loader {
id: profilePictureLoader
active: imageContainer.hasImage
asynchronous: true
anchors.fill: chatPictureThumbnail
source: ( chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat)
? "../ProfilePictureList.qml"
: "ChatInformationProfilePicture.qml"
}
}
leftMargin: imageContainer.getEased((imageContainer.minDimension + Theme.paddingMedium), 0, imageContainer.tweenFactor) + Theme.horizontalPageMargin
title: chatInformationPage.chatInformation.title !== "" ? Emoji.emojify(chatInformationPage.chatInformation.title, Theme.fontSizeLarge) : qsTr("Unknown")
description: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.privateChatUserInformation.usernames.editable_username)
? ("@"+chatInformationPage.privateChatUserInformation.usernames.editable_username) : ""
}
SilicaFlickable {
id: contentFlickable
contentHeight: groupInfoItem.height + tabViewLoader.height
clip: true
interactive: !scrollUpAnimation.running && !scrollDownAnimation.running
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
}
Label {
id: copyIdText
x: Math.max(headerItem.x + imageContainer.x - groupInfoItem.x + (imageContainer.width - width)/2, 0)
text: chatInformationPage.chatPartnerGroupId
font.pixelSize: Theme.fontSizeSmall
color: copyIdMouseArea.pressed ? Theme.secondaryHighlightColor : Theme.highlightColor
visible: text !== ""
MouseArea {
id: copyIdMouseArea
anchors {
fill: parent
margins: -Theme.paddingLarge
}
onClicked: {
Clipboard.text = copyIdText.text
appNotification.show(qsTr("ID has been copied to the clipboard."));
}
}
}
InformationEditArea {
visible: canEdit
canEdit: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && chatInformationPage.groupInformation.status && (chatInformationPage.groupInformation.status.can_change_info || chatInformationPage.groupInformation.status["@type"] === "chatMemberStatusCreator")
headerText: qsTr("Chat Title", "group title header")
text: chatInformationPage.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
}
}
}
InformationEditArea {
canEdit: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && 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.isSecretChat) ? chatInformationPage.chatPartnerFullInformation.bio : chatInformationPage.groupFullInformation.description) || ""
onSaveButtonClicked: {
if ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat)) { // own bio
tdLibWrapper.setBio(textValue);
} else { // group info
tdLibWrapper.setChatDescription(chatInformationPage.chatInformation.id, textValue);
}
}
}
InformationTextItem {
headerText: qsTr("Phone Number", "user phone number header")
text: ((chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) && 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
InformationTextItem {
id: inviteLinkItem
text: !(chatInformationPage.isPrivateChat || chatInformationPage.isSecretChat) ? chatInformationPage.groupFullInformation.invite_link : ""
width: parent.width - inviteLinkButton.width
}
IconButton {
id: inviteLinkButton
icon.source: "image://theme/icon-m-clipboard"
anchors.verticalCenter: inviteLinkItem.verticalCenter
onClicked: {
Clipboard.text = chatInformationPage.groupFullInformation.invite_link
appNotification.show(qsTr("The Invite Link has been copied to the clipboard."));
}
}
}
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 { FadeAnimation {}}
}
}
Loader {
id: tabViewLoader
asynchronous: true
active: false
anchors {
left: parent.left
right: parent.right
top: groupInfoItem.bottom
}
sourceComponent: Component {
ChatInformationTabView {
id: tabView
height: tabView.count > 0 ? chatInformationPage.height - headerItem.height : 0
}
}
}
}
}