2020-11-16 23:38:55 +03:00
/ *
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
2020-11-17 11:51:37 +03:00
import "../"
import "../../js/twemoji.js" as Emoji
import "../../js/functions.js" as Functions
2020-11-20 23:58:26 +03:00
import "../../js/debug.js" as Debug
2020-11-16 23:38:55 +03:00
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 ;
2020-11-28 21:11:51 +03:00
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 ;
2020-11-16 23:38:55 +03:00
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 ;
}
2020-11-28 21:11:51 +03:00
Debug . log ( "is set up" , chatInformationPage . isPrivateChat , chatInformationPage . isSecretChat , chatInformationPage . isBasicGroup , chatInformationPage . isSuperGroup , chatInformationPage . chatPartnerGroupId )
if ( ! ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) ) {
2020-11-16 23:38:55 +03:00
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 . 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 ( ) {
2020-11-18 17:50:23 +03:00
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 ) ) ) ;
2020-11-16 23:38:55 +03:00
} else {
if ( isChannel ) {
2020-11-18 17:50:23 +03:00
headerItem . description = qsTr ( "%1 subscribers" , "" , chatInformationPage . groupInformation . member_count ) . arg ( Functions . getShortenedCount ( chatInformationPage . groupInformation . member_count ) ) ;
2020-11-16 23:38:55 +03:00
} else {
2020-11-18 17:50:23 +03:00
headerItem . description = qsTr ( "%1 members" , "" , chatInformationPage . groupInformation . member_count ) . arg ( Functions . getShortenedCount ( chatInformationPage . groupInformation . member_count ) ) ;
2020-11-16 23:38:55 +03:00
}
}
}
Connections {
target: tdLibWrapper
onChatOnlineMemberCountUpdated: {
if ( ( chatInformationPage . isSuperGroup || chatInformationPage . isBasicGroup ) && chatInformationPage . chatInformation . id . toString ( ) === chatId ) {
2020-11-17 14:59:32 +03:00
chatInformationPage . chatOnlineMemberCount = onlineMemberCount ;
2020-11-16 23:38:55 +03:00
updateGroupStatusText ( ) ;
}
}
onSupergroupFullInfoReceived: {
2020-11-20 23:58:26 +03:00
Debug . log ( "onSupergroupFullInfoReceived" , chatInformationPage . isSuperGroup , chatInformationPage . chatPartnerGroupId , groupId )
2020-11-16 23:38:55 +03:00
if ( chatInformationPage . isSuperGroup && chatInformationPage . chatPartnerGroupId === groupId ) {
chatInformationPage . groupFullInformation = groupFullInfo ;
}
}
onSupergroupFullInfoUpdated: {
2020-11-20 23:58:26 +03:00
Debug . log ( "onSupergroupFullInfoUpdated" , chatInformationPage . isSuperGroup , chatInformationPage . chatPartnerGroupId , groupId )
2020-11-16 23:38:55 +03:00
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: {
2020-11-28 21:11:51 +03:00
if ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) && userFullInfo [ "@extra" ] === chatInformationPage . chatPartnerGroupId ) {
2020-11-16 23:38:55 +03:00
chatInformationPage . chatPartnerFullInformation = userFullInfo ;
}
}
onUserFullInfoUpdated: {
2020-11-28 21:11:51 +03:00
if ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) && userId === chatInformationPage . chatPartnerGroupId ) {
2020-11-16 23:38:55 +03:00
chatInformationPage . chatPartnerFullInformation = userFullInfo ;
}
}
onUserProfilePhotosReceived: {
2020-11-28 21:11:51 +03:00
if ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) && extra === chatInformationPage . chatPartnerGroupId ) {
2020-11-16 23:38:55 +03:00
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
}
}
}
2020-11-28 21:11:51 +03:00
Component.onCompleted: {
2020-11-16 23:38:55 +03:00
initializePage ( ) ;
}
ListModel {
id: membersList
}
PullDownMenu {
MenuItem {
2020-11-18 12:34:13 +03:00
visible: ( chatInformationPage . isSuperGroup || chatInformationPage . isBasicGroup ) && chatInformationPage . groupInformation && chatInformationPage . groupInformation . status [ "@type" ] !== "chatMemberStatusBanned"
2020-11-16 23:38:55 +03:00
text: chatInformationPage . userIsMember ? qsTr ( "Leave Chat" ) : qsTr ( "Join Chat" )
onClicked: {
// ensure it's done even if the page is closed:
if ( chatInformationPage . userIsMember ) {
2020-11-29 15:33:14 +03:00
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 ) } ) ) ;
} ) ;
2020-11-16 23:38:55 +03:00
} 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" )
}
2020-11-28 21:11:51 +03:00
MenuItem {
visible: chatInformationPage . isPrivateChat
onClicked: {
2021-01-10 04:06:41 +03:00
tdLibWrapper . createNewSecretChat ( chatInformationPage . chatPartnerGroupId , "openDirectly" ) ;
2020-11-28 21:11:51 +03:00
}
text: qsTr ( "New Secret Chat" )
}
2020-11-16 23:38:55 +03:00
}
// 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
2020-11-29 15:33:14 +03:00
property int minY: Theme . paddingMedium
2020-11-16 23:38:55 +03:00
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 ? chatInformationPage.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
optimizeImageSize: false
}
Loader {
id: profilePictureLoader
active: imageContainer . hasImage
asynchronous: true
anchors.fill: chatPictureThumbnail
2020-11-28 21:11:51 +03:00
source: ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat )
2020-11-23 10:27:56 +03:00
? "ChatInformationProfilePictureList.qml"
: "ChatInformationProfilePicture.qml"
2020-11-16 23:38:55 +03:00
}
}
2020-11-18 12:27:48 +03:00
leftMargin: imageContainer . getEased ( ( imageContainer . minDimension + Theme . paddingMedium ) , 0 , imageContainer . tweenFactor ) + Theme . horizontalPageMargin
2020-11-22 01:56:03 +03:00
title: chatInformationPage . chatInformation . title !== "" ? Emoji . emojify ( chatInformationPage . chatInformation . title , Theme . fontSizeLarge ) : qsTr ( "Unknown" )
2020-11-28 21:11:51 +03:00
description: ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) ? ( "@" + ( chatInformationPage . privateChatUserInformation . username || chatInformationPage . chatPartnerGroupId ) ) : ""
2020-11-16 23:38:55 +03:00
}
SilicaFlickable {
id: contentFlickable
contentHeight: groupInfoItem . height + tabViewLoader . height
clip: true
2020-11-17 12:09:06 +03:00
interactive: ! scrollUpAnimation . running && ! scrollDownAnimation . running
2020-11-16 23:38:55 +03:00
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
2020-11-28 21:11:51 +03:00
canEdit: ! ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) && chatInformationPage . groupInformation . status && ( chatInformationPage . groupInformation . status . can_change_info || chatInformationPage . groupInformation . status [ "@type" ] === "chatMemberStatusCreator" )
2020-11-16 23:38:55 +03:00
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
}
}
}
ChatInformationEditArea {
2020-11-28 21:11:51 +03:00
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" ) )
2020-11-16 23:38:55 +03:00
emptyPlaceholderText: qsTr ( "There is no information text available, yet." )
headerText: qsTr ( "Info" , "group or user infotext header" )
multiLine: true
2020-11-28 21:11:51 +03:00
text: ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) ? chatInformationPage.chatPartnerFullInformation.bio : chatInformationPage . groupFullInformation . description ) || ""
2020-11-16 23:38:55 +03:00
onSaveButtonClicked: {
2020-11-28 21:11:51 +03:00
if ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) ) { // own bio
2020-11-16 23:38:55 +03:00
tdLibWrapper . setBio ( textValue ) ;
} else { // group info
tdLibWrapper . setChatDescription ( chatInformationPage . chatInformation . id , textValue ) ;
}
}
}
ChatInformationTextItem {
headerText: qsTr ( "Phone Number" , "user phone number header" )
2020-11-28 21:11:51 +03:00
text: ( ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) && chatInformationPage . privateChatUserInformation . phone_number ? "+" + chatInformationPage.privateChatUserInformation.phone_number : "" ) || ""
2020-11-16 23:38:55 +03:00
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
2020-11-28 21:11:51 +03:00
text: ! ( chatInformationPage . isPrivateChat || chatInformationPage . isSecretChat ) ? chatInformationPage.groupFullInformation.invite_link : ""
2020-11-16 23:38:55 +03:00
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
2020-11-23 22:15:28 +03:00
appNotification . show ( qsTr ( "The Invite Link has been copied to the clipboard." ) ) ;
2020-11-16 23:38:55 +03:00
}
}
}
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
2020-11-17 12:09:06 +03:00
Behavior on opacity { FadeAnimation { } }
2020-11-16 23:38:55 +03:00
}
}
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
}
}
}
}
}