Better touch scrolling (#1012)
This commit is contained in:
parent
41c6b75efc
commit
13baf77435
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user