chore(StatusChatList): Keep sync with underlying model after reordering (#825)
This commit is contained in:
parent
b64f2394cd
commit
abd8ea2195
|
@ -9,7 +9,7 @@ import StatusQ.Components 0.1
|
||||||
import StatusQ.Controls 0.1
|
import StatusQ.Controls 0.1
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: statusChatList
|
id: root
|
||||||
|
|
||||||
spacing: 4
|
spacing: 4
|
||||||
width: 288
|
width: 288
|
||||||
|
@ -33,13 +33,33 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onDraggableItemsChanged: delegateModel.items.setGroups(0, delegateModel.items.count, "unsorted")
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property int destinationPosition: -1
|
||||||
|
}
|
||||||
|
|
||||||
DelegateModel {
|
DelegateModel {
|
||||||
id: 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 {
|
delegate: Item {
|
||||||
id: draggable
|
id: draggable
|
||||||
objectName: model.name
|
objectName: model.name
|
||||||
width: statusChatList.width
|
width: root.width
|
||||||
height: statusChatListItem.height
|
height: statusChatListItem.height
|
||||||
property alias chatListItem: statusChatListItem
|
property alias chatListItem: statusChatListItem
|
||||||
|
|
||||||
|
@ -50,7 +70,7 @@ Column {
|
||||||
cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
|
cursorShape: active ? Qt.ClosedHandCursor : Qt.PointingHandCursor
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
pressAndHoldInterval: 150
|
pressAndHoldInterval: 150
|
||||||
enabled: statusChatList.draggableItems
|
enabled: root.draggableItems
|
||||||
|
|
||||||
property bool active: false
|
property bool active: false
|
||||||
property real startY: 0
|
property real startY: 0
|
||||||
|
@ -66,8 +86,8 @@ Column {
|
||||||
}
|
}
|
||||||
onPressAndHold: active = true
|
onPressAndHold: active = true
|
||||||
onReleased: {
|
onReleased: {
|
||||||
if (active) {
|
if (active && d.destinationPosition !== -1 && statusChatListItem.originalOrder !== d.destinationPosition) {
|
||||||
statusChatList.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, statusChatListItem.originalOrder)
|
root.chatItemReordered(statusChatListItem.chatId, statusChatListItem.originalOrder, d.destinationPosition)
|
||||||
}
|
}
|
||||||
active = false
|
active = false
|
||||||
}
|
}
|
||||||
|
@ -81,6 +101,7 @@ Column {
|
||||||
active = true
|
active = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onActiveChanged: d.destinationPosition = -1
|
||||||
|
|
||||||
StatusChatListItem {
|
StatusChatListItem {
|
||||||
id: statusChatListItem
|
id: statusChatListItem
|
||||||
|
@ -96,7 +117,7 @@ Column {
|
||||||
hasUnreadMessages: model.hasUnreadMessages
|
hasUnreadMessages: model.hasUnreadMessages
|
||||||
notificationsCount: model.notificationsCount
|
notificationsCount: model.notificationsCount
|
||||||
highlightWhenCreated: !!model.highlight
|
highlightWhenCreated: !!model.highlight
|
||||||
selected: (model.active && statusChatList.highlightItem)
|
selected: (model.active && root.highlightItem)
|
||||||
|
|
||||||
icon.emoji: model.emoji
|
icon.emoji: model.emoji
|
||||||
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
|
icon.color: !!model.color ? model.color : Theme.palette.userCustomizationColors[model.colorId]
|
||||||
|
@ -105,10 +126,26 @@ Column {
|
||||||
ringSettings.ringSpecModel: model.colorHash
|
ringSettings.ringSpecModel: model.colorHash
|
||||||
|
|
||||||
sensor.cursorShape: dragSensor.cursorShape
|
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: {
|
onClicked: {
|
||||||
highlightWhenCreated = false
|
highlightWhenCreated = false
|
||||||
|
|
||||||
if (mouse.button === Qt.RightButton && !!statusChatList.popupMenu) {
|
if (mouse.button === Qt.RightButton && !!root.popupMenu) {
|
||||||
statusChatListItem.highlighted = true
|
statusChatListItem.highlighted = true
|
||||||
|
|
||||||
let originalOpenHandler = popupMenuSlot.item.openHandler
|
let originalOpenHandler = popupMenuSlot.item.openHandler
|
||||||
|
@ -136,10 +173,10 @@ Column {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!statusChatListItem.selected) {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +187,6 @@ Column {
|
||||||
keys: ["chat-item-category-" + statusChatListItem.categoryId]
|
keys: ["chat-item-category-" + statusChatListItem.categoryId]
|
||||||
|
|
||||||
onEntered: reorderDelay.start()
|
onEntered: reorderDelay.start()
|
||||||
onDropped: statusChatList.chatItemReordered(statusChatListItem.chatId, drag.source.originalOrder, statusChatListItem.DelegateModel.itemsIndex)
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: reorderDelay
|
id: reorderDelay
|
||||||
|
@ -158,7 +194,7 @@ Column {
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (dropArea.containsDrag) {
|
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)
|
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -208,6 +244,6 @@ Column {
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: popupMenuSlot
|
id: popupMenuSlot
|
||||||
active: !!statusChatList.popupMenu
|
active: !!root.popupMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import StatusQ.Core 0.1
|
||||||
import SortFilterProxyModel 0.2
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: statusChatListAndCategories
|
id: root
|
||||||
|
|
||||||
implicitHeight: chatListsAndCategories.height
|
implicitHeight: chatListsAndCategories.height
|
||||||
implicitWidth: chatListsAndCategories.width
|
implicitWidth: chatListsAndCategories.width
|
||||||
|
@ -53,11 +53,11 @@ Item {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: sensor
|
id: sensor
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
width: statusChatListAndCategories.width
|
width: root.width
|
||||||
height: statusChatListAndCategories.height
|
height: root.height
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
onClicked: {
|
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)
|
popupMenuSlot.item.popup(mouse.x + 4, mouse.y + 6)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -73,31 +73,44 @@ Item {
|
||||||
StatusChatList {
|
StatusChatList {
|
||||||
id: statusChatList
|
id: statusChatList
|
||||||
visible: statusChatList.model.count > 0
|
visible: statusChatList.model.count > 0
|
||||||
onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
|
onChatItemSelected: root.chatItemSelected(categoryId, id)
|
||||||
onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
|
onChatItemUnmuted: root.chatItemUnmuted(id)
|
||||||
onChatItemReordered: statusChatListAndCategories.chatItemReordered(categoryId, id, from, to)
|
onChatItemReordered: root.chatItemReordered(categoryId, id, from, to)
|
||||||
draggableItems: statusChatListAndCategories.draggableItems
|
draggableItems: root.draggableItems
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
sourceModel: statusChatListAndCategories.model
|
sourceModel: root.model
|
||||||
|
|
||||||
filters: ValueFilter { roleName: "isCategory"; value: false }
|
filters: ValueFilter { roleName: "isCategory"; value: false }
|
||||||
sorters: RoleSorter { roleName: "position" }
|
sorters: RoleSorter { roleName: "position" }
|
||||||
}
|
}
|
||||||
|
|
||||||
popupMenu: statusChatListAndCategories.chatListPopupMenu
|
popupMenu: root.chatListPopupMenu
|
||||||
}
|
}
|
||||||
|
|
||||||
DelegateModel {
|
DelegateModel {
|
||||||
id: delegateModel
|
id: delegateModel
|
||||||
|
|
||||||
|
property int destinationPosition: -1
|
||||||
|
|
||||||
model: SortFilterProxyModel {
|
model: SortFilterProxyModel {
|
||||||
sourceModel: statusChatListAndCategories.model
|
sourceModel: root.model
|
||||||
|
|
||||||
filters: ValueFilter { roleName: "isCategory"; value: true }
|
filters: ValueFilter { roleName: "isCategory"; value: true }
|
||||||
sorters: RoleSorter { roleName: "position" }
|
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 {
|
delegate: Item {
|
||||||
id: draggable
|
id: draggable
|
||||||
width: statusChatListCategory.width
|
width: statusChatListCategory.width
|
||||||
|
@ -117,13 +130,13 @@ Item {
|
||||||
dragSensor.drag.threshold: 0.1
|
dragSensor.drag.threshold: 0.1
|
||||||
dragSensor.drag.filterChildren: true
|
dragSensor.drag.filterChildren: true
|
||||||
dragSensor.onPressAndHold: {
|
dragSensor.onPressAndHold: {
|
||||||
if (statusChatListAndCategories.draggableCategories) {
|
if (root.draggableCategories) {
|
||||||
dragActive = true
|
dragActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dragSensor.onReleased: {
|
dragSensor.onReleased: {
|
||||||
if (dragActive) {
|
if (dragActive && delegateModel.destinationPosition !== -1 && statusChatListCategory.originalOrder !== delegateModel.destinationPosition) {
|
||||||
statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, statusChatListCategory.originalOrder)
|
root.chatListCategoryReordered(statusChatListCategory.categoryId, statusChatListCategory.originalOrder, delegateModel.destinationPosition)
|
||||||
}
|
}
|
||||||
dragActive = false
|
dragActive = false
|
||||||
}
|
}
|
||||||
|
@ -133,42 +146,44 @@ Item {
|
||||||
startX = dragSensor.mouseX
|
startX = dragSensor.mouseX
|
||||||
}
|
}
|
||||||
dragSensor.onMouseYChanged: {
|
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
|
dragActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dragSensor.onMouseXChanged: {
|
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
|
dragActive = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onDragActiveChanged: delegateModel.destinationPosition = -1
|
||||||
|
|
||||||
addButton.tooltip: statusChatListAndCategories.categoryAddButtonToolTip
|
addButton.tooltip: root.categoryAddButtonToolTip
|
||||||
menuButton.tooltip: statusChatListAndCategories.categoryMenuButtonToolTip
|
menuButton.tooltip: root.categoryMenuButtonToolTip
|
||||||
|
|
||||||
originalOrder: model.position
|
originalOrder: model.position
|
||||||
categoryId: model.itemId
|
categoryId: model.itemId
|
||||||
name: model.name
|
name: model.name
|
||||||
showActionButtons: statusChatListAndCategories.showCategoryActionButtons
|
|
||||||
addButton.onClicked: statusChatListAndCategories.categoryAddButtonClicked(model.itemId)
|
showActionButtons: root.showCategoryActionButtons
|
||||||
|
addButton.onClicked: root.categoryAddButtonClicked(model.itemId)
|
||||||
|
|
||||||
chatList.model: SortFilterProxyModel {
|
chatList.model: SortFilterProxyModel {
|
||||||
sourceModel: model.subItems
|
sourceModel: model.subItems
|
||||||
sorters: RoleSorter { roleName: "position" }
|
sorters: RoleSorter { roleName: "position" }
|
||||||
}
|
}
|
||||||
|
|
||||||
chatList.onChatItemSelected: statusChatListAndCategories.chatItemSelected(categoryId, id)
|
chatList.onChatItemSelected: root.chatItemSelected(categoryId, id)
|
||||||
chatList.onChatItemUnmuted: statusChatListAndCategories.chatItemUnmuted(id)
|
chatList.onChatItemUnmuted: root.chatItemUnmuted(id)
|
||||||
chatList.onChatItemReordered: statusChatListAndCategories.chatItemReordered(model.itemId, id, from, to)
|
chatList.onChatItemReordered: root.chatItemReordered(model.itemId, id, from, to)
|
||||||
chatList.draggableItems: statusChatListAndCategories.draggableItems
|
chatList.draggableItems: root.draggableItems
|
||||||
|
|
||||||
popupMenu: statusChatListAndCategories.categoryPopupMenu
|
popupMenu: root.categoryPopupMenu
|
||||||
chatListPopupMenu: statusChatListAndCategories.chatListPopupMenu
|
chatListPopupMenu: root.chatListPopupMenu
|
||||||
|
|
||||||
// Used to set the initial value of "opened" when the
|
// Used to set the initial value of "opened" when the
|
||||||
// model is bound/changed.
|
// model is bound/changed.
|
||||||
opened: {
|
opened: {
|
||||||
let openedState = statusChatListAndCategories.openedCategoryState[model.itemId]
|
let openedState = root.openedCategoryState[model.itemId]
|
||||||
return openedState !== undefined ? openedState : true // defaults to open
|
return openedState !== undefined ? openedState : true // defaults to open
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +192,18 @@ Item {
|
||||||
// as the state would be lost each time the model is
|
// as the state would be lost each time the model is
|
||||||
// changed.
|
// changed.
|
||||||
onOpenedChanged: {
|
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")
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +214,6 @@ Item {
|
||||||
keys: ["chat-category"]
|
keys: ["chat-category"]
|
||||||
|
|
||||||
onEntered: reorderDelay.start()
|
onEntered: reorderDelay.start()
|
||||||
onDropped: statusChatListAndCategories.chatListCategoryReordered(statusChatListCategory.categoryId, drag.source.originalOrder, statusChatListCategory.DelegateModel.itemsIndex)
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: reorderDelay
|
id: reorderDelay
|
||||||
|
@ -196,7 +221,7 @@ Item {
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (dropArea.containsDrag) {
|
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)
|
delegateModel.items.move(dropArea.drag.source.DelegateModel.itemsIndex, draggable.DelegateModel.itemsIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -242,6 +267,6 @@ Item {
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: popupMenuSlot
|
id: popupMenuSlot
|
||||||
active: !!statusChatListAndCategories.popupMenu
|
active: !!root.popupMenu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,6 +150,29 @@ QtObject {
|
||||||
context.stroke();
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue