Skip to content

Commit

Permalink
chore(StatusChatList): Keep sync with underlying model after reorderi…
Browse files Browse the repository at this point in the history
…ng (#825)
  • Loading branch information
micieslak committed Sep 21, 2022
1 parent b64f239 commit abd8ea2
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 44 deletions.
62 changes: 49 additions & 13 deletions ui/StatusQ/src/StatusQ/Components/StatusChatList.qml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import StatusQ.Components 0.1
import StatusQ.Controls 0.1

Column {
id: statusChatList
id: root

spacing: 4
width: 288
Expand All @@ -33,13 +33,33 @@ Column {
}
}

onDraggableItemsChanged: delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")

QtObject {
id: d

property int destinationPosition: -1
}

DelegateModel {
id: delegateModel
model: statusChatList.model
model: root.model

items.includeByDefault: !root.draggableItems

groups: DelegateModelGroup {
id: unsortedItems

name: "unsorted"
includeByDefault: root.draggableItems
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}

delegate: Item {
id: draggable
objectName: model.name
width: statusChatList.width
width: root.width
height: statusChatListItem.height
property alias chatListItem: statusChatListItem

Expand All @@ -50,7 +70,7 @@ Column {
cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
hoverEnabled: true
pressAndHoldInterval: 150
enabled: statusChatList.draggableItems
enabled: root.draggableItems

property bool active: false
property real startY: 0
Expand All @@ -66,8 +86,8 @@ Column {
}
onPressAndHold: active = true
onReleased: {
if (active) {
statusChatList.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, statusChatListItem.originalOrder)
if (active && d.destinationPosition !== -1 && statusChatListItem.originalOrder !== d.destinationPosition) {
root.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, d.destinationPosition)
}
active = false
}
Expand All @@ -81,6 +101,7 @@ Column {
active = true
}
}
onActiveChanged: d.destinationPosition = -1

StatusChatListItem {
id: statusChatListItem
Expand All @@ -96,7 +117,7 @@ Column {
hasUnreadMessages: model.hasUnreadMessages
notificationsCount: model.notificationsCount
highlightWhenCreated: !!model.highlight
selected: (model.active && statusChatList.highlightItem)
selected: (model.active && root.highlightItem)

icon.emoji: model.emoji
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
Expand All @@ -105,10 +126,26 @@ Column {
ringSettings.ringSpecModel: model.colorHash

sensor.cursorShape: dragSensor.cursorShape

Connections {
target: statusChatListItem
enabled: root.draggableItems

function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return

delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}

}

onClicked: {
highlightWhenCreated = false

if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
if (mouse.button === Qt.RightButton && !!root.popupMenu) {
statusChatListItem.highlighted = true

let originalOpenHandler = popupMenuSlot.item.openHandler
Expand Down Expand Up @@ -136,10 +173,10 @@ Column {
return
}
if (!statusChatListItem.selected) {
statusChatList.chatItemSelected(model.parentItemId, model.itemId)
root.chatItemSelected(model.parentItemId, model.itemId)
}
}
onUnmute: statusChatList.chatItemUnmuted(model.itemId)
onUnmute: root.chatItemUnmuted(model.itemId)
}
}

Expand All @@ -150,15 +187,14 @@ Column {
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
d.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
Expand Down Expand Up @@ -208,6 +244,6 @@ Column {

Loader {
id: popupMenuSlot
active: !!statusChatList.popupMenu
active: !!root.popupMenu
}
}
87 changes: 56 additions & 31 deletions ui/StatusQ/src/StatusQ/Components/StatusChatListAndCategories.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import StatusQ.Core 0.1
import SortFilterProxyModel 0.2

Item {
id: statusChatListAndCategories
id: root

implicitHeight: chatListsAndCategories.height
implicitWidth: chatListsAndCategories.width
Expand Down Expand Up @@ -53,11 +53,11 @@ Item {
MouseArea {
id: sensor
anchors.top: parent.top
width: statusChatListAndCategories.width
height: statusChatListAndCategories.height
width: root.width
height: root.height
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.RightButton && showPopupMenu && !!statusChatListAndCategories.popupMenu) {
if (mouse.button === Qt.RightButton && showPopupMenu && !!root.popupMenu) {
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6)
return
}
Expand All @@ -73,31 +73,44 @@ Item {
StatusChatList {
id: statusChatList
visible: statusChatList.model.count > 0
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
onChatItemReordered: statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
draggableItems: statusChatListAndCategories.draggableItems
onChatItemSelected: root.chatItemSelected(categoryId, id)
onChatItemUnmuted: root.chatItemUnmuted(id)
onChatItemReordered: root.chatItemReordered(categoryId, id, from, to)
draggableItems: root.draggableItems

model: SortFilterProxyModel {
sourceModel: statusChatListAndCategories.model
sourceModel: root.model

filters: ValueFilter { roleName: "isCategory"; value: false }
sorters: RoleSorter { roleName: "position" }
}

popupMenu: statusChatListAndCategories.chatListPopupMenu
popupMenu: root.chatListPopupMenu
}

DelegateModel {
id: delegateModel

property int destinationPosition: -1

model: SortFilterProxyModel {
sourceModel: statusChatListAndCategories.model
sourceModel: root.model

filters: ValueFilter { roleName: "isCategory"; value: true }
sorters: RoleSorter { roleName: "position" }
}

items.includeByDefault: false

groups: DelegateModelGroup {
id: unsortedItems

name: "unsorted"
includeByDefault: true
onChanged: Utils.delegateModelSort(unsortedItems, delegateModel.items,
(a, b) => a.position < b.position)
}

delegate: Item {
id: draggable
width: statusChatListCategory.width
Expand All @@ -117,13 +130,13 @@ Item {
dragSensor.drag.threshold: 0.1
dragSensor.drag.filterChildren: true
dragSensor.onPressAndHold: {
if (statusChatListAndCategories.draggableCategories) {
if (root.draggableCategories) {
dragActive = true
}
}
dragSensor.onReleased: {
if (dragActive) {
statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, statusChatListCategory.originalOrder)
if (dragActive && delegateModel.destinationPosition !== -1 && statusChatListCategory.originalOrder !== delegateModel.destinationPosition) {
root.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, delegateModel.destinationPosition)
}
dragActive = false
}
Expand All @@ -133,42 +146,44 @@ Item {
startX = dragSensor.mouseX
}
dragSensor.onMouseYChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startY - dragSensor.mouseY) > 1) && dragSensor.pressed) {
dragActive = true
}
}
dragSensor.onMouseXChanged: {
if (statusChatListAndCategories.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
if (root.draggableCategories && (Math.abs(startX - dragSensor.mouseX) > 1) && dragSensor.pressed) {
dragActive = true
}
}
onDragActiveChanged: delegateModel.destinationPosition = -1

addButton.tooltip: statusChatListAndCategories.categoryAddButtonToolTip
menuButton.tooltip: statusChatListAndCategories.categoryMenuButtonToolTip
addButton.tooltip: root.categoryAddButtonToolTip
menuButton.tooltip: root.categoryMenuButtonToolTip

originalOrder: model.position
categoryId: model.itemId
name: model.name
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.itemId)

showActionButtons: root.showCategoryActionButtons
addButton.onClicked: root.categoryAddButtonClicked(model.itemId)

chatList.model: SortFilterProxyModel {
sourceModel: model.subItems
sorters: RoleSorter { roleName: "position" }
}

chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: statusChatListAndCategories.draggableItems
chatList.onChatItemSelected: root.chatItemSelected(categoryId, id)
chatList.onChatItemUnmuted: root.chatItemUnmuted(id)
chatList.onChatItemReordered: root.chatItemReordered(model.itemId, id, from, to)
chatList.draggableItems: root.draggableItems

popupMenu: statusChatListAndCategories.categoryPopupMenu
chatListPopupMenu: statusChatListAndCategories.chatListPopupMenu
popupMenu: root.categoryPopupMenu
chatListPopupMenu: root.chatListPopupMenu

// Used to set the initial value of "opened" when the
// model is bound/changed.
opened: {
let openedState = statusChatListAndCategories.openedCategoryState[model.itemId]
let openedState = root.openedCategoryState[model.itemId]
return openedState !== undefined ? openedState : true // defaults to open
}

Expand All @@ -177,7 +192,18 @@ Item {
// as the state would be lost each time the model is
// changed.
onOpenedChanged: {
statusChatListAndCategories.openedCategoryState[model.itemId] = statusChatListCategory.opened
root.openedCategoryState[model.itemId] = statusChatListCategory.opened
}

Connections {
function onOriginalOrderChanged() {
Qt.callLater(() => {
if (!delegateModel)
return

delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
})
}
}
}

Expand All @@ -188,15 +214,14 @@ Item {
keys: ["chat-category"]

onEntered: reorderDelay.start()
onDropped: statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, drag.source.originalOrder, statusChatListCategory.DelegateModel.itemsIndex)

Timer {
id: reorderDelay
interval: 100
repeat: false
onTriggered: {
if (dropArea.containsDrag) {
dropArea.drag.source.chatListCategory.originalOrder = statusChatListCategory.originalOrder
delegateModel.destinationPosition = delegateModel.model.get(draggable.DelegateModel.itemsIndex).position
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
}
}
Expand Down Expand Up @@ -242,6 +267,6 @@ Item {

Loader {
id: popupMenuSlot
active: !!statusChatListAndCategories.popupMenu
active: !!root.popupMenu
}
}
23 changes: 23 additions & 0 deletions ui/StatusQ/src/StatusQ/Core/Utils/Utils.qml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,29 @@ QtObject {
context.stroke();
}
}

function delegateModelSort(srcGroup, dstGroup, lessThan) {
const insertPosition = (lessThan, item) => {
let lower = 0
let upper = dstGroup.count
while (lower < upper) {
const middle = Math.floor(lower + (upper - lower) / 2)
const result = lessThan(item.model, dstGroup.get(middle).model);
if (result)
upper = middle
else
lower = middle + 1
}
return lower
}

while (srcGroup.count > 0) {
const item = srcGroup.get(0)
const index = insertPosition(lessThan, item)
item.groups = dstGroup.name
dstGroup.move(item.itemsIndex, index)
}
}
}


0 comments on commit abd8ea2

Please sign in to comment.