Better touch scrolling (#1012)

This commit is contained in:
Malte E 2022-03-24 01:35:42 +01:00 committed by GitHub
parent 41c6b75efc
commit 13baf77435
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 110 deletions

View File

@ -362,7 +362,7 @@ Item {
} }
delegate: ItemDelegate { delegate: Item {
id: wrapper id: wrapper
required property double proportionalHeight required property double proportionalHeight
@ -407,8 +407,71 @@ Item {
width: chat.delegateMaxWidth width: chat.delegateMaxWidth
height: section.active ? section.height + timelinerow.height : timelinerow.height height: section.active ? section.height + timelinerow.height : timelinerow.height
hoverEnabled: true Loader {
id: section
property int parentWidth: parent.width
property string userId: wrapper.userId
property string previousMessageUserId: wrapper.previousMessageUserId
property string day: wrapper.day
property string previousMessageDay: wrapper.previousMessageDay
property bool previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent
property bool isStateEvent: wrapper.isStateEvent
property bool isSender: wrapper.isSender
property string userName: wrapper.userName
property date timestamp: wrapper.timestamp
z: 4
active: previousMessageUserId !== undefined && previousMessageUserId !== userId || previousMessageDay !== day || previousMessageIsStateEvent !== isStateEvent
//asynchronous: true
sourceComponent: sectionHeader
visible: status == Loader.Ready
}
TimelineRow {
id: timelinerow
proportionalHeight: wrapper.proportionalHeight
type: chat.model, wrapper.type
typeString: wrapper.typeString
originalWidth: wrapper.originalWidth
blurhash: wrapper.blurhash
body: wrapper.body
formattedBody: wrapper.formattedBody
eventId: chat.model, wrapper.eventId
filename: wrapper.filename
filesize: wrapper.filesize
url: wrapper.url
thumbnailUrl: wrapper.thumbnailUrl
duration: wrapper.duration
isOnlyEmoji: wrapper.isOnlyEmoji
isSender: wrapper.isSender
isEncrypted: wrapper.isEncrypted
isEditable: wrapper.isEditable
isEdited: wrapper.isEdited
isStateEvent: wrapper.isStateEvent
replyTo: wrapper.replyTo
userId: wrapper.userId
userName: wrapper.userName
roomTopic: wrapper.roomTopic
roomName: wrapper.roomName
callType: wrapper.callType
reactions: wrapper.reactions
trustlevel: wrapper.trustlevel
encryptionError: wrapper.encryptionError
timestamp: wrapper.timestamp
status: wrapper.status
relatedEventCacheBuster: wrapper.relatedEventCacheBuster
y: section.visible && section.active ? section.y + section.height : 0
onHoveredChanged: {
if (!Settings.mobileMode && hovered) {
if (!messageActions.hovered) {
messageActions.attached = timelinerow;
messageActions.model = timelinerow;
}
}
}
background: Rectangle { background: Rectangle {
id: scrollHighlight id: scrollHighlight
@ -455,75 +518,6 @@ Item {
} }
} }
Loader {
id: section
property int parentWidth: parent.width
property string userId: wrapper.userId
property string previousMessageUserId: wrapper.previousMessageUserId
property string day: wrapper.day
property string previousMessageDay: wrapper.previousMessageDay
property bool previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent
property bool isStateEvent: wrapper.isStateEvent
property bool isSender: wrapper.isSender
property string userName: wrapper.userName
property date timestamp: wrapper.timestamp
z: 4
active: previousMessageUserId !== undefined && previousMessageUserId !== userId || previousMessageDay !== day || previousMessageIsStateEvent !== isStateEvent
//asynchronous: true
sourceComponent: sectionHeader
visible: status == Loader.Ready
}
TimelineRow {
id: timelinerow
hovered: messageActions.hovered ? (messageActions.model != undefined && messageActions.model == timelinerow) : wrapper.hovered
proportionalHeight: wrapper.proportionalHeight
type: chat.model, wrapper.type
typeString: wrapper.typeString
originalWidth: wrapper.originalWidth
blurhash: wrapper.blurhash
body: wrapper.body
formattedBody: wrapper.formattedBody
eventId: chat.model, wrapper.eventId
filename: wrapper.filename
filesize: wrapper.filesize
url: wrapper.url
thumbnailUrl: wrapper.thumbnailUrl
duration: wrapper.duration
isOnlyEmoji: wrapper.isOnlyEmoji
isSender: wrapper.isSender
isEncrypted: wrapper.isEncrypted
isEditable: wrapper.isEditable
isEdited: wrapper.isEdited
isStateEvent: wrapper.isStateEvent
replyTo: wrapper.replyTo
userId: wrapper.userId
userName: wrapper.userName
roomTopic: wrapper.roomTopic
roomName: wrapper.roomName
callType: wrapper.callType
reactions: wrapper.reactions
trustlevel: wrapper.trustlevel
encryptionError: wrapper.encryptionError
timestamp: wrapper.timestamp
status: wrapper.status
relatedEventCacheBuster: wrapper.relatedEventCacheBuster
y: section.visible && section.active ? section.y + section.height : 0
onHoveredChanged: {
if (!Settings.mobileMode && hovered) {
if (!messageActions.hovered) {
messageActions.attached = timelinerow;
messageActions.model = timelinerow;
}
}
}
} }
Connections { Connections {
@ -729,10 +723,12 @@ Item {
property string text property string text
property string link property string link
property string eventId
function show(text_, link_) { function show(text_, link_, eventId_) {
text = text_; text = text_;
link = link_; link = link_;
eventId = eventId_;
open(); open();
} }
@ -754,7 +750,7 @@ Item {
visible: true visible: true
enabled: visible enabled: visible
text: qsTr("&Go to quoted message") text: qsTr("&Go to quoted message")
onTriggered: chat.model.showEvent(eventId) onTriggered: chat.model.showEvent(replyContextMenu.eventId)
} }
} }

View File

@ -11,7 +11,7 @@ import QtQuick.Layouts 1.2
import QtQuick.Window 2.13 import QtQuick.Window 2.13
import im.nheko 1.0 import im.nheko 1.0
Item { AbstractButton {
id: r id: r
required property double proportionalHeight required property double proportionalHeight
@ -46,7 +46,7 @@ Item {
required property int status required property int status
required property int relatedEventCacheBuster required property int relatedEventCacheBuster
property bool hovered: false hoverEnabled: true
width: parent.width width: parent.width
height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 ) height: row.height+(reactionRow.height > 0 ? reactionRow.height-2 : 0 )
@ -55,21 +55,18 @@ Item {
color: (Settings.messageHoverHighlight && hovered) ? Nheko.colors.alternateBase : "transparent" color: (Settings.messageHoverHighlight && hovered) ? Nheko.colors.alternateBase : "transparent"
anchors.fill: parent anchors.fill: parent
// this looks better without margins // this looks better without margins
}
TapHandler { TapHandler {
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onSingleTapped: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText) onSingleTapped: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
gesturePolicy: TapHandler.ReleaseWithinBounds gesturePolicy: TapHandler.ReleaseWithinBounds
} }
TapHandler {
onLongPressed: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
onDoubleTapped: chat.model.reply = eventId
gesturePolicy: TapHandler.ReleaseWithinBounds
} }
Control {
onPressAndHold: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
onDoubleClicked: chat.model.reply = eventId
Rectangle {
id: row id: row
property bool bubbleOnRight : isSender && Settings.bubbles property bool bubbleOnRight : isSender && Settings.bubbles
anchors.leftMargin: isStateEvent || Settings.smallAvatars? 0 : Nheko.avatarSize+8 // align bubble with section header anchors.leftMargin: isStateEvent || Settings.smallAvatars? 0 : Nheko.avatarSize+8 // align bubble with section header
@ -78,20 +75,21 @@ Item {
anchors.horizontalCenter: isStateEvent? parent.horizontalCenter : undefined anchors.horizontalCenter: isStateEvent? parent.horizontalCenter : undefined
property int maxWidth: (parent.width-(Settings.smallAvatars || isStateEvent? 0 : Nheko.avatarSize+8))*(Settings.bubbles && !isStateEvent? 0.9 : 1) property int maxWidth: (parent.width-(Settings.smallAvatars || isStateEvent? 0 : Nheko.avatarSize+8))*(Settings.bubbles && !isStateEvent? 0.9 : 1)
width: Settings.bubbles? Math.min(maxWidth,Math.max(reply.implicitWidth+8,contentItem.implicitWidth+metadata.width+20)) : maxWidth width: Settings.bubbles? Math.min(maxWidth,Math.max(reply.implicitWidth+8,contentItem.implicitWidth+metadata.width+20)) : maxWidth
height: msg.height+msg.anchors.margins*2
leftPadding: 4
rightPadding: (Settings.bubbles && !isStateEvent)? 4: 2
topPadding: rightPadding
bottomPadding: topPadding
background: Rectangle {
property color userColor: TimelineManager.userColor(userId, Nheko.colors.base) property color userColor: TimelineManager.userColor(userId, Nheko.colors.base)
property color bgColor: Nheko.colors.base property color bgColor: Nheko.colors.base
color: Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) color: (Settings.bubbles && !isStateEvent) ? Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) : "#00000000"
radius: 4 radius: 4
visible: Settings.bubbles && !isStateEvent
}
contentItem: GridLayout { GridLayout {
anchors {
left: parent.left
top: parent.top
right: parent.right
margins: (Settings.bubbles && ! isStateEvent)? 4 : 2
leftMargin: 4
}
id: msg id: msg
rowSpacing: 0 rowSpacing: 0
columnSpacing: 2 columnSpacing: 2

View File

@ -5,9 +5,10 @@
import QtQuick 2.15 import QtQuick 2.15
import QtQuick.Window 2.15 import QtQuick.Window 2.15
import QtQuick.Controls 2.3
import im.nheko 1.0 import im.nheko 1.0
Item { AbstractButton {
required property int type required property int type
required property int originalWidth required property int originalWidth
required property double proportionalHeight required property double proportionalHeight
@ -24,6 +25,7 @@ Item {
implicitWidth: Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1)) implicitWidth: Math.round(tempWidth*Math.min((timelineView.height/divisor)/(tempWidth*proportionalHeight), 1))
width: Math.min(parent.width,implicitWidth) width: Math.min(parent.width,implicitWidth)
height: width*proportionalHeight height: width*proportionalHeight
hoverEnabled: true
property int metadataWidth property int metadataWidth
property bool fitsMetadata: (parent.width - width) > metadataWidth+4 property bool fitsMetadata: (parent.width - width) > metadataWidth+4
@ -61,28 +63,17 @@ Item {
visible: loaded visible: loaded
anchors.fill: parent anchors.fill: parent
roomm: room roomm: room
play: !Settings.animateImagesOnHover || mouseArea.hovered play: !Settings.animateImagesOnHover || parent.hovered
eventId: parent.eventId eventId: parent.eventId
} }
TapHandler { onClicked :Settings.openImageExternal ? room.openMedia(eventId) : TimelineManager.openImageOverlay(room, url, eventId);
//enabled: type == MtxEvent.ImageMessage && (img.status == Image.Ready || mxcimage.loaded)
onSingleTapped: {
Settings.openImageExternal ? room.openMedia(eventId) : TimelineManager.openImageOverlay(room, url, eventId);
eventPoint.accepted = true;
}
gesturePolicy: TapHandler.ReleaseWithinBounds
}
HoverHandler {
id: mouseArea
}
Item { Item {
id: overlay id: overlay
anchors.fill: parent anchors.fill: parent
visible: mouseArea.hovered visible: parent.hovered
Rectangle { Rectangle {
id: container id: container

View File

@ -11,7 +11,7 @@ import QtQuick.Window 2.13
import im.nheko 1.0 import im.nheko 1.0
import "../" import "../"
Item { AbstractButton {
id: r id: r
property color userColor: "red" property color userColor: "red"
@ -57,6 +57,16 @@ Item {
color: TimelineManager.userColor(userId, Nheko.colors.base) color: TimelineManager.userColor(userId, Nheko.colors.base)
} }
onClicked: {
let link = reply.child.linkAt != undefined && reply.child.linkAt(pressX-colorLine.width, pressY - userName_.implicitHeight);
if (link) {
Nheko.openLink(link)
} else {
room.showEvent(r.eventId)
}
}
onPressAndHold: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(pressX-colorLine.width, pressY - userName_.implicitHeight), r.eventId)
ColumnLayout { ColumnLayout {
id: replyContainer id: replyContainer
@ -64,23 +74,9 @@ Item {
width: parent.width - 4 width: parent.width - 4
spacing: 0 spacing: 0
TapHandler {
acceptedButtons: Qt.LeftButton
onSingleTapped: {
let link = reply.child.linkAt != undefined && reply.child.linkAt(eventPoint.position.x, eventPoint.position.y - userName_.implicitHeight);
if (link) {
Nheko.openLink(link)
} else {
room.showEvent(r.eventId)
}
}
gesturePolicy: TapHandler.ReleaseWithinBounds
}
TapHandler { TapHandler {
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onLongPressed: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(eventPoint.position.x, eventPoint.position.y - userName_.implicitHeight)) onSingleTapped: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(eventPoint.position.x, eventPoint.position.y - userName_.implicitHeight), r.eventId)
onSingleTapped: replyContextMenu.show(reply.child.copyText, reply.child.linkAt(eventPoint.position.x, eventPoint.position.y - userName_.implicitHeight))
gesturePolicy: TapHandler.ReleaseWithinBounds gesturePolicy: TapHandler.ReleaseWithinBounds
} }