Implement shift+click/A-B message selection
This commit is contained in:
parent
e696c16fc8
commit
ba86414ddf
1
TODO.md
1
TODO.md
|
@ -2,7 +2,6 @@
|
|||
|
||||
- Long-press-drag to select multiple messages on touch
|
||||
- Drag to select multiple messages on non-touch
|
||||
- Shift+click to select everything in between
|
||||
|
||||
- Drag-scrolling in room pane a tiny bit activates the delegates
|
||||
|
||||
|
|
|
@ -64,22 +64,35 @@ ListView {
|
|||
}
|
||||
}
|
||||
|
||||
onSelectedCountChanged: if (! selectedCount) lastCheckedDelegateIndex = 0
|
||||
|
||||
|
||||
property bool allowDragging: true
|
||||
property alias cursorShape: mouseArea.cursorShape
|
||||
property int currentItemHeight: currentItem ? currentItem.height : 0
|
||||
|
||||
property var checkedDelegates: ({})
|
||||
property int lastCheckedDelegateIndex: 0
|
||||
property int selectedCount: Object.keys(checkedDelegates).length
|
||||
|
||||
|
||||
function delegatesChecked(...indices) {
|
||||
print( indices)
|
||||
for (const i of indices) {
|
||||
const model = listView.model.get(i)
|
||||
checkedDelegates[model.id] = model
|
||||
}
|
||||
|
||||
lastCheckedDelegateIndex = indices.slice(-1)[0]
|
||||
|
||||
checkedDelegatesChanged()
|
||||
}
|
||||
|
||||
function delegatesFromLastToHereChecked(here) {
|
||||
const indices = utils.range(lastCheckedDelegateIndex, here)
|
||||
eventList.delegatesChecked(...indices)
|
||||
}
|
||||
|
||||
function delegatesUnchecked(...indices) {
|
||||
for (const i of indices) {
|
||||
const model = listView.model.get(i)
|
||||
|
|
|
@ -183,6 +183,7 @@ HRowLayout {
|
|||
PointHandler {
|
||||
id: mousePointHandler
|
||||
acceptedButtons: Qt.LeftButton
|
||||
acceptedModifiers: Qt.NoModifier
|
||||
acceptedPointerTypes:
|
||||
PointerDevice.GenericPointer | PointerDevice.Eraser
|
||||
|
||||
|
@ -206,6 +207,24 @@ HRowLayout {
|
|||
property bool checkedNow: false
|
||||
}
|
||||
|
||||
PointHandler {
|
||||
id: mouseShiftPointHandler
|
||||
acceptedButtons: Qt.LeftButton
|
||||
acceptedModifiers: Qt.ShiftModifier
|
||||
acceptedPointerTypes:
|
||||
PointerDevice.GenericPointer | PointerDevice.Eraser
|
||||
|
||||
onActiveChanged: {
|
||||
if (active &&
|
||||
! eventDelegate.checked &&
|
||||
(! parent.hoveredLink ||
|
||||
! parent.enableLinkActivation)) {
|
||||
|
||||
eventList.delegatesFromLastToHereChecked(model.index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
id: touchTapHandler
|
||||
acceptedButtons: Qt.LeftButton
|
||||
|
@ -234,7 +253,8 @@ HRowLayout {
|
|||
z: -100
|
||||
color: eventDelegate.checked &&
|
||||
! contentLabel.selectedText &&
|
||||
! mousePointHandler.active ?
|
||||
! mousePointHandler.active &&
|
||||
! mouseShiftPointHandler.active ?
|
||||
theme.chat.message.checkedBackground :
|
||||
|
||||
isOwn?
|
||||
|
|
|
@ -57,8 +57,6 @@ HColumnLayout {
|
|||
combine ? theme.spacing / (compact ? 4 : 2) :
|
||||
theme.spacing * (compact ? 1 : 2)
|
||||
|
||||
readonly property alias leftTapHandler: leftTapHandler
|
||||
|
||||
// Needed because of eventList's MouseArea which steals the
|
||||
// HSelectableLabel's MouseArea hover events
|
||||
onCursorShapeChanged: eventList.cursorShape = cursorShape
|
||||
|
@ -114,11 +112,17 @@ HColumnLayout {
|
|||
}
|
||||
|
||||
TapHandler {
|
||||
id: leftTapHandler
|
||||
acceptedButtons: Qt.LeftButton
|
||||
acceptedModifiers: Qt.NoModifier
|
||||
onTapped: toggleChecked()
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.LeftButton
|
||||
acceptedModifiers: Qt.ShiftModifier
|
||||
onTapped: eventList.delegatesFromLastToHereChecked(model.index)
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedButtons: Qt.RightButton
|
||||
acceptedPointerTypes: PointerDevice.GenericPointer | PointerDevice.Pen
|
||||
|
@ -151,6 +155,13 @@ HColumnLayout {
|
|||
onTriggered: eventList.checkedDelegates = {}
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
visible: model.index !== 0
|
||||
icon.name: "select-until-here"
|
||||
text: qsTr("Select until here")
|
||||
onTriggered: eventList.delegatesFromLastToHereChecked(model.index)
|
||||
}
|
||||
|
||||
HMenuItem {
|
||||
id: copyMedia
|
||||
icon.name: "copy-link"
|
||||
|
|
|
@ -83,6 +83,7 @@ HMxcImage {
|
|||
|
||||
|
||||
TapHandler {
|
||||
acceptedModifiers: Qt.NoModifier
|
||||
onTapped:
|
||||
eventList.selectedCount ?
|
||||
eventDelegate.toggleChecked() : getOpenUrl(Qt.openUrlExternally)
|
||||
|
@ -90,6 +91,14 @@ HMxcImage {
|
|||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
}
|
||||
|
||||
TapHandler {
|
||||
acceptedModifiers: Qt.ShiftModifier
|
||||
onTapped:
|
||||
eventList.delegatesFromLastToHereChecked(singleMediaInfo.index)
|
||||
|
||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||
}
|
||||
|
||||
HoverHandler {
|
||||
id: hover
|
||||
onHoveredChanged: {
|
||||
|
|
|
@ -83,6 +83,26 @@ QtObject {
|
|||
}
|
||||
|
||||
|
||||
function range(startOrEnd, end=null, ) {
|
||||
// range(3) → [0, 1, 2, 3]
|
||||
// range(3, 6) → [3, 4, 5, 6]
|
||||
// range(3, -1) → [3, 2, 1, 0, -1]
|
||||
|
||||
const numbers = []
|
||||
let realStart = end ? startOrEnd : 0
|
||||
let realEnd = end ? end : startOrEnd
|
||||
|
||||
if (realEnd < realStart)
|
||||
for (let i = realStart; i >= realEnd; i--)
|
||||
numbers.push(i)
|
||||
else
|
||||
for (let i = realStart; i <= realEnd; i++)
|
||||
numbers.push(i)
|
||||
|
||||
return numbers
|
||||
}
|
||||
|
||||
|
||||
function isEmptyObject(obj) {
|
||||
return Object.entries(obj).length === 0 && obj.constructor === Object
|
||||
}
|
||||
|
|
3
src/icons/thin/select-until-here.svg
Normal file
3
src/icons/thin/select-until-here.svg
Normal file
|
@ -0,0 +1,3 @@
|
|||
<svg height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m11 24v-2h-4v2zm8-22h3v3h2v-5h-5zm-19 15h2v-4h-2zm0-6h2v-4h-2zm2-6v-3h3v-2h-5v5zm22 2h-2v4h2zm0 6h-2v4h2zm-2 6v3h-3v2h5v-5zm-17 3h-3v-3h-2v5h5zm12 2v-2h-4v2zm-6-22v-2h-4v2zm6 0v-2h-4v2zm0 11h-4v4h-2v-4h-4v-2h4v-4h2v4h4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 327 B |
Loading…
Reference in New Issue
Block a user