Compare commits

...
Author SHA1 Message Date
Pascal Precht 146346a862 WIP SAVEPOINT 2021-09-23 13:35:13 +02:00
Pascal Precht 5a5c611fd1 WIP SAVEPOINT 2021-09-22 14:24:21 +02:00
Pascal Precht 8d2ae42e98 WIP SAVEPOINT 2021-09-22 10:22:42 +02:00
6 changed files with 246 additions and 156 deletions
+219 -154
View File
@@ -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)
}
return true
}
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)
visible: {
if (!!statusChatList.filterFn) {
return statusChatList.filterFn(model, statusChatList.categoryId)
}
active = false
return true
}
onMouseYChanged: {
if ((Math.abs(startY - mouseY) > 1) && pressed) {
active = true
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
}
}
onMouseXChanged: {
if ((Math.abs(startX - mouseX) > 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
}
}
StatusChatListItem {
id: statusChatListItem
property string profileImage: ""
opacity: dragSensor.active ? 0.0 : 1.0
Component.onCompleted: {
if (typeof statusChatList.profileImageFn === "function") {
profileImage = statusChatList.profileImageFn(model.chatId || model.id) || ""
onMouseYChanged: {
if ((Math.abs(startY - mouseY) > 1) && pressed) {
active = true
}
}
onMouseXChanged: {
if ((Math.abs(startX - mouseX) > 1) && pressed) {
active = true
}
}
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 || ""
StatusChatListItem {
sensor.cursorShape: dragSensor.cursorShape
onClicked: {
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
statusChatListItem.highlighted = true
id: statusChatListItem
let originalOpenHandler = popupMenuSlot.item.openHandler
let originalCloseHandler = popupMenuSlot.item.closeHandler
property string chatListId: statusChatList.uuid
property string profileImage: ""
property var newOrder: model.position
property var newCategoryId: model.categoryId
popupMenuSlot.item.openHandler = function () {
if (!!originalOpenHandler) {
originalOpenHandler((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) + " 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
popupMenuSlot.item.closeHandler = function () {
if (statusChatListItem) {
statusChatListItem.highlighted = false
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))
}
}
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)
}
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)
}
}
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]
onEntered: reorderDelay.start()
onDropped: statusChatList.chatItemReordered(statusChatListItem.chatId, drag.source.originalOrder, statusChatListItem.DelegateModel.itemsIndex)
Timer {
id: reorderDelay
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)
StatusChatListDropIndicator {
anchors.bottom: parent.bottom
anchors.bottomMargin: -2
visible: dropArea.containsDrag
}
}
}
}
DropArea {
id: dropArea
width: parent.width
height: parent.height
keys: ["chat-item"]
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
onEntered: reorderDelay.start()
Component.onCompleted: {
x = globalPosition.x
y = globalPosition.y
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
}
}
}
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
}
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
icon.color: draggable.chatListItem.icon.color
image.isIdenticon: draggable.chatListItem.image.isIdenticon
image.source: draggable.chatListItem.image.source
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
}
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: reorderDelay2
interval: 100
repeat: false
onTriggered: {
if (emptyListDropArea.containsDrag) {
emptyListDropArea.drag.source.chatListItem.newOrder = 0
emptyListDropArea.drag.source.chatListItem.newCategoryId = statusChatList.categoryId
}
}
}
}
}
}
}
@@ -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 {
@@ -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
@@ -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
}
+1
View File
@@ -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
+1
View File
@@ -249,6 +249,7 @@
<file>src/StatusQ/Controls/StatusBaseInput.qml</file>
<file>src/StatusQ/Controls/StatusChatListCategoryItemButton.qml</file>
<file>src/StatusQ/Components/StatusChatList.qml</file>
<file>src/StatusQ/Components/StatusChatListDropIndicator.qml</file>
<file>src/StatusQ/Popups/statusModal/StatusImageWithTitle.qml</file>
<file>src/StatusQ/Popups/statusModal/StatusModalFooter.qml</file>
<file>src/StatusQ/Popups/statusModal/StatusModalHeader.qml</file>