forked from mirror/nheko
parent
517a126a44
commit
1a029112d9
@ -1,111 +1,113 @@ |
|||||||
import QtQuick 2.9 |
import QtQuick 2.9 |
||||||
import QtQuick.Controls 2.3 |
import QtQuick.Controls 2.3 |
||||||
import QtQuick.Layouts 1.2 |
import QtQuick.Layouts 1.2 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Rectangle { |
Rectangle { |
||||||
id: activeCallBar |
id: activeCallBar |
||||||
visible: TimelineManager.callState != WebRTCState.DISCONNECTED |
|
||||||
color: "#2ECC71" |
visible: TimelineManager.callState != WebRTCState.DISCONNECTED |
||||||
implicitHeight: rowLayout.height + 8 |
color: "#2ECC71" |
||||||
|
implicitHeight: rowLayout.height + 8 |
||||||
RowLayout { |
|
||||||
id: rowLayout |
RowLayout { |
||||||
anchors.left: parent.left |
id: rowLayout |
||||||
anchors.right: parent.right |
|
||||||
anchors.verticalCenter: parent.verticalCenter |
anchors.left: parent.left |
||||||
anchors.leftMargin: 8 |
anchors.right: parent.right |
||||||
|
anchors.verticalCenter: parent.verticalCenter |
||||||
Avatar { |
anchors.leftMargin: 8 |
||||||
width: avatarSize |
|
||||||
height: avatarSize |
Avatar { |
||||||
|
width: avatarSize |
||||||
url: TimelineManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/") |
height: avatarSize |
||||||
displayName: TimelineManager.callPartyName |
url: TimelineManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/") |
||||||
} |
displayName: TimelineManager.callPartyName |
||||||
|
} |
||||||
Label { |
|
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1 |
Label { |
||||||
text: " " + TimelineManager.callPartyName + " " |
font.pointSize: fontMetrics.font.pointSize * 1.1 |
||||||
} |
text: " " + TimelineManager.callPartyName + " " |
||||||
|
} |
||||||
Image { |
|
||||||
Layout.preferredWidth: 24 |
Image { |
||||||
Layout.preferredHeight: 24 |
Layout.preferredWidth: 24 |
||||||
source: "qrc:/icons/icons/ui/place-call.png" |
Layout.preferredHeight: 24 |
||||||
} |
source: "qrc:/icons/icons/ui/place-call.png" |
||||||
|
} |
||||||
Label { |
|
||||||
id: callStateLabel |
Label { |
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1 |
id: callStateLabel |
||||||
} |
|
||||||
|
font.pointSize: fontMetrics.font.pointSize * 1.1 |
||||||
Connections { |
} |
||||||
target: TimelineManager |
|
||||||
function onCallStateChanged(state) { |
Connections { |
||||||
switch (state) { |
function onCallStateChanged(state) { |
||||||
case WebRTCState.INITIATING: |
switch (state) { |
||||||
callStateLabel.text = qsTr("Initiating...") |
case WebRTCState.INITIATING: |
||||||
break; |
callStateLabel.text = qsTr("Initiating..."); |
||||||
case WebRTCState.OFFERSENT: |
break; |
||||||
callStateLabel.text = qsTr("Calling...") |
case WebRTCState.OFFERSENT: |
||||||
break; |
callStateLabel.text = qsTr("Calling..."); |
||||||
case WebRTCState.CONNECTING: |
break; |
||||||
callStateLabel.text = qsTr("Connecting...") |
case WebRTCState.CONNECTING: |
||||||
break; |
callStateLabel.text = qsTr("Connecting..."); |
||||||
case WebRTCState.CONNECTED: |
break; |
||||||
callStateLabel.text = "00:00" |
case WebRTCState.CONNECTED: |
||||||
var d = new Date() |
callStateLabel.text = "00:00"; |
||||||
callTimer.startTime = Math.floor(d.getTime() / 1000) |
var d = new Date(); |
||||||
break; |
callTimer.startTime = Math.floor(d.getTime() / 1000); |
||||||
case WebRTCState.DISCONNECTED: |
break; |
||||||
callStateLabel.text = "" |
case WebRTCState.DISCONNECTED: |
||||||
} |
callStateLabel.text = ""; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
Timer { |
target: TimelineManager |
||||||
id: callTimer |
} |
||||||
property int startTime |
|
||||||
interval: 1000 |
Timer { |
||||||
running: TimelineManager.callState == WebRTCState.CONNECTED |
id: callTimer |
||||||
repeat: true |
|
||||||
onTriggered: { |
property int startTime |
||||||
var d = new Date() |
|
||||||
let seconds = Math.floor(d.getTime() / 1000 - startTime) |
function pad(n) { |
||||||
let s = Math.floor(seconds % 60) |
return (n < 10) ? ("0" + n) : n; |
||||||
let m = Math.floor(seconds / 60) % 60 |
} |
||||||
let h = Math.floor(seconds / 3600) |
|
||||||
callStateLabel.text = (h ? (pad(h) + ":") : "") + pad(m) + ":" + pad(s) |
interval: 1000 |
||||||
} |
running: TimelineManager.callState == WebRTCState.CONNECTED |
||||||
|
repeat: true |
||||||
function pad(n) { |
onTriggered: { |
||||||
return (n < 10) ? ("0" + n) : n |
var d = new Date(); |
||||||
} |
let seconds = Math.floor(d.getTime() / 1000 - startTime); |
||||||
} |
let s = Math.floor(seconds % 60); |
||||||
|
let m = Math.floor(seconds / 60) % 60; |
||||||
Item { |
let h = Math.floor(seconds / 3600); |
||||||
Layout.fillWidth: true |
callStateLabel.text = (h ? (pad(h) + ":") : "") + pad(m) + ":" + pad(s); |
||||||
} |
} |
||||||
|
} |
||||||
ImageButton { |
|
||||||
width: 24 |
Item { |
||||||
height: 24 |
Layout.fillWidth: true |
||||||
buttonTextColor: "#000000" |
} |
||||||
image: TimelineManager.isMicMuted ? |
|
||||||
":/icons/icons/ui/microphone-unmute.png" : |
ImageButton { |
||||||
":/icons/icons/ui/microphone-mute.png" |
width: 24 |
||||||
|
height: 24 |
||||||
hoverEnabled: true |
buttonTextColor: "#000000" |
||||||
ToolTip.visible: hovered |
image: TimelineManager.isMicMuted ? ":/icons/icons/ui/microphone-unmute.png" : ":/icons/icons/ui/microphone-mute.png" |
||||||
ToolTip.text: TimelineManager.isMicMuted ? qsTr("Unmute Mic") : qsTr("Mute Mic") |
hoverEnabled: true |
||||||
|
ToolTip.visible: hovered |
||||||
onClicked: TimelineManager.toggleMicMute() |
ToolTip.text: TimelineManager.isMicMuted ? qsTr("Unmute Mic") : qsTr("Mute Mic") |
||||||
} |
onClicked: TimelineManager.toggleMicMute() |
||||||
|
} |
||||||
Item { |
|
||||||
implicitWidth: 16 |
Item { |
||||||
} |
implicitWidth: 16 |
||||||
} |
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,69 +1,75 @@ |
|||||||
|
import QtGraphicalEffects 1.0 |
||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
import QtQuick.Controls 2.3 |
import QtQuick.Controls 2.3 |
||||||
import QtGraphicalEffects 1.0 |
|
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Rectangle { |
Rectangle { |
||||||
id: avatar |
id: avatar |
||||||
width: 48 |
|
||||||
height: 48 |
property alias url: img.source |
||||||
radius: Settings.avatarCircles ? height/2 : 3 |
property string userid |
||||||
|
property string displayName |
||||||
|
|
||||||
property alias url: img.source |
width: 48 |
||||||
property string userid |
height: 48 |
||||||
property string displayName |
radius: Settings.avatarCircles ? height / 2 : 3 |
||||||
|
color: colors.base |
||||||
|
|
||||||
Label { |
Label { |
||||||
anchors.fill: parent |
anchors.fill: parent |
||||||
text: TimelineManager.escapeEmoji(displayName ? String.fromCodePoint(displayName.codePointAt(0)) : "") |
text: TimelineManager.escapeEmoji(displayName ? String.fromCodePoint(displayName.codePointAt(0)) : "") |
||||||
textFormat: Text.RichText |
textFormat: Text.RichText |
||||||
font.pixelSize: avatar.height/2 |
font.pixelSize: avatar.height / 2 |
||||||
verticalAlignment: Text.AlignVCenter |
verticalAlignment: Text.AlignVCenter |
||||||
horizontalAlignment: Text.AlignHCenter |
horizontalAlignment: Text.AlignHCenter |
||||||
visible: img.status != Image.Ready |
visible: img.status != Image.Ready |
||||||
color: colors.text |
color: colors.text |
||||||
} |
} |
||||||
|
|
||||||
Image { |
Image { |
||||||
id: img |
id: img |
||||||
anchors.fill: parent |
|
||||||
asynchronous: true |
|
||||||
fillMode: Image.PreserveAspectCrop |
|
||||||
mipmap: true |
|
||||||
smooth: false |
|
||||||
|
|
||||||
sourceSize.width: avatar.width |
anchors.fill: parent |
||||||
sourceSize.height: avatar.height |
asynchronous: true |
||||||
|
fillMode: Image.PreserveAspectCrop |
||||||
|
mipmap: true |
||||||
|
smooth: false |
||||||
|
sourceSize.width: avatar.width |
||||||
|
sourceSize.height: avatar.height |
||||||
|
layer.enabled: true |
||||||
|
|
||||||
layer.enabled: true |
layer.effect: OpacityMask { |
||||||
layer.effect: OpacityMask { |
|
||||||
maskSource: Rectangle { |
|
||||||
anchors.fill: parent |
|
||||||
width: avatar.width |
|
||||||
height: avatar.height |
|
||||||
radius: Settings.avatarCircles ? height/2 : 3 |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
maskSource: Rectangle { |
||||||
|
anchors.fill: parent |
||||||
|
width: avatar.width |
||||||
|
height: avatar.height |
||||||
|
radius: Settings.avatarCircles ? height / 2 : 3 |
||||||
|
} |
||||||
|
|
||||||
Rectangle { |
} |
||||||
anchors.bottom: avatar.bottom |
|
||||||
anchors.right: avatar.right |
|
||||||
|
|
||||||
visible: !!userid |
} |
||||||
|
|
||||||
height: avatar.height / 6 |
Rectangle { |
||||||
width: height |
anchors.bottom: avatar.bottom |
||||||
radius: Settings.avatarCircles ? height / 2 : height / 4 |
anchors.right: avatar.right |
||||||
color: switch (TimelineManager.userPresence(userid)) { |
visible: !!userid |
||||||
case "online": return "#00cc66" |
height: avatar.height / 6 |
||||||
case "unavailable": return "#ff9933" |
width: height |
||||||
case "offline": // return "#a82353" don't show anything if offline, since it is confusing, if presence is disabled |
radius: Settings.avatarCircles ? height / 2 : height / 4 |
||||||
default: "transparent" |
color: { |
||||||
} |
switch (TimelineManager.userPresence(userid)) { |
||||||
} |
case "online": |
||||||
|
return "#00cc66"; |
||||||
|
case "unavailable": |
||||||
|
return "#ff9933"; |
||||||
|
case "offline": |
||||||
|
default: |
||||||
|
// return "#a82353" don't show anything if offline, since it is confusing, if presence is disabled |
||||||
|
"transparent"; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
color: colors.base |
|
||||||
} |
} |
||||||
|
@ -1,35 +1,37 @@ |
|||||||
import QtQuick 2.5 |
import QtQuick 2.5 |
||||||
import QtQuick.Controls 2.3 |
import QtQuick.Controls 2.3 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
TextEdit { |
TextEdit { |
||||||
textFormat: TextEdit.RichText |
textFormat: TextEdit.RichText |
||||||
readOnly: true |
readOnly: true |
||||||
wrapMode: Text.Wrap |
wrapMode: Text.Wrap |
||||||
selectByMouse: true |
selectByMouse: true |
||||||
activeFocusOnPress: false |
activeFocusOnPress: false |
||||||
color: colors.text |
color: colors.text |
||||||
|
onLinkActivated: { |
||||||
|
if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) { |
||||||
|
chat.model.openUserProfile(/^https:\/\/matrix.to\/#\/(@.*)$/.exec(link)[1]); |
||||||
|
} else if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) { |
||||||
|
TimelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1]); |
||||||
|
} else if (/^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.test(link)) { |
||||||
|
var match = /^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.exec(link); |
||||||
|
TimelineManager.setHistoryView(match[1]); |
||||||
|
chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain); |
||||||
|
} else { |
||||||
|
TimelineManager.openLink(link); |
||||||
|
} |
||||||
|
} |
||||||
|
ToolTip.visible: hoveredLink |
||||||
|
ToolTip.text: hoveredLink |
||||||
|
|
||||||
|
MouseArea { |
||||||
|
id: ma |
||||||
|
|
||||||
onLinkActivated: { |
anchors.fill: parent |
||||||
if (/^https:\/\/matrix.to\/#\/(@.*)$/.test(link)) chat.model.openUserProfile(/^https:\/\/matrix.to\/#\/(@.*)$/.exec(link)[1]) |
propagateComposedEvents: true |
||||||
else if (/^https:\/\/matrix.to\/#\/(![^\/]*)$/.test(link)) TimelineManager.setHistoryView(/^https:\/\/matrix.to\/#\/(!.*)$/.exec(link)[1]) |
acceptedButtons: Qt.NoButton |
||||||
else if (/^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.test(link)) { |
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor |
||||||
var match = /^https:\/\/matrix.to\/#\/(![^\/]*)\/(\$.*)$/.exec(link) |
} |
||||||
TimelineManager.setHistoryView(match[1]) |
|
||||||
chat.positionViewAtIndex(chat.model.idToIndex(match[2]), ListView.Contain) |
|
||||||
} |
|
||||||
else TimelineManager.openLink(link) |
|
||||||
} |
|
||||||
MouseArea |
|
||||||
{ |
|
||||||
id: ma |
|
||||||
anchors.fill: parent |
|
||||||
propagateComposedEvents: true |
|
||||||
acceptedButtons: Qt.NoButton |
|
||||||
cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor |
|
||||||
} |
|
||||||
|
|
||||||
ToolTip.visible: hoveredLink |
|
||||||
ToolTip.text: hoveredLink |
|
||||||
} |
} |
||||||
|
@ -1,94 +1,95 @@ |
|||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
import QtQuick.Controls 2.2 |
import QtQuick.Controls 2.2 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
// This class is for showing Reactions in the timeline row, not for |
// This class is for showing Reactions in the timeline row, not for |
||||||
// adding new reactions via the emoji picker |
// adding new reactions via the emoji picker |
||||||
Flow { |
Flow { |
||||||
id: reactionFlow |
id: reactionFlow |
||||||
|
|
||||||
// highlight colors for selfReactedEvent background |
// highlight colors for selfReactedEvent background |
||||||
property real highlightHue: colors.highlight.hslHue |
property real highlightHue: colors.highlight.hslHue |
||||||
property real highlightSat: colors.highlight.hslSaturation |
property real highlightSat: colors.highlight.hslSaturation |
||||||
property real highlightLight: colors.highlight.hslLightness |
property real highlightLight: colors.highlight.hslLightness |
||||||
|
property string eventId |
||||||
property string eventId |
property alias reactions: repeater.model |
||||||
|
|
||||||
anchors.left: parent.left |
anchors.left: parent.left |
||||||
anchors.right: parent.right |
anchors.right: parent.right |
||||||
spacing: 4 |
spacing: 4 |
||||||
|
|
||||||
property alias reactions: repeater.model |
Repeater { |
||||||
|
id: repeater |
||||||
Repeater { |
|
||||||
id: repeater |
delegate: AbstractButton { |
||||||
|
id: reaction |
||||||
delegate: AbstractButton { |
|
||||||
id: reaction |
hoverEnabled: true |
||||||
hoverEnabled: true |
implicitWidth: contentItem.childrenRect.width + contentItem.leftPadding * 2 |
||||||
implicitWidth: contentItem.childrenRect.width + contentItem.leftPadding*2 |
implicitHeight: contentItem.childrenRect.height |
||||||
implicitHeight: contentItem.childrenRect.height |
ToolTip.visible: hovered |
||||||
|
ToolTip.text: modelData.users |
||||||
ToolTip.visible: hovered |
onClicked: { |
||||||
ToolTip.text: modelData.users |
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent); |
||||||
|
TimelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key); |
||||||
onClicked: { |
} |
||||||
console.debug("Picked " + modelData.key + "in response to " + reactionFlow.eventId + ". selfReactedEvent: " + modelData.selfReactedEvent) |
|
||||||
TimelineManager.queueReactionMessage(reactionFlow.eventId, modelData.key) |
contentItem: Row { |
||||||
} |
anchors.centerIn: parent |
||||||
|
spacing: reactionText.implicitHeight / 4 |
||||||
|
leftPadding: reactionText.implicitHeight / 2 |
||||||
contentItem: Row { |
rightPadding: reactionText.implicitHeight / 2 |
||||||
anchors.centerIn: parent |
|
||||||
spacing: reactionText.implicitHeight/4 |
TextMetrics { |
||||||
leftPadding: reactionText.implicitHeight / 2 |
id: textMetrics |
||||||
rightPadding: reactionText.implicitHeight / 2 |
|
||||||
|
font.family: Settings.emojiFont |
||||||
TextMetrics { |
elide: Text.ElideRight |
||||||
id: textMetrics |
elideWidth: 150 |
||||||
font.family: Settings.emojiFont |
text: modelData.key |
||||||
elide: Text.ElideRight |
} |
||||||
elideWidth: 150 |
|
||||||
text: modelData.key |
Text { |
||||||
} |
id: reactionText |
||||||
|
|
||||||
Text { |
anchors.baseline: reactionCounter.baseline |
||||||
anchors.baseline: reactionCounter.baseline |
text: textMetrics.elidedText + (textMetrics.elidedText == modelData.key ? "" : "…") |
||||||
id: reactionText |
font.family: Settings.emojiFont |
||||||
text: textMetrics.elidedText + (textMetrics.elidedText == modelData.key ? "" : "…") |
color: reaction.hovered ? colors.highlight : colors.text |
||||||
font.family: Settings.emojiFont |
maximumLineCount: 1 |
||||||
color: reaction.hovered ? colors.highlight : colors.text |
} |
||||||
maximumLineCount: 1 |
|
||||||
} |
Rectangle { |
||||||
|
id: divider |
||||||
Rectangle { |
|
||||||
id: divider |
height: Math.floor(reactionCounter.implicitHeight * 1.4) |
||||||
height: Math.floor(reactionCounter.implicitHeight * 1.4) |
width: 1 |
||||||
width: 1 |
color: (reaction.hovered || modelData.selfReactedEvent !== '') ? colors.highlight : colors.text |
||||||
color: (reaction.hovered || modelData.selfReactedEvent !== '') ? colors.highlight : colors.text |
} |
||||||
} |
|
||||||
|
Text { |
||||||
Text { |
id: reactionCounter |
||||||
anchors.verticalCenter: divider.verticalCenter |
|
||||||
id: reactionCounter |
anchors.verticalCenter: divider.verticalCenter |
||||||
text: modelData.count |
text: modelData.count |
||||||
font: reaction.font |
font: reaction.font |
||||||
color: reaction.hovered ? colors.highlight : colors.text |
color: reaction.hovered ? colors.highlight : colors.text |
||||||
} |
} |
||||||
} |
|
||||||
|
} |
||||||
background: Rectangle { |
|
||||||
anchors.centerIn: parent |
background: Rectangle { |
||||||
|
anchors.centerIn: parent |
||||||
implicitWidth: reaction.implicitWidth |
implicitWidth: reaction.implicitWidth |
||||||
implicitHeight: reaction.implicitHeight |
implicitHeight: reaction.implicitHeight |
||||||
border.color: (reaction.hovered || modelData.selfReactedEvent !== '') ? colors.highlight : colors.text |
border.color: (reaction.hovered || modelData.selfReactedEvent !== '') ? colors.highlight : colors.text |
||||||
color: modelData.selfReactedEvent !== '' ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.20) : colors.base |
color: modelData.selfReactedEvent !== '' ? Qt.hsla(highlightHue, highlightSat, highlightLight, 0.2) : colors.base |
||||||
border.width: 1 |
border.width: 1 |
||||||
radius: reaction.height / 2.0 |
radius: reaction.height / 2 |
||||||
} |
} |
||||||
} |
|
||||||
} |
} |
||||||
} |
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
@ -1,146 +1,148 @@ |
|||||||
|
import "./delegates" |
||||||
|
import "./emoji" |
||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
import QtQuick.Controls 2.3 |
import QtQuick.Controls 2.3 |
||||||
import QtQuick.Layouts 1.2 |
import QtQuick.Layouts 1.2 |
||||||
import QtQuick.Window 2.2 |
import QtQuick.Window 2.2 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
import "./delegates" |
|
||||||
import "./emoji" |
|
||||||
|
|
||||||
Item { |
Item { |
||||||
anchors.left: parent.left |
anchors.left: parent.left |
||||||
anchors.right: parent.right |
anchors.right: parent.right |
||||||
height: row.height |
height: row.height |
||||||
|
|
||||||
MouseArea { |
MouseArea { |
||||||
anchors.fill: parent |
anchors.fill: parent |
||||||
propagateComposedEvents: true |
propagateComposedEvents: true |
||||||
preventStealing: true |
preventStealing: true |
||||||
hoverEnabled: true |
hoverEnabled: true |
||||||
|
acceptedButtons: Qt.AllButtons |
||||||
acceptedButtons: Qt.AllButtons |
onClicked: { |
||||||
onClicked: { |
if (mouse.button === Qt.RightButton) |
||||||
if (mouse.button === Qt.RightButton) |
messageContextMenu.show(model.id, model.type, model.isEncrypted, row); |
||||||
messageContextMenu.show(model.id, model.type, model.isEncrypted, row) |
|
||||||
} |
} |
||||||
onPressAndHold: { |
onPressAndHold: { |
||||||
messageContextMenu.show(model.id, model.type, model.isEncrypted, row, mapToItem(timelineRoot, mouse.x, mouse.y)) |
messageContextMenu.show(model.id, model.type, model.isEncrypted, row, mapToItem(timelineRoot, mouse.x, mouse.y)); |
||||||
} |
} |
||||||
} |
} |
||||||
Rectangle { |
|
||||||
color: (Settings.messageHoverHighlight && parent.containsMouse) ? colors.base : "transparent" |
Rectangle { |
||||||
anchors.fill: row |
color: (Settings.messageHoverHighlight && parent.containsMouse) ? colors.base : "transparent" |
||||||
} |
anchors.fill: row |
||||||
RowLayout { |
} |
||||||
id: row |
|
||||||
|
RowLayout { |
||||||
anchors.leftMargin: avatarSize + 16 |
id: row |
||||||
anchors.left: parent.left |
|
||||||
anchors.right: parent.right |
anchors.leftMargin: avatarSize + 16 |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.right: parent.right |
||||||
Column { |
|
||||||
Layout.fillWidth: true |
Column { |
||||||
Layout.alignment: Qt.AlignTop |
Layout.fillWidth: true |
||||||
spacing: 4 |
Layout.alignment: Qt.AlignTop |
||||||
|
spacing: 4 |
||||||
// fancy reply, if this is a reply |
|
||||||
Reply { |
// fancy reply, if this is a reply |
||||||
visible: model.replyTo |
Reply { |
||||||
modelData: chat.model.getDump(model.replyTo,model.id) |
visible: model.replyTo |
||||||
userColor: TimelineManager.userColor(modelData.userId, colors.window) |
modelData: chat.model.getDump(model.replyTo, model.id) |
||||||
} |
userColor: TimelineManager.userColor(modelData.userId, colors.window) |
||||||
|
} |
||||||
// actual message content |
|
||||||
MessageDelegate { |
// actual message content |
||||||
id: contentItem |
MessageDelegate { |
||||||
|
id: contentItem |
||||||
width: parent.width |
|
||||||
|
width: parent.width |
||||||
modelData: model |
modelData: model |
||||||
} |
} |
||||||
|
|
||||||
Reactions { |
Reactions { |
||||||
id: reactionRow |
id: reactionRow |
||||||
reactions: model.reactions |
|
||||||
eventId: model.id |
reactions: model.reactions |
||||||
} |
eventId: model.id |
||||||
} |
} |
||||||
|
|
||||||
StatusIndicator { |
} |
||||||
state: model.state |
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
StatusIndicator { |
||||||
Layout.preferredHeight: 16 |
state: model.state |
||||||
width: 16 |
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
} |
Layout.preferredHeight: 16 |
||||||
|
width: 16 |
||||||
EncryptionIndicator { |
} |
||||||
visible: model.isRoomEncrypted |
|
||||||
encrypted: model.isEncrypted |
EncryptionIndicator { |
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
visible: model.isRoomEncrypted |
||||||
Layout.preferredHeight: 16 |
encrypted: model.isEncrypted |
||||||
width: 16 |
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
} |
Layout.preferredHeight: 16 |
||||||
EmojiButton { |
width: 16 |
||||||
visible: Settings.buttonsInTimeline |
} |
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
|
||||||
Layout.preferredHeight: 16 |
EmojiButton { |
||||||
width: 16 |
id: reactButton |
||||||
id: reactButton |
|
||||||
hoverEnabled: true |
visible: Settings.buttonsInTimeline |
||||||
ToolTip.visible: hovered |
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
ToolTip.text: qsTr("React") |
Layout.preferredHeight: 16 |
||||||
emojiPicker: emojiPopup |
width: 16 |
||||||
event_id: model.id |
hoverEnabled: true |
||||||
} |
ToolTip.visible: hovered |
||||||
ImageButton { |
ToolTip.text: qsTr("React") |
||||||
visible: Settings.buttonsInTimeline |
emojiPicker: emojiPopup |
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
event_id: model.id |
||||||
Layout.preferredHeight: 16 |
} |
||||||
width: 16 |
|
||||||
id: replyButton |
ImageButton { |
||||||
hoverEnabled: true |
id: replyButton |
||||||
|
|
||||||
|
visible: Settings.buttonsInTimeline |
||||||
image: ":/icons/icons/ui/mail-reply.png" |
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
|
Layout.preferredHeight: 16 |
||||||
ToolTip.visible: hovered |
width: 16 |
||||||
ToolTip.text: qsTr("Reply") |
hoverEnabled: true |
||||||
|
image: ":/icons/icons/ui/mail-reply.png" |
||||||
onClicked: chat.model.replyAction(model.id) |
ToolTip.visible: hovered |
||||||
} |
ToolTip.text: qsTr("Reply") |
||||||
ImageButton { |
onClicked: chat.model.replyAction(model.id) |
||||||
visible: Settings.buttonsInTimeline |
} |
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
|
||||||
Layout.preferredHeight: 16 |
ImageButton { |
||||||
width: 16 |
id: optionsButton |
||||||
id: optionsButton |
|
||||||
hoverEnabled: true |
visible: Settings.buttonsInTimeline |
||||||
|
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
image: ":/icons/icons/ui/vertical-ellipsis.png" |
Layout.preferredHeight: 16 |
||||||
|
width: 16 |
||||||
ToolTip.visible: hovered |
hoverEnabled: true |
||||||
ToolTip.text: qsTr("Options") |
image: ":/icons/icons/ui/vertical-ellipsis.png" |
||||||
|
ToolTip.visible: hovered |
||||||
onClicked: messageContextMenu.show(model.id, model.type, model.isEncrypted, optionsButton) |
ToolTip.text: qsTr("Options") |
||||||
} |
onClicked: messageContextMenu.show(model.id, model.type, model.isEncrypted, optionsButton) |
||||||
|
} |
||||||
Label { |
|
||||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
Label { |
||||||
text: model.timestamp.toLocaleTimeString("HH:mm") |
Layout.alignment: Qt.AlignRight | Qt.AlignTop |
||||||
width: Math.max(implicitWidth, text.length*fontMetrics.maximumCharacterWidth) |
text: model.timestamp.toLocaleTimeString("HH:mm") |
||||||
color: inactiveColors.text |
width: Math.max(implicitWidth, text.length * fontMetrics.maximumCharacterWidth) |
||||||
|
color: inactiveColors.text |
||||||
MouseArea{ |
ToolTip.visible: ma.containsMouse |
||||||
id: ma |
ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) |
||||||
anchors.fill: parent |
|
||||||
hoverEnabled: true |
MouseArea { |
||||||
propagateComposedEvents: true |
id: ma |
||||||
} |
|
||||||
|
anchors.fill: parent |
||||||
ToolTip.visible: ma.containsMouse |
hoverEnabled: true |
||||||
ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate) |
propagateComposedEvents: true |
||||||
} |
} |
||||||
} |
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,172 +1,175 @@ |
|||||||
|
import "./device-verification" |
||||||
import QtQuick 2.9 |
import QtQuick 2.9 |
||||||
import QtQuick.Controls 2.3 |
import QtQuick.Controls 2.3 |
||||||
import QtQuick.Layouts 1.2 |
import QtQuick.Layouts 1.2 |
||||||
import QtQuick.Window 2.3 |
import QtQuick.Window 2.3 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
import "./device-verification" |
ApplicationWindow { |
||||||
|
id: userProfileDialog |
||||||
|
|
||||||
|
property var profile |
||||||
|
|
||||||
|
height: 650 |
||||||
|
width: 420 |
||||||
|
minimumHeight: 420 |
||||||
|
palette: colors |
||||||
|
|
||||||
|
Component { |
||||||
|
id: deviceVerificationDialog |
||||||
|
|
||||||
|
DeviceVerification { |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
ColumnLayout { |
||||||
|
id: contentL |
||||||
|
|
||||||
|
anchors.fill: parent |
||||||
|
anchors.margins: 10 |
||||||
|
spacing: 10 |
||||||
|
|
||||||
|
Avatar { |
||||||
|
url: profile.avatarUrl.replace("mxc://", "image://MxcImage/") |
||||||
|
height: 130 |
||||||
|
width: 130 |
||||||
|
displayName: profile.displayName |
||||||
|
userid: profile.userid |
||||||
|
Layout.alignment: Qt.AlignHCenter |
||||||
|
} |
||||||
|
|
||||||
|
Label { |
||||||
|
text: profile.displayName |
||||||
|
fontSizeMode: Text.HorizontalFit |
||||||
|
font.pixelSize: 20 |
||||||
|
color: TimelineManager.userColor(profile.userid, colors.window) |
||||||
|
font.bold: true |
||||||
|
Layout.alignment: Qt.AlignHCenter |
||||||
|
} |
||||||
|
|
||||||
|
MatrixText { |
||||||
|
text: profile.userid |
||||||
|
font.pixelSize: 15 |
||||||
|
Layout.alignment: Qt.AlignHCenter |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
id: verifyUserButton |
||||||
|
|
||||||
|
text: qsTr("Verify") |
||||||
|
Layout.alignment: Qt.AlignHCenter |
||||||
|
enabled: !profile.isUserVerified |
||||||
|
visible: !profile.isUserVerified |
||||||
|
onClicked: profile.verify() |
||||||
|
} |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
Layout.alignment: Qt.AlignHCenter |
||||||
|
spacing: 8 |
||||||
|
|
||||||
|
ImageButton { |
||||||
|
image: ":/icons/icons/ui/do-not-disturb-rounded-sign.png" |
||||||
|
hoverEnabled: true |
||||||
|
ToolTip.visible: hovered |
||||||
|
ToolTip.text: qsTr("Ban the user") |
||||||
|
onClicked: profile.banUser() |
||||||
|
} |
||||||
|
// ImageButton{ |
||||||
|
|
||||||
|
// image:":/icons/icons/ui/volume-off-indicator.png" |
||||||
|
// Layout.margins: { |
||||||
|
// left: 5 |
||||||
|
// right: 5 |
||||||
|
// } |
||||||
|
// ToolTip.visible: hovered |
||||||
|
// ToolTip.text: qsTr("Ignore messages from this user") |
||||||
|
// onClicked : { |
||||||
|
// profile.ignoreUser() |
||||||
|
// } |
||||||
|
// } |
||||||
|
ImageButton { |
||||||
|
image: ":/icons/icons/ui/black-bubble-speech.png" |
||||||
|
hoverEnabled: true |
||||||
|
ToolTip.visible: hovered |
||||||
|
ToolTip.text: qsTr("Start a private chat") |
||||||
|
onClicked: profile.startChat() |
||||||
|
} |
||||||
|
|
||||||
|
ImageButton { |
||||||
|
image: ":/icons/icons/ui/round-remove-button.png" |
||||||
|
hoverEnabled: true |
||||||
|
ToolTip.visible: hovered |
||||||
|
ToolTip.text: qsTr("Kick the user") |
||||||
|
onClicked: profile.kickUser() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
ListView { |
||||||
|
id: devicelist |
||||||
|
|
||||||
|
Layout.fillHeight: true |
||||||
|
Layout.minimumHeight: 200 |
||||||
|
Layout.fillWidth: true |
||||||
|
clip: true |
||||||
|
spacing: 8 |
||||||
|
boundsBehavior: Flickable.StopAtBounds |
||||||
|
model: profile.deviceList |
||||||
|
|
||||||
|
delegate: RowLayout { |
||||||
|
width: devicelist.width |
||||||
|
spacing: 4 |
||||||
|
|
||||||
|
ColumnLayout { |
||||||
|
spacing: 0 |
||||||
|
|
||||||
|
Text { |
||||||
|
Layout.fillWidth: true |
||||||
|
Layout.alignment: Qt.AlignLeft |
||||||
|
elide: Text.ElideRight |
||||||
|
font.bold: true |
||||||
|
color: colors.text |
||||||
|
text: model.deviceId |
||||||
|
} |
||||||
|
|
||||||
|
Text { |
||||||
|
Layout.fillWidth: true |
||||||
|
Layout.alignment: Qt.AlignRight |
||||||
|
elide: Text.ElideRight |
||||||
|
color: colors.text |
||||||
|
text: model.deviceName |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Image { |
||||||
|
Layout.preferredHeight: 16 |
||||||
|
Layout.preferredWidth: 16 |
||||||
|
source: ((model.verificationStatus == VerificationStatus.VERIFIED) ? "image://colorimage/:/icons/icons/ui/lock.png?green" : ((model.verificationStatus == VerificationStatus.UNVERIFIED) ? "image://colorimage/:/icons/icons/ui/unlock.png?yellow" : "image://colorimage/:/icons/icons/ui/unlock.png?red")) |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
id: verifyButton |
||||||
|
|
||||||
|
text: (model.verificationStatus != VerificationStatus.VERIFIED) ? "Verify" : "Unverify" |
||||||
|
onClicked: { |
||||||
|
if (model.verificationStatus == VerificationStatus.VERIFIED) |
||||||
|
profile.unverify(model.deviceId); |
||||||
|
else |
||||||
|
profile.verify(model.deviceId); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
footer: DialogButtonBox { |
||||||
|
standardButtons: DialogButtonBox.Ok |
||||||
|
onAccepted: userProfileDialog.close() |
||||||
|
} |
||||||
|
|
||||||
ApplicationWindow{ |
|
||||||
property var profile |
|
||||||
|
|
||||||
id: userProfileDialog |
|
||||||
height: 650 |
|
||||||
width: 420 |
|
||||||
minimumHeight: 420 |
|
||||||
|
|
||||||
palette: colors |
|
||||||
|
|
||||||
Component { |
|
||||||
id: deviceVerificationDialog |
|
||||||
DeviceVerification {} |
|
||||||
} |
|
||||||
|
|
||||||
ColumnLayout{ |
|
||||||
id: contentL |
|
||||||
|
|
||||||
anchors.fill: parent |
|
||||||
anchors.margins: 10 |
|
||||||
|
|
||||||
spacing: 10 |
|
||||||
|
|
||||||
Avatar { |
|
||||||
url: profile.avatarUrl.replace("mxc://", "image://MxcImage/") |
|
||||||
height: 130 |
|
||||||
width: 130 |
|
||||||
displayName: profile.displayName |
|
||||||
userid: profile.userid |
|
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
} |
|
||||||
|
|
||||||
Label { |
|
||||||
text: profile.displayName |
|
||||||
fontSizeMode: Text.HorizontalFit |
|
||||||
font.pixelSize: 20 |
|
||||||
color: TimelineManager.userColor(profile.userid, colors.window) |
|
||||||
font.bold: true |
|
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
} |
|
||||||
|
|
||||||
MatrixText { |
|
||||||
text: profile.userid |
|
||||||
font.pixelSize: 15 |
|
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
} |
|
||||||
|
|
||||||
Button { |
|
||||||
id: verifyUserButton |
|
||||||
text: qsTr("Verify") |
|
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
enabled: !profile.isUserVerified |
|
||||||
visible: !profile.isUserVerified |
|
||||||
|
|
||||||
onClicked: profile.verify() |
|
||||||
} |
|
||||||
|
|
||||||
RowLayout { |
|
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
spacing: 8 |
|
||||||
|
|
||||||
ImageButton { |
|
||||||
image:":/icons/icons/ui/do-not-disturb-rounded-sign.png" |
|
||||||
hoverEnabled: true |
|
||||||
ToolTip.visible: hovered |
|
||||||
ToolTip.text: qsTr("Ban the user") |
|
||||||
onClicked: profile.banUser() |
|
||||||
} |
|
||||||
// ImageButton{ |
|
||||||
// image:":/icons/icons/ui/volume-off-indicator.png" |
|
||||||
// Layout.margins: { |
|
||||||
// left: 5 |
|
||||||
// right: 5 |
|
||||||
// } |
|
||||||
// ToolTip.visible: hovered |
|
||||||
// ToolTip.text: qsTr("Ignore messages from this user") |
|
||||||
// onClicked : { |
|
||||||
// profile.ignoreUser() |
|
||||||
// } |
|
||||||
// } |
|
||||||
ImageButton{ |
|
||||||
image:":/icons/icons/ui/black-bubble-speech.png" |
|
||||||
hoverEnabled: true |
|
||||||
ToolTip.visible: hovered |
|
||||||
ToolTip.text: qsTr("Start a private chat") |
|
||||||
onClicked: profile.startChat() |
|
||||||
} |
|
||||||
ImageButton{ |
|
||||||
image:":/icons/icons/ui/round-remove-button.png" |
|
||||||
hoverEnabled: true |
|
||||||
ToolTip.visible: hovered |
|
||||||
ToolTip.text: qsTr("Kick the user") |
|
||||||
onClicked: profile.kickUser() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
ListView{ |
|
||||||
id: devicelist |
|
||||||
|
|
||||||
Layout.fillHeight: true |
|
||||||
Layout.minimumHeight: 200 |
|
||||||
Layout.fillWidth: true |
|
||||||
|
|
||||||
clip: true |
|
||||||
spacing: 8 |
|
||||||
boundsBehavior: Flickable.StopAtBounds |
|
||||||
|
|
||||||
model: profile.deviceList |
|
||||||
|
|
||||||
delegate: RowLayout{ |
|
||||||
width: devicelist.width |
|
||||||
spacing: 4 |
|
||||||
|
|
||||||
ColumnLayout{ |
|
||||||
spacing: 0 |
|
||||||
Text{ |
|
||||||
Layout.fillWidth: true |
|
||||||
Layout.alignment: Qt.AlignLeft |
|
||||||
|
|
||||||
elide: Text.ElideRight |
|
||||||
font.bold: true |
|
||||||
color: colors.text |
|
||||||
text: model.deviceId |
|
||||||
} |
|
||||||
Text{ |
|
||||||
Layout.fillWidth: true |
|
||||||
Layout.alignment: Qt.AlignRight |
|
||||||
|
|
||||||
elide: Text.ElideRight |
|
||||||
color: colors.text |
|
||||||
text: model.deviceName |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
Image{ |
|
||||||
Layout.preferredHeight: 16 |
|
||||||
Layout.preferredWidth: 16 |
|
||||||
|
|
||||||
source: ((model.verificationStatus == VerificationStatus.VERIFIED)?"image://colorimage/:/icons/icons/ui/lock.png?green": |
|
||||||
((model.verificationStatus == VerificationStatus.UNVERIFIED)?"image://colorimage/:/icons/icons/ui/unlock.png?yellow": |
|
||||||
"image://colorimage/:/icons/icons/ui/unlock.png?red")) |
|
||||||
} |
|
||||||
Button{ |
|
||||||
id: verifyButton |
|
||||||
text: (model.verificationStatus != VerificationStatus.VERIFIED)?"Verify":"Unverify" |
|
||||||
onClicked: { |
|
||||||
if(model.verificationStatus == VerificationStatus.VERIFIED){ |
|
||||||
profile.unverify(model.deviceId) |
|
||||||
}else{ |
|
||||||
profile.verify(model.deviceId); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
footer: DialogButtonBox { |
|
||||||
standardButtons: DialogButtonBox.Ok |
|
||||||
|
|
||||||
onAccepted: userProfileDialog.close() |
|
||||||
} |
|
||||||
} |
} |
||||||
|
@ -1,68 +1,75 @@ |
|||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
import QtQuick.Layouts 1.2 |
import QtQuick.Layouts 1.2 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Item { |
Item { |
||||||
height: row.height + 24 |
height: row.height + 24 |
||||||
width: parent ? parent.width : undefined |
width: parent ? parent.width : undefined |
||||||
|
|
||||||
RowLayout { |
RowLayout { |
||||||
id: row |
id: row |
||||||
|
|
||||||
anchors.centerIn: parent |
anchors.centerIn: parent |
||||||
width: parent.width - 24 |
width: parent.width - 24 |
||||||
|
spacing: 15 |
||||||
spacing: 15 |
|
||||||
|
Rectangle { |
||||||
Rectangle { |
id: button |
||||||
id: button |
|
||||||
color: colors.light |
color: colors.light |
||||||
radius: 22 |
radius: 22 |
||||||
height: 44 |
height: 44 |
||||||
width: 44 |
width: 44 |
||||||
Image { |
|
||||||
id: img |
Image { |
||||||
anchors.centerIn: parent |
id: img |
||||||
|
|
||||||
source: "qrc:/icons/icons/ui/arrow-pointing-down.png" |
anchors.centerIn: parent |
||||||
fillMode: Image.Pad |
source: "qrc:/icons/icons/ui/arrow-pointing-down.png" |
||||||
|
fillMode: Image.Pad |
||||||
} |
} |
||||||
MouseArea { |
|
||||||
anchors.fill: parent |
MouseArea { |
||||||
onClicked: TimelineManager.timeline.saveMedia(model.data.id) |
anchors.fill: parent |
||||||
cursorShape: Qt.PointingHandCursor |
onClicked: TimelineManager.timeline.saveMedia(model.data.id) |
||||||
} |
cursorShape: Qt.PointingHandCursor |
||||||
} |
} |
||||||
ColumnLayout { |
|
||||||
id: col |
} |
||||||
|
|
||||||
Text { |
ColumnLayout { |
||||||
id: filename |
id: col |
||||||
Layout.fillWidth: true |
|
||||||
text: model.data.filename |
Text { |
||||||
textFormat: Text.PlainText |
id: filename |
||||||
elide: Text.ElideRight |
|
||||||
color: colors.text |
Layout.fillWidth: true |
||||||
} |
text: model.data.filename |
||||||
Text { |
textFormat: Text.PlainText |
||||||
id: filesize |
elide: Text.ElideRight |
||||||
Layout.fillWidth: true |
color: colors.text |
||||||
text: model.data.filesize |
} |
||||||
textFormat: Text.PlainText |
|
||||||
elide: Text.ElideRight |
Text { |
||||||
color: colors.text |
id: filesize |
||||||
} |
|
||||||
} |
Layout.fillWidth: true |
||||||
} |
text: model.data.filesize |
||||||
|
textFormat: Text.PlainText |
||||||
Rectangle { |
elide: Text.ElideRight |
||||||
color: colors.dark |
color: colors.text |
||||||
z: -1 |
} |
||||||
radius: 10 |
|
||||||
height: row.height + 24 |
} |
||||||
width: 44 + 24 + 24 + Math.max(Math.min(filesize.width, filesize.implicitWidth), Math.min(filename.width, filename.implicitWidth)) |
|
||||||
} |
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
color: colors.dark |
||||||
|
z: -1 |
||||||
|
radius: 10 |
||||||
|
height: row.height + 24 |
||||||
|
width: 44 + 24 + 24 + Math.max(Math.min(filesize.width, filesize.implicitWidth), Math.min(filename.width, filename.implicitWidth)) |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,42 +1,41 @@ |
|||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Item { |
Item { |
||||||
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? parent.width : model.data.width) |
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? parent.width : model.data.width) |
||||||
property double tempHeight: tempWidth * model.data.proportionalHeight |
property double tempHeight: tempWidth * model.data.proportionalHeight |
||||||
|
property double divisor: model.isReply ? 4 : 2 |
||||||
property double divisor: model.isReply ? 4 : 2 |
property bool tooHigh: tempHeight > timelineRoot.height / divisor |
||||||
property bool tooHigh: tempHeight > timelineRoot.height / divisor |
|
||||||
|
height: Math.round(tooHigh ? timelineRoot.height / divisor : tempHeight) |
||||||
height: Math.round(tooHigh ? timelineRoot.height / divisor : tempHeight) |
width: Math.round(tooHigh ? (timelineRoot.height / divisor) / model.data.proportionalHeight : tempWidth) |
||||||
width: Math.round(tooHigh ? (timelineRoot.height / divisor) / model.data.proportionalHeight : tempWidth) |
|
||||||
|
Image { |
||||||
Image { |
id: blurhash |
||||||
id: blurhash |
|
||||||
anchors.fill: parent |
anchors.fill: parent |
||||||
visible: img.status != Image.Ready |
visible: img.status != Image.Ready |
||||||
|
source: model.data.blurhash ? ("image://blurhash/" + model.data.blurhash) : ("image://colorimage/:/icons/icons/ui/do-not-disturb-rounded-sign@2x.png?" + colors.buttonText) |
||||||
source: model.data.blurhash ? ("image://blurhash/" + model.data.blurhash) : ("image://colorimage/:/icons/icons/ui/do-not-disturb-rounded-sign@2x.png?"+colors.buttonText) |
asynchronous: true |
||||||
asynchronous: true |
fillMode: Image.PreserveAspectFit |
||||||
fillMode: Image.PreserveAspectFit |
sourceSize.width: parent.width |
||||||
|
sourceSize.height: parent.height |
||||||
sourceSize.width: parent.width |
} |
||||||
sourceSize.height: parent.height |
|
||||||
} |
Image { |
||||||
|
id: img |
||||||
Image { |
|
||||||
id: img |
anchors.fill: parent |
||||||
anchors.fill: parent |
source: model.data.url.replace("mxc://", "image://MxcImage/") |
||||||
|
asynchronous: true |
||||||
source: model.data.url.replace("mxc://", "image://MxcImage/") |
fillMode: Image.PreserveAspectFit |
||||||
asynchronous: true |
|
||||||
fillMode: Image.PreserveAspectFit |
MouseArea { |
||||||
|
enabled: model.data.type == MtxEvent.ImageMessage && img.status == Image.Ready |
||||||
MouseArea { |
anchors.fill: parent |
||||||
enabled: model.data.type == MtxEvent.ImageMessage && img.status == Image.Ready |
onClicked: TimelineManager.openImageOverlay(model.data.url, model.data.id) |
||||||
anchors.fill: parent |
} |
||||||
onClicked: TimelineManager.openImageOverlay(model.data.url, model.data.id) |
|
||||||
} |
} |
||||||
} |
|
||||||
} |
} |
||||||
|
@ -1,6 +1,6 @@ |
|||||||
TextMessage { |
TextMessage { |
||||||
font.italic: true |
font.italic: true |
||||||
color: colors.buttonText |
color: colors.buttonText |
||||||
height: isReply ? Math.min(chat.height / 8, implicitHeight) : undefined |
height: isReply ? Math.min(chat.height / 8, implicitHeight) : undefined |
||||||
clip: true |
clip: true |
||||||
} |
} |
||||||
|
@ -1,7 +1,7 @@ |
|||||||
import ".." |
import ".." |
||||||
|
|
||||||
MatrixText { |
MatrixText { |
||||||
text: qsTr("unimplemented event: ") + model.data.typeString |
text: qsTr("unimplemented event: ") + model.data.typeString |
||||||
width: parent ? parent.width : undefined |
width: parent ? parent.width : undefined |
||||||
color: inactiveColors.text |
color: inactiveColors.text |
||||||
} |
} |
||||||
|
@ -1,173 +1,216 @@ |
|||||||
|
import QtMultimedia 5.6 |
||||||
import QtQuick 2.6 |
import QtQuick 2.6 |
||||||
import QtQuick.Layouts 1.2 |
|
||||||
import QtQuick.Controls 2.1 |
import QtQuick.Controls 2.1 |
||||||
import QtMultimedia 5.6 |
import QtQuick.Layouts 1.2 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Rectangle { |
Rectangle { |
||||||
id: bg |
id: bg |
||||||
radius: 10 |
|
||||||
color: colors.dark |
|
||||||
height: Math.round(content.height + 24) |
|
||||||
width: parent ? parent.width : undefined |
|
||||||
|
|
||||||
Column { |
|
||||||
id: content |
|
||||||
width: parent.width - 24 |
|
||||||
anchors.centerIn: parent |
|
||||||
|
|
||||||
Rectangle { |
|
||||||
id: videoContainer |
|
||||||
visible: model.data.type == MtxEvent.VideoMessage |
|
||||||
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? 400 : model.data.width) |
|
||||||
property double tempHeight: tempWidth * model.data.proportionalHeight |
|
||||||
|
|
||||||
property double divisor: model.isReply ? 4 : 2 |
|
||||||
property bool tooHigh: tempHeight > timelineRoot.height / divisor |
|
||||||
|
|
||||||
height: tooHigh ? timelineRoot.height / divisor : tempHeight |
|
||||||
width: tooHigh ? (timelineRoot.height / divisor) / model.data.proportionalHeight : tempWidth |
|
||||||
Image { |
|
||||||
anchors.fill: parent |
|
||||||
source: model.data.thumbnailUrl.replace("mxc://", "image://MxcImage/") |
|
||||||
asynchronous: true |
|
||||||
fillMode: Image.PreserveAspectFit |
|
||||||
|
|
||||||
VideoOutput { |
|
||||||
anchors.fill: parent |
|
||||||
fillMode: VideoOutput.PreserveAspectFit |
|
||||||
source: media |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RowLayout { |
|
||||||
width: parent.width |
|
||||||
Text { |
|
||||||
id: positionText |
|
||||||
text: "--:--:--" |
|
||||||
color: colors.text |
|
||||||
} |
|
||||||
Slider { |
|
||||||
Layout.fillWidth: true |
|
||||||
id: progress |
|
||||||
value: media.position |
|
||||||
from: 0 |
|
||||||
to: media.duration |
|
||||||
|
|
||||||
onMoved: media.seek(value) |
|
||||||
//indeterminate: true |
|
||||||
function updatePositionTexts() { |
|
||||||
function formatTime(date) { |
|
||||||
var hh = date.getUTCHours(); |
|
||||||
var mm = date.getUTCMinutes(); |
|
||||||
var ss = date.getSeconds(); |
|
||||||
if (hh < 10) {hh = "0"+hh;} |
|
||||||
if (mm < 10) {mm = "0"+mm;} |
|
||||||
if (ss < 10) {ss = "0"+ss;} |
|
||||||
return hh+":"+mm+":"+ss; |
|
||||||
} |
|
||||||
positionText.text = formatTime(new Date(media.position)) |
|
||||||
durationText.text = formatTime(new Date(media.duration)) |
|
||||||
} |
|
||||||
onValueChanged: updatePositionTexts() |
|
||||||
|
|
||||||
palette: colors |
|
||||||
} |
|
||||||
Text { |
|
||||||
id: durationText |
|
||||||
text: "--:--:--" |
|
||||||
color: colors.text |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
RowLayout { |
|
||||||
width: parent.width |
|
||||||
|
|
||||||
spacing: 15 |
|
||||||
|
|
||||||
Rectangle { |
|
||||||
id: button |
|
||||||
color: colors.window |
|
||||||
radius: 22 |
|
||||||
height: 44 |
|
||||||
width: 44 |
|
||||||
Image { |
|
||||||
id: img |
|
||||||
anchors.centerIn: parent |
|
||||||
z: 3 |
|
||||||
|
|
||||||
source: "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?"+colors.text |
|
||||||
fillMode: Image.Pad |
|
||||||
|
|
||||||
} |
|
||||||
MouseArea { |
|
||||||
anchors.fill: parent |
|
||||||
onClicked: { |
|
||||||
switch (button.state) { |
|
||||||
case "": TimelineManager.timeline.cacheMedia(model.data.id); break; |
|
||||||
case "stopped": |
|
||||||
media.play(); console.log("play"); |
|
||||||
button.state = "playing" |
|
||||||
break |
|
||||||
case "playing": |
|
||||||
media.pause(); console.log("pause"); |
|
||||||
button.state = "stopped" |
|
||||||
break |
|
||||||
} |
|
||||||
} |
|
||||||
cursorShape: Qt.PointingHandCursor |
|
||||||
} |
|
||||||
MediaPlayer { |
|
||||||
id: media |
|
||||||
onError: console.log(errorString) |
|
||||||
onStatusChanged: if(status == MediaPlayer.Loaded) progress.updatePositionTexts() |
|
||||||
onStopped: button.state = "stopped" |
|
||||||
} |
|
||||||
|
|
||||||
Connections { |
|
||||||
target: TimelineManager.timeline |
|
||||||
onMediaCached: { |
|
||||||
if (mxcUrl == model.data.url) { |
|
||||||
media.source = "file://" + cacheUrl |
|
||||||
button.state = "stopped" |
|
||||||
console.log("media loaded: " + mxcUrl + " at " + cacheUrl) |
|
||||||
} |
|
||||||
console.log("media cached: " + mxcUrl + " at " + cacheUrl) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
states: [ |
|
||||||
State { |
|
||||||
name: "stopped" |
|
||||||
PropertyChanges { target: img; source: "image://colorimage/:/icons/icons/ui/play-sign.png?"+colors.text } |
|
||||||
}, |
|
||||||
State { |
|
||||||
name: "playing" |
|
||||||
PropertyChanges { target: img; source: "image://colorimage/:/icons/icons/ui/pause-symbol.png?"+colors.text } |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
ColumnLayout { |
|
||||||
id: col |
|
||||||
|
|
||||||
Text { |
|
||||||
Layout.fillWidth: true |
|
||||||
text: model.data.body |
|
||||||
textFormat: Text.PlainText |
|
||||||
elide: Text.ElideRight |
|
||||||
color: colors.text |
|
||||||
} |
|
||||||
Text { |
|
||||||
Layout.fillWidth: true |
|
||||||
text: model.data.filesize |
|
||||||
textFormat: Text.PlainText |
|
||||||
elide: Text.ElideRight |
|
||||||
color: colors.text |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
radius: 10 |
||||||
|
color: colors.dark |
||||||
|
height: Math.round(content.height + 24) |
||||||
|
width: parent ? parent.width : undefined |
||||||
|
|
||||||
|
Column { |
||||||
|
id: content |
||||||
|
|
||||||
|
width: parent.width - 24 |
||||||
|
anchors.centerIn: parent |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: videoContainer |
||||||
|
|
||||||
|
property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? 400 : model.data.width) |
||||||
|
property double tempHeight: tempWidth * model.data.proportionalHeight |
||||||
|
property double divisor: model.isReply ? 4 : 2 |
||||||
|
property bool tooHigh: tempHeight > timelineRoot.height / divisor |
||||||
|
|
||||||
|
visible: model.data.type == MtxEvent.VideoMessage |
||||||
|
height: tooHigh ? timelineRoot.height / divisor : tempHeight |
||||||
|
width: tooHigh ? (timelineRoot.height / divisor) / model.data.proportionalHeight : tempWidth |
||||||
|
|
||||||
|
Image { |
||||||
|
anchors.fill: parent |
||||||
|
source: model.data.thumbnailUrl.replace("mxc://", "image://MxcImage/") |
||||||
|
asynchronous: true |
||||||
|
fillMode: Image.PreserveAspectFit |
||||||
|
|
||||||
|
VideoOutput { |
||||||
|
anchors.fill: parent |
||||||
|
fillMode: VideoOutput.PreserveAspectFit |
||||||
|
source: media |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
width: parent.width |
||||||
|
|
||||||
|
Text { |
||||||
|
id: positionText |
||||||
|
|
||||||
|
text: "--:--:--" |
||||||
|
color: colors.text |
||||||
|
} |
||||||
|
|
||||||
|
Slider { |
||||||
|
id: progress |
||||||
|
|
||||||
|
//indeterminate: true |
||||||
|
function updatePositionTexts() { |
||||||
|
function formatTime(date) { |
||||||
|
var hh = date.getUTCHours(); |
||||||
|
var mm = date.getUTCMinutes(); |
||||||
|
var ss = date.getSeconds(); |
||||||
|
if (hh < 10) |
||||||
|
hh = "0" + hh; |
||||||
|
|
||||||
|
if (mm < 10) |
||||||
|
mm = "0" + mm; |
||||||
|
|
||||||
|
if (ss < 10) |
||||||
|
ss = "0" + ss; |
||||||
|
|
||||||
|
return hh + ":" + mm + ":" + ss; |
||||||
|
} |
||||||
|
|
||||||
|
positionText.text = formatTime(new Date(media.position)); |
||||||
|
durationText.text = formatTime(new Date(media.duration)); |
||||||
|
} |
||||||
|
|
||||||
|
Layout.fillWidth: true |
||||||
|
value: media.position |
||||||
|
from: 0 |
||||||
|
to: media.duration |
||||||
|
onMoved: media.seek(value) |
||||||
|
onValueChanged: updatePositionTexts() |
||||||
|
palette: colors |
||||||
|
} |
||||||
|
|
||||||
|
Text { |
||||||
|
id: durationText |
||||||
|
|
||||||
|
text: "--:--:--" |
||||||
|
color: colors.text |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
RowLayout { |
||||||
|
width: parent.width |
||||||
|
spacing: 15 |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: button |
||||||
|
|
||||||
|
color: colors.window |
||||||
|
radius: 22 |
||||||
|
height: 44 |
||||||
|
width: 44 |
||||||
|
states: [ |
||||||
|
State { |
||||||
|
name: "stopped" |
||||||
|
|
||||||
|
PropertyChanges { |
||||||
|
target: img |
||||||
|
source: "image://colorimage/:/icons/icons/ui/play-sign.png?" + colors.text |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "playing" |
||||||
|
|
||||||
|
PropertyChanges { |
||||||
|
target: img |
||||||
|
source: "image://colorimage/:/icons/icons/ui/pause-symbol.png?" + colors.text |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
] |
||||||
|
|
||||||
|
Image { |
||||||
|
id: img |
||||||
|
|
||||||
|
anchors.centerIn: parent |
||||||
|
z: 3 |
||||||
|
source: "image://colorimage/:/icons/icons/ui/arrow-pointing-down.png?" + colors.text |
||||||
|
fillMode: Image.Pad |
||||||
|
} |
||||||
|
|
||||||
|
MouseArea { |
||||||
|
anchors.fill: parent |
||||||
|
onClicked: { |
||||||
|
switch (button.state) { |
||||||
|
case "": |
||||||
|
TimelineManager.timeline.cacheMedia(model.data.id); |
||||||
|
break; |
||||||
|
case "stopped": |
||||||
|
media.play(); |
||||||
|
console.log("play"); |
||||||
|
button.state = "playing"; |
||||||
|
break; |
||||||
|
case "playing": |
||||||
|
media.pause(); |
||||||
|
console.log("pause"); |
||||||
|
button.state = "stopped"; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
cursorShape: Qt.PointingHandCursor |
||||||
|
} |
||||||
|
|
||||||
|
MediaPlayer { |
||||||
|
id: media |
||||||
|
|
||||||
|
onError: console.log(errorString) |
||||||
|
onStatusChanged: { |
||||||
|
if (status == MediaPlayer.Loaded) |
||||||
|
progress.updatePositionTexts(); |
||||||
|
|
||||||
|
} |
||||||
|
onStopped: button.state = "stopped" |
||||||
|
} |
||||||
|
|
||||||
|
Connections { |
||||||
|
target: TimelineManager.timeline |
||||||
|
onMediaCached: { |
||||||
|
if (mxcUrl == model.data.url) { |
||||||
|
media.source = "file://" + cacheUrl; |
||||||
|
button.state = "stopped"; |
||||||
|
console.log("media loaded: " + mxcUrl + " at " + cacheUrl); |
||||||
|
} |
||||||
|
console.log("media cached: " + mxcUrl + " at " + cacheUrl); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
ColumnLayout { |
||||||
|
id: col |
||||||
|
|
||||||
|
Text { |
||||||
|
Layout.fillWidth: true |
||||||
|
text: model.data.body |
||||||
|
textFormat: Text.PlainText |
||||||
|
elide: Text.ElideRight |
||||||
|
color: colors.text |
||||||
|
} |
||||||
|
|
||||||
|
Text { |
||||||
|
Layout.fillWidth: true |
||||||
|
text: model.data.filesize |
||||||
|
textFormat: Text.PlainText |
||||||
|
elide: Text.ElideRight |
||||||
|
color: colors.text |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
@ -1,12 +1,12 @@ |
|||||||
import ".." |
import ".." |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
MatrixText { |
MatrixText { |
||||||
property string formatted: model.data.formattedBody |
property string formatted: model.data.formattedBody |
||||||
text: "<style type=\"text/css\">a { color:"+colors.link+";}</style>" + formatted.replace("<pre>", "<pre style='white-space: pre-wrap'>") |
|
||||||
width: parent ? parent.width : undefined |
text: "<style type=\"text/css\">a { color:" + colors.link + ";}</style>" + formatted.replace("<pre>", "<pre style='white-space: pre-wrap'>") |
||||||
height: isReply ? Math.round(Math.min(timelineRoot.height / 8, implicitHeight)) : undefined |
width: parent ? parent.width : undefined |
||||||
clip: true |
height: isReply ? Math.round(Math.min(timelineRoot.height / 8, implicitHeight)) : undefined |
||||||
font.pointSize: (Settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize |
clip: true |
||||||
|
font.pointSize: (Settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize |
||||||
} |
} |
||||||
|
@ -1,39 +1,46 @@ |
|||||||
import QtQuick 2.3 |
import QtQuick 2.3 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Layouts 1.10 |
import QtQuick.Layouts 1.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Pane { |
Pane { |
||||||
property string title: qsTr("Awaiting Confirmation") |
property string title: qsTr("Awaiting Confirmation") |
||||||
ColumnLayout { |
|
||||||
spacing: 16 |
ColumnLayout { |
||||||
Label { |
spacing: 16 |
||||||
Layout.maximumWidth: 400 |
|
||||||
Layout.fillHeight: true |
Label { |
||||||
Layout.fillWidth: true |
id: content |
||||||
wrapMode: Text.Wrap |
|
||||||
id: content |
Layout.maximumWidth: 400 |
||||||
text: qsTr("Waiting for other side to complete verification.") |
Layout.fillHeight: true |
||||||
color:colors.text |
Layout.fillWidth: true |
||||||
verticalAlignment: Text.AlignVCenter |
wrapMode: Text.Wrap |
||||||
} |
text: qsTr("Waiting for other side to complete verification.") |
||||||
BusyIndicator { |
color: colors.text |
||||||
Layout.alignment: Qt.AlignHCenter |
verticalAlignment: Text.AlignVCenter |
||||||
} |
} |
||||||
RowLayout { |
|
||||||
Button { |
BusyIndicator { |
||||||
Layout.alignment: Qt.AlignLeft |
Layout.alignment: Qt.AlignHCenter |
||||||
text: qsTr("Cancel") |
} |
||||||
|
|
||||||
onClicked: { |
RowLayout { |
||||||
flow.cancel(); |
Button { |
||||||
dialog.close(); |
Layout.alignment: Qt.AlignLeft |
||||||
} |
text: qsTr("Cancel") |
||||||
} |
onClicked: { |
||||||
Item { |
flow.cancel(); |
||||||
Layout.fillWidth: true |
dialog.close(); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
|
||||||
|
Item { |
||||||
|
Layout.fillWidth: true |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,97 +1,144 @@ |
|||||||
import QtQuick 2.10 |
import QtQuick 2.10 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Window 2.10 |
import QtQuick.Window 2.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
ApplicationWindow { |
ApplicationWindow { |
||||||
property var flow |
id: dialog |
||||||
|
|
||||||
onClosing: TimelineManager.removeVerificationFlow(flow) |
property var flow |
||||||
|
|
||||||
title: stack.currentItem.title |
onClosing: TimelineManager.removeVerificationFlow(flow) |
||||||
id: dialog |
title: stack.currentItem.title |
||||||
|
flags: Qt.Dialog |
||||||
flags: Qt.Dialog |
palette: colors |
||||||
|
height: stack.implicitHeight |
||||||
palette: colors |
width: stack.implicitWidth |
||||||
|
|
||||||
height: stack.implicitHeight |
StackView { |
||||||
width: stack.implicitWidth |
id: stack |
||||||
|
|
||||||
StackView { |
initialItem: newVerificationRequest |
||||||
id: stack |
implicitWidth: currentItem.implicitWidth |
||||||
initialItem: newVerificationRequest |
implicitHeight: currentItem.implicitHeight |
||||||
implicitWidth: currentItem.implicitWidth |
} |
||||||
implicitHeight: currentItem.implicitHeight |
|
||||||
} |
Component { |
||||||
|
id: newVerificationRequest |
||||||
Component{ |
|
||||||
id: newVerificationRequest |
NewVerificationRequest { |
||||||
NewVerificationRequest {} |
} |
||||||
} |
|
||||||
|
} |
||||||
Component { |
|
||||||
id: waiting |
Component { |
||||||
Waiting {} |
id: waiting |
||||||
} |
|
||||||
|
Waiting { |
||||||
Component { |
} |
||||||
id: success |
|
||||||
Success {} |
} |
||||||
} |
|
||||||
|
Component { |
||||||
Component { |
id: success |
||||||
id: failed |
|
||||||
Failed {} |
Success { |
||||||
} |
} |
||||||
|
|
||||||
Component { |
} |
||||||
id: digitVerification |
|
||||||
DigitVerification {} |
Component { |
||||||
} |
id: failed |
||||||
|
|
||||||
Component { |
Failed { |
||||||
id: emojiVerification |
} |
||||||
EmojiVerification {} |
|
||||||
} |
} |
||||||
|
|
||||||
Item { |
Component { |
||||||
state: flow.state |
id: digitVerification |
||||||
|
|
||||||
states: [ |
DigitVerification { |
||||||
State { |
} |
||||||
name: "PromptStartVerification" |
|
||||||
StateChangeScript { script: stack.replace(newVerificationRequest) } |
} |
||||||
}, |
|
||||||
State { |
Component { |
||||||
name: "CompareEmoji" |
id: emojiVerification |
||||||
StateChangeScript { script: stack.replace(emojiVerification) } |
|
||||||
}, |
EmojiVerification { |
||||||
State { |
} |
||||||
name: "CompareNumber" |
|
||||||
StateChangeScript { script: stack.replace(digitVerification) } |
} |
||||||
}, |
|
||||||
State { |
Item { |
||||||
name: "WaitingForKeys" |
state: flow.state |
||||||
StateChangeScript { script: stack.replace(waiting) } |
states: [ |
||||||
}, |
State { |
||||||
State { |
name: "PromptStartVerification" |
||||||
name: "WaitingForOtherToAccept" |
|
||||||
StateChangeScript { script: stack.replace(waiting) } |
StateChangeScript { |
||||||
}, |
script: stack.replace(newVerificationRequest) |
||||||
State { |
} |
||||||
name: "WaitingForMac" |
|
||||||
StateChangeScript { script: stack.replace(waiting) } |
}, |
||||||
}, |
State { |
||||||
State { |
name: "CompareEmoji" |
||||||
name: "Success" |
|
||||||
StateChangeScript { script: stack.replace(success) } |
StateChangeScript { |
||||||
}, |
script: stack.replace(emojiVerification) |
||||||
State { |
} |
||||||
name: "Failed" |
|
||||||
StateChangeScript { script: stack.replace(failed); } |
}, |
||||||
} |
State { |
||||||
] |
name: "CompareNumber" |
||||||
} |
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(digitVerification) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "WaitingForKeys" |
||||||
|
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(waiting) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "WaitingForOtherToAccept" |
||||||
|
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(waiting) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "WaitingForMac" |
||||||
|
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(waiting) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "Success" |
||||||
|
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(success) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
State { |
||||||
|
name: "Failed" |
||||||
|
|
||||||
|
StateChangeScript { |
||||||
|
script: stack.replace(failed) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,60 +1,69 @@ |
|||||||
import QtQuick 2.3 |
import QtQuick 2.3 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Layouts 1.10 |
import QtQuick.Layouts 1.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Pane { |
Pane { |
||||||
property string title: qsTr("Verification Code") |
property string title: qsTr("Verification Code") |
||||||
|
|
||||||
ColumnLayout { |
ColumnLayout { |
||||||
spacing: 16 |
spacing: 16 |
||||||
Label { |
|
||||||
Layout.maximumWidth: 400 |
Label { |
||||||
Layout.fillHeight: true |
Layout.maximumWidth: 400 |
||||||
Layout.fillWidth: true |
Layout.fillHeight: true |
||||||
wrapMode: Text.Wrap |
Layout.fillWidth: true |
||||||
text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!") |
wrapMode: Text.Wrap |
||||||
color:colors.text |
text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!") |
||||||
verticalAlignment: Text.AlignVCenter |
color: colors.text |
||||||
} |
verticalAlignment: Text.AlignVCenter |
||||||
RowLayout { |
} |
||||||
Layout.alignment: Qt.AlignHCenter |
|
||||||
Label { |
RowLayout { |
||||||
font.pixelSize: Qt.application.font.pixelSize * 2 |
Layout.alignment: Qt.AlignHCenter |
||||||
text: flow.sasList[0] |
|
||||||
color:colors.text |
Label { |
||||||
} |
font.pixelSize: Qt.application.font.pixelSize * 2 |
||||||
Label { |
text: flow.sasList[0] |
||||||
font.pixelSize: Qt.application.font.pixelSize * 2 |
color: colors.text |
||||||
text: flow.sasList[1] |
} |
||||||
color:colors.text |
|
||||||
} |
Label { |
||||||
Label { |
font.pixelSize: Qt.application.font.pixelSize * 2 |
||||||
font.pixelSize: Qt.application.font.pixelSize * 2 |
text: flow.sasList[1] |
||||||
text: flow.sasList[2] |
color: colors.text |
||||||
color:colors.text |
} |
||||||
} |
|
||||||
} |
Label { |
||||||
RowLayout { |
font.pixelSize: Qt.application.font.pixelSize * 2 |
||||||
Button { |
text: flow.sasList[2] |
||||||
Layout.alignment: Qt.AlignLeft |
color: colors.text |
||||||
text: qsTr("They do not match!") |
} |
||||||
|
|
||||||
onClicked: { |
} |
||||||
flow.cancel(); |
|
||||||
dialog.close(); |
RowLayout { |
||||||
} |
Button { |
||||||
} |
Layout.alignment: Qt.AlignLeft |
||||||
Item { |
text: qsTr("They do not match!") |
||||||
Layout.fillWidth: true |
onClicked: { |
||||||
} |
flow.cancel(); |
||||||
Button { |
dialog.close(); |
||||||
Layout.alignment: Qt.AlignRight |
} |
||||||
text: qsTr("They match!") |
} |
||||||
|
|
||||||
onClicked: flow.next(); |
Item { |
||||||
} |
Layout.fillWidth: true |
||||||
} |
} |
||||||
} |
|
||||||
|
Button { |
||||||
|
Layout.alignment: Qt.AlignRight |
||||||
|
text: qsTr("They match!") |
||||||
|
onClicked: flow.next() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,44 +1,56 @@ |
|||||||
import QtQuick 2.3 |
import QtQuick 2.3 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Layouts 1.10 |
import QtQuick.Layouts 1.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Pane { |
Pane { |
||||||
property string title: qsTr("Verification failed") |
property string title: qsTr("Verification failed") |
||||||
ColumnLayout { |
|
||||||
spacing: 16 |
ColumnLayout { |
||||||
Text { |
spacing: 16 |
||||||
id: content |
|
||||||
|
Text { |
||||||
Layout.maximumWidth: 400 |
id: content |
||||||
Layout.fillHeight: true |
|
||||||
Layout.fillWidth: true |
Layout.maximumWidth: 400 |
||||||
|
Layout.fillHeight: true |
||||||
wrapMode: Text.Wrap |
Layout.fillWidth: true |
||||||
text: switch (flow.error) { |
wrapMode: Text.Wrap |
||||||
case DeviceVerificationFlow.UnknownMethod: return qsTr("Other client does not support our verification protocol.") |
text: { |
||||||
case DeviceVerificationFlow.MismatchedCommitment: |
switch (flow.error) { |
||||||
case DeviceVerificationFlow.MismatchedSAS: |
case DeviceVerificationFlow.UnknownMethod: |
||||||
case DeviceVerificationFlow.KeyMismatch: return qsTr("Key mismatch detected!") |
return qsTr("Other client does not support our verification protocol."); |
||||||
case DeviceVerificationFlow.Timeout: return qsTr("Device verification timed out.") |
case DeviceVerificationFlow.MismatchedCommitment: |
||||||
case DeviceVerificationFlow.User: return qsTr("Other party canceled the verification.") |
case DeviceVerificationFlow.MismatchedSAS: |
||||||
case DeviceVerificationFlow.OutOfOrder: return qsTr("Device verification timed out.") |
case DeviceVerificationFlow.KeyMismatch: |
||||||
default: return "Unknown verification error."; |
return qsTr("Key mismatch detected!"); |
||||||
} |
case DeviceVerificationFlow.Timeout: |
||||||
color:colors.text |
return qsTr("Device verification timed out."); |
||||||
verticalAlignment: Text.AlignVCenter |
case DeviceVerificationFlow.User: |
||||||
} |
return qsTr("Other party canceled the verification."); |
||||||
RowLayout { |
case DeviceVerificationFlow.OutOfOrder: |
||||||
Item { |
return qsTr("Device verification timed out."); |
||||||
Layout.fillWidth: true |
default: |
||||||
} |
return "Unknown verification error."; |
||||||
Button { |
} |
||||||
Layout.alignment: Qt.AlignRight |
} |
||||||
text: qsTr("Close") |
color: colors.text |
||||||
|
verticalAlignment: Text.AlignVCenter |
||||||
onClicked: dialog.close() |
} |
||||||
} |
|
||||||
} |
RowLayout { |
||||||
} |
Item { |
||||||
|
Layout.fillWidth: true |
||||||
|
} |
||||||
|
|
||||||
|
Button { |
||||||
|
Layout.alignment: Qt.AlignRight |
||||||
|
text: qsTr("Close") |
||||||
|
onClicked: dialog.close() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,44 +1,46 @@ |
|||||||
import QtQuick 2.3 |
import QtQuick 2.3 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Layouts 1.10 |
import QtQuick.Layouts 1.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Pane { |
Pane { |
||||||
property string title: flow.sender ? qsTr("Send Device Verification Request") : qsTr("Recieved Device Verification Request") |
property string title: flow.sender ? qsTr("Send Device Verification Request") : qsTr("Recieved Device Verification Request") |
||||||
|
|
||||||
ColumnLayout { |
ColumnLayout { |
||||||
spacing: 16 |
spacing: 16 |
||||||
Label { |
|
||||||
Layout.maximumWidth: 400 |
Label { |
||||||
Layout.fillHeight: true |
Layout.maximumWidth: 400 |
||||||
Layout.fillWidth: true |
Layout.fillHeight: true |
||||||
wrapMode: Text.Wrap |
Layout.fillWidth: true |
||||||
text: flow.sender ? |
wrapMode: Text.Wrap |
||||||
qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.") |
text: flow.sender ? qsTr("To ensure that no malicious user can eavesdrop on your encrypted communications, you can verify this device.") : qsTr("The device was requested to be verified") |
||||||
: qsTr("The device was requested to be verified") |
color: colors.text |
||||||
color:colors.text |
verticalAlignment: Text.AlignVCenter |
||||||
verticalAlignment: Text.AlignVCenter |
} |
||||||
} |
|
||||||
RowLayout { |
RowLayout { |
||||||
Button { |
Button { |
||||||
Layout.alignment: Qt.AlignLeft |
Layout.alignment: Qt.AlignLeft |
||||||
text: flow.sender ? qsTr("Cancel") : qsTr("Deny") |
text: flow.sender ? qsTr("Cancel") : qsTr("Deny") |
||||||
|
onClicked: { |
||||||
onClicked: { |
flow.cancel(); |
||||||
flow.cancel(); |
dialog.close(); |
||||||
dialog.close(); |
} |
||||||
} |
} |
||||||
} |
|
||||||
Item { |
Item { |
||||||
Layout.fillWidth: true |
Layout.fillWidth: true |
||||||
} |
} |
||||||
Button { |
|
||||||
Layout.alignment: Qt.AlignRight |
Button { |
||||||
text: flow.sender ? qsTr("Start verification") : qsTr("Accept") |
Layout.alignment: Qt.AlignRight |
||||||
|
text: flow.sender ? qsTr("Start verification") : qsTr("Accept") |
||||||
onClicked: flow.next(); |
onClicked: flow.next() |
||||||
} |
} |
||||||
} |
|
||||||
} |
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,45 +1,56 @@ |
|||||||
import QtQuick 2.3 |
import QtQuick 2.3 |
||||||
import QtQuick.Controls 2.10 |
import QtQuick.Controls 2.10 |
||||||
import QtQuick.Layouts 1.10 |
import QtQuick.Layouts 1.10 |
||||||
|
|
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
|
|
||||||
Pane { |
Pane { |
||||||
property string title: qsTr("Waiting for other party") |
property string title: qsTr("Waiting for other party") |
||||||
ColumnLayout { |
|
||||||
spacing: 16 |
ColumnLayout { |
||||||
Label { |
spacing: 16 |
||||||
Layout.maximumWidth: 400 |
|
||||||
Layout.fillHeight: true |
Label { |
||||||
Layout.fillWidth: true |
id: content |
||||||
wrapMode: Text.Wrap |
|
||||||
id: content |
Layout.maximumWidth: 400 |
||||||
text: switch (flow.state) { |
Layout.fillHeight: true |
||||||
case "WaitingForOtherToAccept": return qsTr("Waiting for other side to accept the verification request.") |
Layout.fillWidth: true |
||||||
case "WaitingForKeys": return qsTr("Waiting for other side to continue the verification request.") |
wrapMode: Text.Wrap |
||||||
case "WaitingForMac": return qsTr("Waiting for other side to complete the verification request.") |
text: { |
||||||
} |
switch (flow.state) { |
||||||
|
case "WaitingForOtherToAccept": |
||||||
color: colors.text |
return qsTr("Waiting for other side to accept the verification request."); |
||||||
verticalAlignment: Text.AlignVCenter |
case "WaitingForKeys": |
||||||
} |
return qsTr("Waiting for other side to continue the verification request."); |
||||||
BusyIndicator { |
case "WaitingForMac": |
||||||
Layout.alignment: Qt.AlignHCenter |
return qsTr("Waiting for other side to complete the verification request."); |
||||||
palette: colors |
} |
||||||
} |
} |
||||||
RowLayout { |
color: colors.text |
||||||
Button { |
verticalAlignment: Text.AlignVCenter |
||||||
Layout.alignment: Qt.AlignLeft |
} |
||||||
text: qsTr("Cancel") |
|
||||||
|
BusyIndicator { |
||||||
onClicked: { |
Layout.alignment: Qt.AlignHCenter |
||||||
flow.cancel(); |
palette: colors |
||||||
dialog.close(); |
} |
||||||
} |
|
||||||
} |
RowLayout { |
||||||
Item { |
Button { |
||||||
Layout.fillWidth: true |
Layout.alignment: Qt.AlignLeft |
||||||
} |
text: qsTr("Cancel") |
||||||
} |
onClicked: { |
||||||
} |
flow.cancel(); |
||||||
|
dialog.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Item { |
||||||
|
Layout.fillWidth: true |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
} |
} |
||||||
|
@ -1,17 +1,16 @@ |
|||||||
|
import "../" |
||||||
import QtQuick 2.10 |
import QtQuick 2.10 |
||||||
import QtQuick.Controls 2.1 |
import QtQuick.Controls 2.1 |
||||||
import im.nheko 1.0 |
import im.nheko 1.0 |
||||||
import im.nheko.EmojiModel 1.0 |
import im.nheko.EmojiModel 1.0 |
||||||
|
|
||||||
import "../" |
|
||||||
|
|
||||||
ImageButton { |
ImageButton { |
||||||
|
id: emojiButton |
||||||
|
|
||||||
property var colors: currentActivePalette |
property var colors: currentActivePalette |
||||||
property var emojiPicker |
property var emojiPicker |
||||||
property string event_id |
property string event_id |
||||||
|
|
||||||
image: ":/icons/icons/ui/smile.png" |
image: ":/icons/icons/ui/smile.png" |
||||||
id: emojiButton |
|
||||||
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, event_id) |
onClicked: emojiPicker.visible ? emojiPicker.close() : emojiPicker.show(emojiButton, event_id) |
||||||
|
|
||||||
} |
} |
||||||
|
Loading…
Reference in new issue