1import QtQuick 2.0
2import AsemanTools.Controls 1.0
3import AsemanTools 1.0
4import TelegramQmlLib 1.0
5// import CutegramTypes 1.0
6import QtGraphicalEffects 1.0
7
8Item {
9    id: ad_list
10    width: minimum? 80*Devices.density : Cutegram.currentTheme.dialogListWidth*Devices.density
11
12    property alias telegramObject: dialogs_model.telegram
13    property Dialog currentDialog: telegramObject.dialog(0)
14
15    property bool unminimumForce: false
16    property bool minimum: Cutegram.minimumDialogs && !unminimumForce && !forceUnminimum
17    property bool forceUnminimum: false
18
19    property bool showLastMessage: Cutegram.showLastMessage
20
21    property real typeMessageMediaDocument: 0x2fda2204
22    property real typeMessageMediaContact: 0x5e7d2f39
23    property real typeMessageMediaVideo: 0x5bcf1675
24    property real typeMessageMediaEmpty: 0x3ded6320
25    property real typeMessageMediaAudio: 0xc6b68300
26    property real typeMessageMediaPhoto: 0x3d8ce53d
27    property real typeMessageMediaGeo: 0x56e0d474
28
29    property real typeMessageActionEmpty: 0xb6aef7b0
30    property real typeMessageActionChatDeletePhoto: 0x95e3fbef
31    property real typeMessageActionChatCreate: 0xa6638b9a
32    property real typeMessageActionChatEditTitle: 0xb5a1ce5a
33    property real typeMessageActionChatEditPhoto: 0x7fcb13a8
34    property real typeMessageActionGeoChatCreate: 0x6f038ebc
35    property real typeMessageActionChatDeleteUser: 0xb2ae9b0c
36    property real typeMessageActionChatAddUser: 0x5e3cfc4b
37    property real typeMessageActionGeoChatCheckin: 0xc7d53de
38
39    signal windowRequest(variant dialog)
40
41    onCurrentDialogChanged: {
42        dlist.currentIndex = dialogs_model.indexOf(currentDialog)
43    }
44
45    Behavior on width {
46        NumberAnimation{ easing.type: Easing.OutCubic; duration: 400 }
47    }
48
49    DialogsModel {
50        id: dialogs_model
51        stopUpdating: main.dragging
52        onInitializingChanged: {
53            if( initializing )
54                indicator.start()
55            else
56                indicator.stop()
57        }
58    }
59
60    Indicator {
61        id: indicator
62        anchors.centerIn: parent
63        light: true
64        modern: true
65        indicatorSize: 20*Devices.density
66    }
67
68    AsemanListView {
69        id: dlist
70        width: Cutegram.currentTheme.dialogListWidth*Devices.density - x
71        height: parent.height
72        x: Cutegram.currentTheme.dialogListScrollWidth*Devices.density
73        clip: true
74        model: dialogs_model
75        maximumFlickVelocity: 2000
76        flickDeceleration: 2000
77
78        currentIndex: -1
79        highlightMoveDuration: 0
80        highlight: Item {
81            width: dlist.width
82            height: showLastMessage? 60*Devices.density : 54*Devices.density
83
84            Rectangle {
85                anchors.fill: parent
86                anchors.topMargin: 3*Devices.density
87                anchors.bottomMargin: 3*Devices.density
88                anchors.rightMargin: -radius
89                color: Cutegram.currentTheme.dialogListHighlightColor
90                radius: 5*Devices.density
91
92                Rectangle {
93                    anchors.bottom: parent.bottom
94                    anchors.left: parent.right
95                    anchors.leftMargin: -parent.radius
96                    transformOrigin: Item.BottomLeft
97                    rotation: -90
98                    width: parent.height
99                    height: Cutegram.currentTheme.dialogListShadowWidth*Devices.density
100                    opacity: 0.4
101                    gradient: Gradient {
102                        GradientStop { position: 0.0; color: "#00000000" }
103                        GradientStop { position: 1.0; color: Cutegram.currentTheme.dialogListShadowColor }
104                    }
105                }
106            }
107
108            Item {
109                id: pointer_frame
110                width: pointer_rct.width*Math.pow(2,0.5)*2
111                height: width
112                x: ad_list.width - width/2 - dlist.x
113                anchors.verticalCenter: parent.verticalCenter
114                visible: false
115
116                Rectangle {
117                    id: pointer_rct
118                    anchors.centerIn: parent
119                    transformOrigin: Item.Center
120                    rotation: 45
121                    width: Cutegram.currentTheme.dialogPointerHeight*Devices.density
122                    height: width
123                    color: Cutegram.currentTheme.dialogPointerColor
124                }
125            }
126
127            DropShadow {
128                anchors.fill: pointer_frame
129                radius: Cutegram.currentTheme.dialogListShadowWidth
130                samples: 16
131                color: Cutegram.currentTheme.dialogListShadowColor
132                source: pointer_frame
133            }
134        }
135
136//        move: Transition {
137//            NumberAnimation { easing.type: Easing.OutCubic; properties: "y"; duration: 300 }
138//        }
139//        moveDisplaced: Transition {
140//            NumberAnimation { easing.type: Easing.OutCubic; properties: "y"; duration: 300 }
141//        }
142
143        delegate: Item {
144            id: list_item
145            width: dlist.width
146            height: showLastMessage? 60*Devices.density : 54*Devices.density
147            clip: true
148
149            property Dialog dItem: item
150
151            property bool isChat: dItem.peer.chatId != 0
152            property User user: telegramObject.user(dItem.encrypted?enChatUid:dItem.peer.userId)
153            property Chat chat: telegramObject.chat(dItem.peer.chatId)
154
155            property EncryptedChat enchat: telegramObject.encryptedChat(dItem.peer.userId)
156            property int enChatUid: enchat.adminId==telegramObject.me? enchat.participantId : enchat.adminId
157
158            property Message message: telegramObject.message(dItem.topMessage)
159            property variant msgDate: CalendarConv.fromTime_t(message.date)
160
161            property bool selected: currentDialog==dItem
162            property real itemOpacities: minimum? 0 : 1
163
164            property bool disableBadges: (telegramObject.userData.notify(isChat? chat.id : user.id) & UserData.DisableBadges)
165
166            onSelectedChanged: if(selected) dlist.currentIndex = index
167
168            Connections {
169                target: telegramObject.userData
170                onNotifyChanged: {
171                    if(isChat && id == chat.id)
172                        disableBadges = value
173                    else
174                    if(!isChat && id == user.id)
175                        disableBadges = value
176                }
177            }
178
179            Behavior on itemOpacities {
180                NumberAnimation{ easing.type: Easing.OutCubic; duration: 400 }
181            }
182
183            Rectangle {
184                anchors.fill: parent
185                opacity: marea.pressed && !selected? 1 : 0
186                anchors.topMargin: 3*Devices.density
187                anchors.bottomMargin: 3*Devices.density
188                color: Cutegram.currentTheme.dialogListHighlightColor
189                radius: 5*Devices.density
190            }
191
192            Item {
193                anchors.fill: parent
194                anchors.topMargin: 3*Devices.density
195                anchors.bottomMargin: 3*Devices.density
196                anchors.leftMargin: 5*Devices.density
197                anchors.rightMargin: 12*Devices.density
198
199                Frame {
200                    id: profile_img
201                    anchors.top: parent.top
202                    anchors.bottom: parent.bottom
203                    anchors.left: parent.left
204                    anchors.margins: 4*Devices.density
205                    width: height
206                    backgroundColor: selected || marea.pressed? Cutegram.currentTheme.dialogListHighlightColor : Cutegram.currentTheme.dialogListBackground
207
208                    ContactImage {
209                        id: contact_img
210                        anchors.fill: parent
211                        dialog: dItem
212                        circleMode: false
213                    }
214                }
215
216                Image {
217                    anchors.bottom: profile_img.bottom
218                    anchors.right: profile_img.right
219                    anchors.margins: -4*Devices.density
220                    source: "files/online.png"
221                    sourceSize: Qt.size(width,height)
222                    width: 14*Devices.density
223                    height: 14*Devices.density
224                    visible: isChat? false : (user.status.classType == contact_img.typeUserStatusOnline)
225                }
226
227                Text {
228                    id: title_txt
229                    anchors.top: parent.top
230                    anchors.bottom: showLastMessage? parent.verticalCenter : parent.bottom
231                    anchors.left: profile_img.right
232                    anchors.right: time_txt.left
233                    anchors.margins: 4*Devices.density
234                    font.pixelSize: Math.floor(11*Devices.fontDensity)
235                    font.family: Cutegram.currentTheme.dialogListFont.family
236                    horizontalAlignment: Text.AlignLeft
237                    verticalAlignment: Text.AlignVCenter
238                    color: selected || marea.pressed? Cutegram.currentTheme.dialogListHighlightTextColor : Cutegram.currentTheme.dialogListFontColor
239                    wrapMode: Text.WrapAnywhere
240                    elide: Text.ElideRight
241                    maximumLineCount: 1
242                    textFormat: Text.RichText
243                    text: emojis.textToEmojiText( isChat? chat.title : user.firstName + " " + user.lastName, 16, true)
244                    opacity: itemOpacities
245                }
246
247                Image {
248                    x: title_txt.x + title_txt.paintedWidth + 4*Devices.density
249                    anchors.verticalCenter: parent.verticalCenter
250                    source: Cutegram.currentTheme.dialogListLightIcon? "files/lock.png" : "files/lock-dark.png"
251                    sourceSize: Qt.size(width, height)
252                    visible: dItem.encrypted
253                    width: 14*Devices.density
254                    height: width
255                }
256
257                Text {
258                    id: msg_txt
259                    anchors.top: parent.verticalCenter
260                    anchors.bottom: parent.bottom
261                    anchors.left: profile_img.right
262                    anchors.right: parent.right
263                    anchors.margins: 4*Devices.density
264                    anchors.topMargin: 0
265                    textFormat: Text.RichText
266                    font.pixelSize: Math.floor(Cutegram.currentTheme.dialogListMessageFont.pointSize*Devices.fontDensity)
267                    font.family: Cutegram.currentTheme.dialogListMessageFont.family
268                    color: selected || marea.pressed? Cutegram.currentTheme.dialogListHighlightMessageColor : Cutegram.currentTheme.dialogListMessageColor
269                    wrapMode: Text.WrapAnywhere
270                    elide: Text.ElideRight
271                    maximumLineCount: 1
272                    lineHeight: 100
273                    clip: true
274                    opacity: itemOpacities
275                    visible: showLastMessage
276                    text: {
277                        if(!visible)
278                            return ""
279                        var list = dItem.typingUsers
280                        if( list.length )
281                        {
282                            if(!isChat)
283                                return qsTr("Typing...")
284                            else
285                            {
286                                var result = ""
287                                for( var i=0; i<list.length; i++ ) {
288                                    var uid = list[i]
289                                    var user = telegramObject.user(list[i])
290                                    var uname = user.firstName + " " + user.lastName
291                                    result += uname.trim()
292
293                                    if( i < list.length-1 )
294                                        result += ", "
295                                }
296
297                                return result.trim() + " typing..."
298                            }
299                        }
300                        else
301                        {
302                            var message_text = ""
303                            if(message.media.classType != typeMessageMediaEmpty)
304                            {
305                                switch(message.media.classType)
306                                {
307                                    case typeMessageMediaDocument:
308                                        message_text = qsTr("Document")
309                                        break;
310                                    case typeMessageMediaContact:
311                                        message_text = qsTr("Contact")
312                                        break;
313                                    case typeMessageMediaVideo:
314                                        message_text = qsTr("Video")
315                                        break;
316                                    case typeMessageMediaAudio:
317                                        message_text = qsTr("Audio")
318                                        break;
319                                    case typeMessageMediaPhoto:
320                                        message_text = qsTr("Photo")
321                                        break;
322                                    case typeMessageMediaGeo:
323                                        message_text = qsTr("Location")
324                                        break;
325                                    default:
326                                        message_text = qsTr("Unknown")
327                                        break;
328                                }
329                            }
330                            else if(message.action.classType != typeMessageActionEmpty)
331                            {
332                                var res = ""
333                                var userName
334                                var fromUserName = telegramObject.user(message.fromId).firstName + " " + telegramObject.user(message.fromId).lastName
335                                fromUserName = fromUserName.trim()
336
337                                switch(message.action.classType) {
338                                case typeMessageActionChatCreate:
339                                    res = qsTr("%1 created the group \"%2\"").arg(fromUserName).arg(message.action.title)
340                                    break
341
342                                case typeMessageActionChatAddUser:
343                                    userName = telegramObject.user(message.action.userId).firstName + " " + telegramObject.user(message.action.userId).lastName
344                                    userName = userName.trim()
345
346                                    res = qsTr("%1 added %2 to group").arg(fromUserName).arg(userName)
347                                    break
348
349                                case typeMessageActionChatDeleteUser:
350                                    userName = telegramObject.user(message.action.userId).firstName + " " + telegramObject.user(message.action.userId).lastName
351                                    userName = userName.trim()
352
353                                    if(telegramObject.user(message.action.userId).id == telegramObject.user(message.fromId).id)
354                                        res = qsTr("%1 left the group").arg(userName)
355                                    else
356                                        res = qsTr("%1 kicked %2").arg(fromUserName).arg(userName)
357                                    break;
358
359                                case typeMessageActionChatEditTitle:
360                                    res = qsTr("%1 changed group name to \"%2\"").arg(fromUserName).arg(message.action.title)
361                                    break
362
363                                case typeMessageActionChatEditPhoto:
364                                    res = qsTr("%1 changed group photo.").arg(fromUserName)
365                                    break
366
367                                case typeMessageActionChatDeletePhoto:
368                                    res = qsTr("%1 deleted group photo").arg(fromUserName)
369                                    break
370
371                                default:
372                                    break
373                                }
374
375                                message_text = emojis.textToEmojiText(res, 16, true)
376                            }
377                            else
378                            {
379                                message_text = emojis.textToEmojiText(message.message,16,true)
380                            }
381
382                            if(isChat && message.action.classType == typeMessageActionEmpty)
383                            {
384                                var chat_username = ""
385                                if(message.fromId == telegramObject.me)
386                                    chat_username = qsTr("You")
387                                else
388                                    chat_username = telegramObject.user(message.fromId).firstName + " " + telegramObject.user(message.fromId).lastName
389
390                                message_text = chat_username.trim() + ": " + message_text
391                            }
392
393                            return message_text
394                        }
395                    }
396                }
397
398                Text {
399                    id: time_txt
400                    anchors.top: parent.top
401                    anchors.right: parent.right
402                    anchors.margins: 4*Devices.density
403                    font.family: Cutegram.currentTheme.dialogListDateFont.family
404                    font.pixelSize: Math.floor(Cutegram.currentTheme.dialogListDateFont.pointSize*Devices.fontDensity)
405                    color: selected || marea.pressed? Cutegram.currentTheme.dialogListHighlightDateColor : Cutegram.currentTheme.dialogListDateColor
406                    text: Cutegram.getTimeString(msgDate)
407                    opacity: itemOpacities
408                    visible: showLastMessage
409                }
410
411                UnreadItem {
412                    unread: dItem.unreadCount
413                    visible: unread != 0 && !selected && !disableBadges
414                }
415            }
416
417            MouseArea {
418                id: marea
419                anchors.fill: parent
420                hoverEnabled: true
421                acceptedButtons: Qt.LeftButton | Qt.RightButton
422                onContainsMouseChanged: toggleMinimum(containsMouse)
423                onDoubleClicked: ad_list.windowRequest(list_item.dItem)
424                onPressed: {
425                    if( mouse.button == Qt.RightButton ) {
426                        var actions, res
427                        if(dItem.encrypted) {
428                            actions = [qsTr("Open in New Window"), qsTr("Delete")]
429                            res = Desktop.showMenu(actions)
430                            switch(res) {
431                            case 0:
432                                ad_list.windowRequest(list_item.dItem)
433                                break;
434                            case 1:
435                                if( Desktop.yesOrNo(View, qsTr("Delete secret chat"), qsTr("Are you sure about deleting this secret chat?")) )
436                                    telegramObject.messagesDiscardEncryptedChat(dItem.peer.userId, true)
437                                break;
438                            }
439                        } else if(user.id == telegramObject.cutegramId) {
440                            actions = [qsTr("Delete")]
441                            res = Desktop.showMenu(actions)
442                            switch(res) {
443                            case 0:
444                                telegramObject.deleteCutegramDialog()
445                                break;
446                            }
447                        } else if(isChat) {
448                            actions = [qsTr("Open in New Window"), qsTr("Delete History")]
449                            res = Desktop.showMenu(actions)
450                            switch(res) {
451                            case 0:
452                                ad_list.windowRequest(list_item.dItem)
453                                break;
454                            case 1:
455                                if( Desktop.yesOrNo(View, qsTr("Delete History"), qsTr("Are you sure about deleting history?")) )
456                                    telegramObject.messagesDeleteHistory(dItem.peer.chatId)
457                                break;
458                            }
459                        } else {
460                            var notifyValue = telegramObject.userData.notify(dItem.peer.userId)
461                            var notifyOnline = notifyValue & UserData.NotifyOnline
462                            var notifyTyping = notifyValue & UserData.NotifyTyping
463                            var notifyMenu = {"text": qsTr("Notify when"),
464                                "list":[{"text": qsTr("Go online"), "checkable": true, "checked": notifyOnline}]}
465//                                        {"text": qsTr("Start typing"), "checkable": true, "checked": notifyTyping}]}
466
467                            actions = [qsTr("Open in New Window"), qsTr("Delete History"), notifyMenu]
468                            res = Desktop.showMenu(actions)
469                            switch(res) {
470                            case 0:
471                                ad_list.windowRequest(list_item.dItem)
472                                break;
473                            case 1:
474                                if( Desktop.yesOrNo(View, qsTr("Delete History"), qsTr("Are you sure about deleting history?")) )
475                                    telegramObject.messagesDeleteHistory(dItem.peer.userId)
476                                break;
477                            case 2:
478                                var withoutOnline = (notifyValue-notifyOnline)
479                                notifyOnline = notifyOnline? 0 : UserData.NotifyOnline
480                                telegramObject.userData.setNotify(dItem.peer.userId, notifyOnline|withoutOnline)
481                                break;
482                            case 3:
483                                var withoutTyping = (notifyValue-notifyTyping)
484                                notifyTyping = notifyTyping? 0 : UserData.NotifyTyping
485                                telegramObject.userData.setNotify(dItem.peer.userId, notifyTyping|withoutTyping)
486                                break;
487                            }
488                        }
489                    }
490                }
491                onClicked: {
492                    if( mouse.button == Qt.LeftButton )
493                        currentDialog = list_item.dItem
494                }
495            }
496
497            DialogItemTools {
498                anchors.verticalCenter: parent.verticalCenter
499                anchors.right: parent.right
500                anchors.rightMargin: 12*Devices.density
501                height: 22*Devices.density
502                dialog: dItem
503                show: marea.containsMouse
504                opacity: itemOpacities
505            }
506
507            DialogDropFile {
508                anchors.fill: parent
509                dialogItem: dItem
510                color: "#dd222222"
511                onDropped: switch_dialog_timer.restart()
512                onContainsDragChanged: toggleMinimum(containsDrag)
513            }
514
515            Timer {
516                id: switch_dialog_timer
517                interval: 400
518                onTriggered: {
519                    currentDialog = list_item.dItem
520                    dlist.currentIndex = index
521                }
522            }
523        }
524
525        section.property: "section"
526        section.criteria: ViewSection.FullString
527        section.labelPositioning: ViewSection.InlineLabels
528        section.delegate: Item {
529            height: 30*Devices.density
530            width: dlist.width
531
532            Image {
533                anchors.left: parent.left
534                anchors.bottom: parent.bottom
535                anchors.margins: 4*Devices.density
536                width: 12*Devices.density
537                height: width
538                sourceSize: Qt.size(width,height)
539                smooth: true
540                source: {
541                    if( section == 0 )
542                        return Cutegram.currentTheme.dialogListLightIcon? "files/contact-light.png" : "files/contact.png"
543                    else
544                    if( section == 1 )
545                        return Cutegram.currentTheme.dialogListLightIcon? "files/favorite-light.png" : "files/favorite.png"
546                    else
547                    if( section == 2 )
548                        return "files/love.png"
549                    else
550                        return ""
551                }
552            }
553        }
554    }
555
556    MouseArea {
557        anchors.left: parent.right
558        anchors.right: dlist.right
559        anchors.top: parent.top
560        anchors.bottom: parent.bottom
561        hoverEnabled: true
562    }
563
564    NormalWheelScroll {
565        flick: dlist
566        animated: Cutegram.smoothScroll
567    }
568
569    Timer {
570        id: restore_minimum_timer
571        interval: 500
572        onTriggered: unminimumForce = false
573    }
574
575    Timer {
576        id: restore_unminimum_timer
577        interval: 50
578        onTriggered: unminimumForce = true
579    }
580
581    PhysicalScrollBar {
582        scrollArea: dlist; height: dlist.height; width: Cutegram.currentTheme.dialogListScrollWidth*Devices.density
583        anchors.right: dlist.left; anchors.top: dlist.top; color: Cutegram.currentTheme.dialogListScrollColor
584    }
585
586    Button {
587        anchors.right: parent.right
588        anchors.verticalCenter: parent.verticalCenter
589        height: 50*Devices.density
590        width: 10*Devices.density
591        normalColor: enter? "#88ffffff" : "#44ffffff"
592        highlightColor: "#aaffffff"
593        onClicked: Cutegram.minimumDialogs = !Cutegram.minimumDialogs
594        cursorShape: Qt.PointingHandCursor
595        icon: Cutegram.minimumDialogs? "files/arrow-right.png" : "files/arrow-left.png"
596        iconHeight: 8*Devices.density
597        visible: false
598
599        Behavior on color {
600            ColorAnimation{ easing.type: Easing.OutCubic; duration: 400 }
601        }
602    }
603
604    function toggleMinimum(stt) {
605        if(!Cutegram.minimumDialogs)
606            return
607        if(stt) {
608            restore_minimum_timer.stop()
609            restore_unminimum_timer.restart()
610        } else {
611            restore_unminimum_timer.stop()
612            restore_minimum_timer.restart()
613        }
614    }
615
616    function next() {
617        var dialog = dialogs_model.at(dlist.currentIndex+1)
618        if(!dialog)
619            return
620
621        currentDialog = dialog
622    }
623
624    function previous() {
625        var dialog = dialogs_model.at(dlist.currentIndex-1)
626        if(!dialog)
627            return
628
629        currentDialog = dialog
630    }
631}
632