diff --git a/src/StatusQ/Components/StatusChatList.qml b/src/StatusQ/Components/StatusChatList.qml
index 8fe20149..29e28740 100644
--- a/src/StatusQ/Components/StatusChatList.qml
+++ b/src/StatusQ/Components/StatusChatList.qml
@@ -11,12 +11,14 @@ import StatusQ.Controls 0.1
Column {
id: statusChatList
- spacing: 4
+ spacing: 0
width: 288
+ property string uuid: Utils.uuid()
+
property string categoryId: ""
property string selectedChatId: ""
- property alias chatListItems: delegateModel
+ property alias chatListItems: statusChatListItems
property bool draggableItems: false
property alias statusChatListItems: statusChatListItems
@@ -29,7 +31,7 @@ Column {
signal chatItemSelected(string id)
signal chatItemUnmuted(string id)
- signal chatItemReordered(string id, int from, int to)
+ signal chatItemReordered(string categoryId, string id, int from, int to)
onPopupMenuChanged: {
if (!!popupMenu) {
@@ -37,191 +39,254 @@ Column {
}
}
- DelegateModel {
- id: delegateModel
+ Column {
+ id: statusChatListItemsWrapper
+ width: parent.width
+ spacing: 4
+ onImplicitHeightChanged: {
+ // For some reason, the binding on emptyListDropAreaLoaoder.active alone doesn't work.
+ // We have to explicitly reassign it here.
+ emptyListDropAreaLoader.active = implicitHeight == 0
+ }
- delegate: Item {
- id: draggable
- width: statusChatListItem.width
- height: statusChatListItem.height
+ Repeater {
+ id: statusChatListItems
+ delegate: Item {
+ id: draggable
+ width: statusChatListItem.width
+ height: statusChatListItem.height
- property alias chatListItem: statusChatListItem
+ property alias chatListItem: statusChatListItem
- visible: {
- if (!!statusChatList.filterFn) {
- return statusChatList.filterFn(model, statusChatList.categoryId)
+ visible: {
+ if (!!statusChatList.filterFn) {
+ return statusChatList.filterFn(model, statusChatList.categoryId)
+ }
+ return true
}
- return true
- }
- MouseArea {
- id: dragSensor
+ MouseArea {
+ id: dragSensor
- anchors.fill: parent
- cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
- hoverEnabled: true
- pressAndHoldInterval: 150
- enabled: statusChatList.draggableItems
-
- property bool active: false
- property real startY: 0
- property real startX: 0
-
- drag.target: draggedListItemLoader.item
- drag.threshold: 0.1
- drag.filterChildren: true
-
- onPressed: {
- startY = mouseY
- startX = mouseX
- }
- onPressAndHold: active = true
- onReleased: {
- if (active) {
- statusChatList.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, statusChatListItem.originalOrder)
+ anchors.fill: parent
+ cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
+ hoverEnabled: true
+ pressAndHoldInterval: 150
+ enabled: statusChatList.draggableItems
+
+ property bool active: false
+ property real startY: 0
+ property real startX: 0
+
+ drag.target: draggedListItemLoader.item
+ drag.threshold: 0.1
+ drag.filterChildren: true
+
+ onPressed: {
+ startY = mouseY
+ startX = mouseX
}
- active = false
- }
- onMouseYChanged: {
- if ((Math.abs(startY - mouseY) > 1) && pressed) {
- active = true
+
+ onPressAndHold: active = true
+ onReleased: {
+ if (active && (statusChatListItem.originalOder !== statusChatListItem.newOrder ||
+ statusChatListItem.categoryId !== statusChatListItem.newCategoryId)) {
+ statusChatList.chatItemReordered(
+ statusChatListItem.newCategoryId,
+ statusChatListItem.chatId,
+ statusChatListItem.originalOrder,
+ statusChatListItem.newOrder
+ )
+ }
+ active = false
}
- }
- onMouseXChanged: {
- if ((Math.abs(startX - mouseX) > 1) && pressed) {
- active = true
+ onMouseYChanged: {
+ if ((Math.abs(startY - mouseY) > 1) && pressed) {
+ active = true
+ }
+ }
+ onMouseXChanged: {
+ if ((Math.abs(startX - mouseX) > 1) && pressed) {
+ active = true
+ }
}
- }
- StatusChatListItem {
+ StatusChatListItem {
- id: statusChatListItem
+ id: statusChatListItem
- property string profileImage: ""
+ property string chatListId: statusChatList.uuid
+ property string profileImage: ""
+ property var newOrder: model.position
+ property var newCategoryId: model.categoryId
- opacity: dragSensor.active ? 0.0 : 1.0
- Component.onCompleted: {
- if (typeof statusChatList.profileImageFn === "function") {
- profileImage = statusChatList.profileImageFn(model.chatId || model.id) || ""
+ anchors.centerIn: parent
+ opacity: dragSensor.active ? 0.3 : 1.0
+ Component.onCompleted: {
+ if (typeof statusChatList.profileImageFn === "function") {
+ profileImage = statusChatList.profileImageFn(model.chatId || model.id) || ""
+ }
}
- }
- originalOrder: model.position
- chatId: model.chatId || model.id
- categoryId: model.categoryId || ""
- name: !!statusChatList.chatNameFn ? statusChatList.chatNameFn(model) : model.name
- type: model.chatType
- muted: !!model.muted
- hasUnreadMessages: !!model.hasUnreadMessages || model.unviewedMessagesCount > 0
- hasMention: model.mentionsCount > 0
- badge.value: model.chatType === StatusChatListItem.Type.OneToOneChat ?
- model.unviewedMessagesCount || 0 :
- model.mentionsCount || 0
- selected: (model.chatId || model.id) === statusChatList.selectedChatId
-
- icon.color: model.color || ""
- image.isIdenticon: !!!profileImage && !!!model.identityImage && !!model.identicon
- image.source: profileImage || model.identityImage || model.identicon || ""
-
- sensor.cursorShape: dragSensor.cursorShape
- onClicked: {
- if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
- statusChatListItem.highlighted = true
-
- let originalOpenHandler = popupMenuSlot.item.openHandler
- let originalCloseHandler = popupMenuSlot.item.closeHandler
-
- popupMenuSlot.item.openHandler = function () {
- if (!!originalOpenHandler) {
- originalOpenHandler((model.chatId || model.id))
+ originalOrder: model.position
+ chatId: model.chatId || model.id
+ categoryId: model.categoryId || ""
+ /* name: (!!statusChatList.chatNameFn ? statusChatList.chatNameFn(model) : model.name) + " POSITION: " + statusChatListItem.newOrder */
+ name: (!!statusChatList.chatNameFn ? statusChatList.chatNameFn(model) : model.name)
+ type: model.chatType
+ muted: !!model.muted
+ hasUnreadMessages: !!model.hasUnreadMessages || model.unviewedMessagesCount > 0
+ hasMention: model.mentionsCount > 0
+ badge.value: model.chatType === StatusChatListItem.Type.OneToOneChat ?
+ model.unviewedMessagesCount || 0 :
+ model.mentionsCount || 0
+ selected: (model.chatId || model.id) === statusChatList.selectedChatId
+
+ icon.color: model.color || ""
+ image.isIdenticon: !!!profileImage && !!!model.identityImage && !!model.identicon
+ image.source: profileImage || model.identityImage || model.identicon || ""
+
+ sensor.cursorShape: dragSensor.cursorShape
+ onClicked: {
+ if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
+ statusChatListItem.highlighted = true
+
+ let originalOpenHandler = popupMenuSlot.item.openHandler
+ let originalCloseHandler = popupMenuSlot.item.closeHandler
+
+ popupMenuSlot.item.openHandler = function () {
+ if (!!originalOpenHandler) {
+ originalOpenHandler((model.chatId || model.id))
+ }
}
- }
- popupMenuSlot.item.closeHandler = function () {
- if (statusChatListItem) {
- statusChatListItem.highlighted = false
- }
- if (!!originalCloseHandler) {
- originalCloseHandler()
+ popupMenuSlot.item.closeHandler = function () {
+ if (statusChatListItem) {
+ statusChatListItem.highlighted = false
+ }
+ if (!!originalCloseHandler) {
+ originalCloseHandler()
+ }
}
+
+ popupMenuSlot.item.popup(mouse.x + 4, statusChatListItem.y + mouse.y + 6)
+ popupMenuSlot.item.openHandler = originalOpenHandler
+ return
+ }
+ if (!statusChatListItem.selected) {
+ statusChatList.chatItemSelected(model.chatId || model.id)
}
+ }
+ onUnmute: statusChatList.chatItemUnmuted(model.chatId || model.id)
- popupMenuSlot.item.popup(mouse.x + 4, statusChatListItem.y + mouse.y + 6)
- popupMenuSlot.item.openHandler = originalOpenHandler
- return
+ StatusChatListDropIndicator {
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: -2
+ visible: dropArea.containsDrag
}
- if (!statusChatListItem.selected) {
- statusChatList.chatItemSelected(model.chatId || model.id)
+ }
+ }
+ DropArea {
+ id: dropArea
+ width: parent.width
+ height: parent.height
+ keys: ["chat-item"]
+
+ onEntered: reorderDelay.start()
+
+ Timer {
+ id: reorderDelay
+ interval: 100
+ repeat: false
+ onTriggered: {
+ if (dropArea.containsDrag) {
+ let newOrder = statusChatListItem.originalOrder
+
+ if (dropArea.drag.source.chatListItem.originalOrder > statusChatListItem.originalOrder) {
+ newOrder = newOrder + 1
+ }
+ dropArea.drag.source.chatListItem.newOrder = newOrder
+ dropArea.drag.source.chatListItem.newCategoryId = statusChatListItem.categoryId
+ }
+ }
+ }
+ }
+ Loader {
+ id: draggedListItemLoader
+ active: dragSensor.active
+ sourceComponent: StatusChatListItem {
+ property string chatListId: draggable.chatListItem.chatListId
+ property var globalPosition: Utils.getAbsolutePosition(draggable)
+ parent: QC.Overlay.overlay
+ sensor.cursorShape: dragSensor.cursorShape
+ Drag.active: dragSensor.active
+ Drag.hotSpot.x: width / 2
+ Drag.hotSpot.y: height / 2
+ Drag.keys: ["chat-item"]
+ Drag.source: draggable
+
+ Component.onCompleted: {
+ x = globalPosition.x
+ y = globalPosition.y
}
+ chatId: draggable.chatListItem.chatId
+ categoryId: draggable.chatListItem.categoryId
+ name: draggable.chatListItem.name
+ type: draggable.chatListItem.type
+ muted: draggable.chatListItem.muted
+ dragged: true
+ hasUnreadMessages: draggable.chatListItem.hasUnreadMessages
+ hasMention: draggable.chatListItem.hasMention
+ badge.value: draggable.chatListItem.badge.value
+ selected: draggable.chatListItem.selected
+
+ icon.color: draggable.chatListItem.icon.color
+ image.isIdenticon: draggable.chatListItem.image.isIdenticon
+ image.source: draggable.chatListItem.image.source
}
- onUnmute: statusChatList.chatItemUnmuted(model.chatId || model.id)
}
}
+ }
+ }
- DropArea {
- id: dropArea
- width: dragSensor.active ? 0 : parent.width
- height: dragSensor.active ? 0 : parent.height
- keys: ["chat-item-category-" + statusChatListItem.categoryId]
+ Loader {
+ id: popupMenuSlot
+ active: !!statusChatList.popupMenu
+ }
- onEntered: reorderDelay.start()
- onDropped: statusChatList.chatItemReordered(statusChatListItem.chatId, drag.source.originalOrder, statusChatListItem.DelegateModel.itemsIndex)
+ Loader {
+ id: emptyListDropAreaLoader
+ active: statusChatListItemsWrapper.implicitHeight == 0
+ width: parent.width
+ height: active ? 8 : 0
+ sourceComponent: Item {
+ width: statusChatList.width
+ height: 8
+
+ StatusChatListDropIndicator {
+ visible: emptyListDropArea.containsDrag
+ opacity: 0.5
+ anchors.bottom: statusChatList.categoryId == "" ? parent.bottom : undefined
+ anchors.top: statusChatList.categoryId !== "" ? parent.top : undefined
+ }
+ DropArea {
+ id: emptyListDropArea
+ anchors.fill: parent
+ visible: parent.visible
+ keys: ["chat-item"]
+ onEntered: reorderDelay2.start()
Timer {
- id: reorderDelay
+ id: reorderDelay2
interval: 100
repeat: false
onTriggered: {
- if (dropArea.containsDrag) {
- dropArea.drag.source.chatListItem.originalOrder = statusChatListItem.originalOrder
- delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
+ if (emptyListDropArea.containsDrag) {
+ emptyListDropArea.drag.source.chatListItem.newOrder = 0
+ emptyListDropArea.drag.source.chatListItem.newCategoryId = statusChatList.categoryId
}
}
}
}
-
- Loader {
- id: draggedListItemLoader
- active: dragSensor.active
- sourceComponent: StatusChatListItem {
- property var globalPosition: Utils.getAbsolutePosition(draggable)
- parent: QC.Overlay.overlay
- sensor.cursorShape: dragSensor.cursorShape
- Drag.active: dragSensor.active
- Drag.hotSpot.x: width / 2
- Drag.hotSpot.y: height / 2
- Drag.keys: ["chat-item-category-" + categoryId]
- Drag.source: draggable
-
- Component.onCompleted: {
- x = globalPosition.x
- y = globalPosition.y
- }
- chatId: draggable.chatListItem.chatId
- categoryId: draggable.chatListItem.categoryId
- name: draggable.chatListItem.name
- type: draggable.chatListItem.type
- muted: draggable.chatListItem.muted
- dragged: true
- hasUnreadMessages: draggable.chatListItem.hasUnreadMessages
- hasMention: draggable.chatListItem.hasMention
- badge.value: draggable.chatListItem.badge.value
- selected: draggable.chatListItem.selected
-
- icon.color: draggable.chatListItem.icon.color
- image.isIdenticon: draggable.chatListItem.image.isIdenticon
- image.source: draggable.chatListItem.image.source
- }
- }
}
}
-
- Repeater {
- id: statusChatListItems
- model: delegateModel
- }
-
- Loader {
- id: popupMenuSlot
- active: !!statusChatList.popupMenu
- }
}
diff --git a/src/StatusQ/Components/StatusChatListAndCategories.qml b/src/StatusQ/Components/StatusChatListAndCategories.qml
index 2411fe09..b2086549 100644
--- a/src/StatusQ/Components/StatusChatListAndCategories.qml
+++ b/src/StatusQ/Components/StatusChatListAndCategories.qml
@@ -142,7 +142,14 @@ Item {
chatList.selectedChatId: statusChatListAndCategories.selectedChatId
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(id)
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
- chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.categoryId, id, from, to)
+ chatList.onChatItemReordered: {
+ console.log("REORDERING CHAT ITEM:")
+ console.log("FROM CATEGORY: ", model.categoryId)
+ console.log("TO: ", categoryId)
+ console.log("FROM POSITION: ", from)
+ console.log("TO POSITION: ", to)
+ statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
+ }
chatList.draggableItems: statusChatListAndCategories.draggableItems
popupMenu: statusChatListAndCategories.categoryPopupMenu
@@ -155,7 +162,9 @@ Item {
height: draggable.chatListCategory.dragActive ? 0 : parent.height
keys: ["chat-category"]
- onEntered: reorderDelay.start()
+ onEntered: {
+ reorderDelay.start()
+ }
onDropped: statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, drag.source.originalOrder, statusChatListCategory.DelegateModel.itemsIndex)
Timer {
diff --git a/src/StatusQ/Components/StatusChatListCategory.qml b/src/StatusQ/Components/StatusChatListCategory.qml
index 806136de..ffbcdc40 100644
--- a/src/StatusQ/Components/StatusChatListCategory.qml
+++ b/src/StatusQ/Components/StatusChatListCategory.qml
@@ -1,5 +1,6 @@
import QtQuick 2.13
+import StatusQ.Core.Utils 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
@@ -8,6 +9,7 @@ Column {
spacing: 0
opacity: dragged ? 0.5 : 1
+ property string uuid: Utils.uuid()
objectName: "chatListCategory"
property int originalOrder: -1
@@ -64,6 +66,7 @@ Column {
StatusChatList {
id: statusChatList
+ uuid: statusChatListCategory.uuid
anchors.horizontalCenter: parent.horizontalCenter
visible: statusChatListCategory.opened
categoryId: statusChatListCategory.categoryId
diff --git a/src/StatusQ/Components/StatusChatListDropIndicator.qml b/src/StatusQ/Components/StatusChatListDropIndicator.qml
new file mode 100644
index 00000000..84b31aee
--- /dev/null
+++ b/src/StatusQ/Components/StatusChatListDropIndicator.qml
@@ -0,0 +1,11 @@
+import QtQuick 2.13
+import StatusQ.Core.Theme 0.1
+
+Rectangle {
+ id: root
+ implicitWidth: 288
+ height: 4
+ color: Theme.palette.successColor1
+ radius: 2
+}
+
diff --git a/src/StatusQ/Components/qmldir b/src/StatusQ/Components/qmldir
index 78e2b203..1354b19e 100644
--- a/src/StatusQ/Components/qmldir
+++ b/src/StatusQ/Components/qmldir
@@ -3,6 +3,7 @@ module StatusQ.Components
StatusBadge 0.1 StatusBadge.qml
StatusChatInfoToolBar 0.1 StatusChatInfoToolBar.qml
StatusChatList 0.1 StatusChatList.qml
+StatusChatListDropIndicator 0.1 StatusChatListDropIndicator.qml
StatusChatListItem 0.1 StatusChatListItem.qml
StatusChatListCategory 0.1 StatusChatListCategory.qml
StatusChatListCategoryItem 0.1 StatusChatListCategoryItem.qml
diff --git a/statusq.qrc b/statusq.qrc
index 01a6b987..358056ee 100644
--- a/statusq.qrc
+++ b/statusq.qrc
@@ -249,6 +249,7 @@
src/StatusQ/Controls/StatusBaseInput.qml
src/StatusQ/Controls/StatusChatListCategoryItemButton.qml
src/StatusQ/Components/StatusChatList.qml
+ src/StatusQ/Components/StatusChatListDropIndicator.qml
src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml
src/StatusQ/Popups/statusModal/StatusModalFooter.qml
src/StatusQ/Popups/statusModal/StatusModalHeader.qml