11import QtQuick 2.13
2+ import QtQml.Models 2.14
3+ import QtQuick.Controls 2.13 as QC
24
35import StatusQ.Core 0.1
46import StatusQ.Core.Theme 0.1
@@ -13,7 +15,8 @@ Column {
1315
1416 property string categoryId: " "
1517 property string selectedChatId: " "
16- property alias chatListItems: statusChatListItems
18+ property alias chatListItems: delegateModel
19+ property bool draggableItems: false
1720
1821 property Component popupMenu
1922
@@ -23,82 +26,209 @@ Column {
2326
2427 signal chatItemSelected (string id)
2528 signal chatItemUnmuted (string id)
29+ signal chatItemReordered (string id, int from, int to)
30+
31+ function getAbsolutePosition (node ) {
32+ var returnPos = {};
33+ returnPos .x = 0 ;
34+ returnPos .y = 0 ;
35+ if (node !== undefined && node !== null ) {
36+ var parentValue = getAbsolutePosition (node .parent );
37+ returnPos .x = parentValue .x + node .x ;
38+ returnPos .y = parentValue .y + node .y ;
39+ }
40+ return returnPos;
41+ }
2642
2743 onPopupMenuChanged: {
2844 if (!! popupMenu) {
2945 popupMenuSlot .sourceComponent = popupMenu
3046 }
3147 }
3248
33- Repeater {
34- id: statusChatListItems
35- delegate: StatusChatListItem {
49+ DelegateModel {
50+ id: delegateModel
3651
37- id: statusChatListItem
52+ delegate: Item {
53+ id: draggable
54+ width: statusChatListItem .width
55+ height: statusChatListItem .height
3856
39- property string profileImage : " "
57+ property alias chatListItem : statusChatListItem
4058
41- Component . onCompleted : {
42- if (typeof statusChatList .profileImageFn === " function " ) {
43- profileImage = statusChatList .profileImageFn (model . chatId || model . id ) || " "
59+ visible : {
60+ if (!! statusChatList .filterFn ) {
61+ return statusChatList .filterFn (model, statusChatList . categoryId )
4462 }
63+ return true
4564 }
4665
47- chatId: model .chatId || model .id
48- name: !! statusChatList .chatNameFn ? statusChatList .chatNameFn (model) : model .name
49- type: model .chatType
50- muted: !! model .muted
51- hasUnreadMessages: !! model .hasUnreadMessages || model .unviewedMessagesCount > 0
52- hasMention: model .mentionsCount > 0
53- badge .value : model .chatType === StatusChatListItem .Type .OneToOneChat ?
54- model .unviewedMessagesCount || 0 :
55- model .mentionsCount || 0
56- selected: (model .chatId || model .id ) === statusChatList .selectedChatId
57-
58- icon .color : model .color || " "
59- image .isIdenticon : !!! profileImage && !!! model .identityImage && !! model .identicon
60- image .source : profileImage || model .identityImage || model .identicon || " "
61-
62- onClicked: {
63- if (mouse .button === Qt .RightButton && !! statusChatList .popupMenu ) {
64- statusChatListItem .highlighted = true
65-
66- let originalOpenHandler = popupMenuSlot .item .openHandler
67- let originalCloseHandler = popupMenuSlot .item .closeHandler
68-
69- popupMenuSlot .item .openHandler = function () {
70- if (!! originalOpenHandler) {
71- originalOpenHandler ((model .chatId || model .id ))
72- }
66+ MouseArea {
67+ id: dragSensor
68+
69+ anchors .fill : parent
70+ cursorShape: active ? Qt .ClosedHandCursor : Qt .PointingHandCursor
71+ hoverEnabled: true
72+ pressAndHoldInterval: 150
73+ enabled: statusChatList .draggableItems
74+
75+ property bool active: false
76+ property real startY: 0
77+ property real startX: 0
78+
79+ drag .target : draggedListItemLoader .item
80+ drag .threshold : 0.1
81+ drag .filterChildren : true
82+
83+ onPressed: {
84+ startY = mouseY
85+ startX = mouseX
86+ }
87+ onPressAndHold: active = true
88+ onReleased: {
89+ if (active) {
90+ statusChatList .chatItemReordered (statusChatListItem .chatId , statusChatListItem .originalOrder , statusChatListItem .originalOrder )
91+ }
92+ active = false
93+ }
94+ onMouseYChanged: {
95+ if ((Math .abs (startY - mouseY) > 1 ) && pressed) {
96+ active = true
97+ }
98+ }
99+ onMouseXChanged: {
100+ if ((Math .abs (startX - mouseX) > 1 ) && pressed) {
101+ active = true
73102 }
103+ }
104+
105+ StatusChatListItem {
74106
75- popupMenuSlot .item .closeHandler = function () {
76- if (statusChatListItem) {
77- statusChatListItem .highlighted = false
107+ id: statusChatListItem
108+
109+ property string profileImage: " "
110+
111+ opacity: dragSensor .active ? 0.0 : 1.0
112+ Component .onCompleted : {
113+ if (typeof statusChatList .profileImageFn === " function" ) {
114+ profileImage = statusChatList .profileImageFn (model .chatId || model .id ) || " "
78115 }
79- if (!! originalCloseHandler) {
80- originalCloseHandler ()
116+ }
117+ originalOrder: model .position
118+ chatId: model .chatId || model .id
119+ categoryId: model .categoryId || " "
120+ name: !! statusChatList .chatNameFn ? statusChatList .chatNameFn (model) : model .name
121+ type: model .chatType
122+ muted: !! model .muted
123+ hasUnreadMessages: !! model .hasUnreadMessages || model .unviewedMessagesCount > 0
124+ hasMention: model .mentionsCount > 0
125+ badge .value : model .chatType === StatusChatListItem .Type .OneToOneChat ?
126+ model .unviewedMessagesCount || 0 :
127+ model .mentionsCount || 0
128+ selected: (model .chatId || model .id ) === statusChatList .selectedChatId
129+
130+ icon .color : model .color || " "
131+ image .isIdenticon : !!! profileImage && !!! model .identityImage && !! model .identicon
132+ image .source : profileImage || model .identityImage || model .identicon || " "
133+
134+ sensor .cursorShape : dragSensor .cursorShape
135+ onClicked: {
136+ if (mouse .button === Qt .RightButton && !! statusChatList .popupMenu ) {
137+ statusChatListItem .highlighted = true
138+
139+ let originalOpenHandler = popupMenuSlot .item .openHandler
140+ let originalCloseHandler = popupMenuSlot .item .closeHandler
141+
142+ popupMenuSlot .item .openHandler = function () {
143+ if (!! originalOpenHandler) {
144+ originalOpenHandler ((model .chatId || model .id ))
145+ }
146+ }
147+
148+ popupMenuSlot .item .closeHandler = function () {
149+ if (statusChatListItem) {
150+ statusChatListItem .highlighted = false
151+ }
152+ if (!! originalCloseHandler) {
153+ originalCloseHandler ()
154+ }
155+ }
156+
157+ popupMenuSlot .item .popup (mouse .x + 4 , statusChatListItem .y + mouse .y + 6 )
158+ popupMenuSlot .item .openHandler = originalOpenHandler
159+ return
160+ }
161+ if (! statusChatListItem .selected ) {
162+ statusChatList .chatItemSelected (model .chatId || model .id )
81163 }
82164 }
83-
84- popupMenuSlot .item .popup (mouse .x + 4 , statusChatListItem .y + mouse .y + 6 )
85- popupMenuSlot .item .openHandler = originalOpenHandler
86- return
165+ onUnmute: statusChatList .chatItemUnmuted (model .chatId || model .id )
87166 }
88- if (! statusChatListItem .selected ) {
89- statusChatList .chatItemSelected (model .chatId || model .id )
167+ }
168+
169+ DropArea {
170+ id: dropArea
171+ width: dragSensor .active ? 0 : parent .width
172+ height: dragSensor .active ? 0 : parent .height
173+ keys: [" chat-item-category-" + statusChatListItem .categoryId ]
174+
175+ onEntered: reorderDelay .start ()
176+ onDropped: statusChatList .chatItemReordered (statusChatListItem .chatId , drag .source .originalOrder , statusChatListItem .DelegateModel .itemsIndex )
177+
178+ Timer {
179+ id: reorderDelay
180+ interval: 100
181+ repeat: false
182+ onTriggered: {
183+ if (dropArea .containsDrag ) {
184+ dropArea .drag .source .chatListItem .originalOrder = statusChatListItem .originalOrder
185+ delegateModel .items .move (dropArea .drag .source .DelegateModel .itemsIndex , draggable .DelegateModel .itemsIndex )
186+ }
187+ }
90188 }
91189 }
92- onUnmute: statusChatList .chatItemUnmuted (model .chatId || model .id )
93- visible: {
94- if (!! statusChatList .filterFn ) {
95- return statusChatList .filterFn (model, statusChatList .categoryId )
190+
191+ Loader {
192+ id: draggedListItemLoader
193+ active: dragSensor .active
194+ sourceComponent: StatusChatListItem {
195+ property var globalPosition: statusChatList .getAbsolutePosition (draggable)
196+ parent: QC .Overlay .overlay
197+ sensor .cursorShape : dragSensor .cursorShape
198+ Drag .active : dragSensor .active
199+ Drag .hotSpot .x : width / 2
200+ Drag .hotSpot .y : height / 2
201+ Drag .keys : [" chat-item-category-" + categoryId]
202+ Drag .source : draggable
203+
204+ Component .onCompleted : {
205+ x = globalPosition .x
206+ y = globalPosition .y
207+ }
208+ chatId: draggable .chatListItem .chatId
209+ categoryId: draggable .chatListItem .categoryId
210+ name: draggable .chatListItem .name
211+ type: draggable .chatListItem .type
212+ muted: draggable .chatListItem .muted
213+ dragged: true
214+ hasUnreadMessages: draggable .chatListItem .hasUnreadMessages
215+ hasMention: draggable .chatListItem .hasMention
216+ badge .value : draggable .chatListItem .badge .value
217+ selected: draggable .chatListItem .selected
218+
219+ icon .color : draggable .chatListItem .icon .color
220+ image .isIdenticon : draggable .chatListItem .image .isIdenticon
221+ image .source : draggable .chatListItem .image .source
96222 }
97- return true
98223 }
99224 }
100225 }
101226
227+ Repeater {
228+ id: statusChatListItems
229+ model: delegateModel
230+ }
231+
102232 Loader {
103233 id: popupMenuSlot
104234 active: !! statusChatList .popupMenu
0 commit comments