Add menu button in chat and remove trashcan

Add ephemeral messages to files
Fix call from encrypted chat room
This commit is contained in:
Julien Wadel 2021-08-19 19:16:55 +02:00
parent ba57fc7f51
commit ce9b2bf3b9
12 changed files with 493 additions and 113 deletions

View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="28"
height="28"
viewBox="0 0 28 28"
version="1.1"
id="svg32"
sodipodi:docname="chat_menu_normal.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview34"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="31.178571"
inkscape:cx="14"
inkscape:cy="14.016037"
inkscape:window-width="1920"
inkscape:window-height="1131"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg32" />
<defs
id="defs10">
<filter
id="ceccbcx0va"
width="1.2"
height="1.2"
x="-0.1"
y="-0.1"
filterUnits="objectBoundingBox">
<feOffset
in="SourceAlpha"
result="shadowOffsetOuter1"
id="feOffset2" />
<feGaussianBlur
in="shadowOffsetOuter1"
result="shadowBlurOuter1"
stdDeviation="1"
id="feGaussianBlur4" />
<feColorMatrix
in="shadowBlurOuter1"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.236309558 0"
id="feColorMatrix6" />
</filter>
<rect
id="694qr2vy9b"
width="24"
height="24"
x="0"
y="0"
rx="5" />
</defs>
<g
fill="none"
fill-rule="evenodd"
id="g30">
<g
id="g28">
<g
id="g26">
<g
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000)"
id="g16">
<use
fill="#000"
filter="url(#ceccbcx0va)"
xlink:href="#694qr2vy9b"
id="use12" />
<use
fill="#DEDEDE"
xlink:href="#694qr2vy9b"
id="use14" />
</g>
<g
fill="#595759"
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) rotate(90.000000) translate(-12.000000, -12.000000) translate(10.000000, 4.000000)"
id="g24">
<circle
cx="2"
cy="2"
r="2"
transform="translate(2.000000, 2.000000) rotate(90.000000) translate(-2.000000, -2.000000)"
id="circle18" />
<circle
cx="2"
cy="8"
r="2"
transform="translate(2.000000, 8.000000) rotate(90.000000) translate(-2.000000, -8.000000)"
id="circle20" />
<circle
cx="2"
cy="14"
r="2"
transform="translate(2.000000, 14.000000) rotate(90.000000) translate(-2.000000, -14.000000)"
id="circle22" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="28"
height="28"
viewBox="0 0 28 28"
version="1.1"
id="svg32"
sodipodi:docname="chat_menu_normal.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview34"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="31.178571"
inkscape:cx="14"
inkscape:cy="14.016037"
inkscape:window-width="1920"
inkscape:window-height="1131"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg32" />
<defs
id="defs10">
<filter
id="ceccbcx0va"
width="1.2"
height="1.2"
x="-0.1"
y="-0.1"
filterUnits="objectBoundingBox">
<feOffset
in="SourceAlpha"
result="shadowOffsetOuter1"
id="feOffset2" />
<feGaussianBlur
in="shadowOffsetOuter1"
result="shadowBlurOuter1"
stdDeviation="1"
id="feGaussianBlur4" />
<feColorMatrix
in="shadowBlurOuter1"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.236309558 0"
id="feColorMatrix6" />
</filter>
<rect
id="694qr2vy9b"
width="24"
height="24"
x="0"
y="0"
rx="5" />
</defs>
<g
fill="none"
fill-rule="evenodd"
id="g30">
<g
id="g28">
<g
id="g26">
<g
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000)"
id="g16">
<use
fill="#000"
filter="url(#ceccbcx0va)"
xlink:href="#694qr2vy9b"
id="use12" />
<use
fill="#DEDEDE"
xlink:href="#694qr2vy9b"
id="use14" />
</g>
<g
fill="#595759"
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) rotate(90.000000) translate(-12.000000, -12.000000) translate(10.000000, 4.000000)"
id="g24">
<circle
cx="2"
cy="2"
r="2"
transform="translate(2.000000, 2.000000) rotate(90.000000) translate(-2.000000, -2.000000)"
id="circle18" />
<circle
cx="2"
cy="8"
r="2"
transform="translate(2.000000, 8.000000) rotate(90.000000) translate(-2.000000, -8.000000)"
id="circle20" />
<circle
cx="2"
cy="14"
r="2"
transform="translate(2.000000, 14.000000) rotate(90.000000) translate(-2.000000, -14.000000)"
id="circle22" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="28"
height="28"
viewBox="0 0 28 28"
version="1.1"
id="svg32"
sodipodi:docname="chat_menu_hovered.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview34"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="31.178571"
inkscape:cx="14"
inkscape:cy="14.016037"
inkscape:window-width="1920"
inkscape:window-height="1131"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg32" />
<defs
id="defs10">
<filter
id="s47nlu1tya"
width="1.2"
height="1.2"
x="-0.1"
y="-0.1"
filterUnits="objectBoundingBox">
<feOffset
in="SourceAlpha"
result="shadowOffsetOuter1"
id="feOffset2" />
<feGaussianBlur
in="shadowOffsetOuter1"
result="shadowBlurOuter1"
stdDeviation="1"
id="feGaussianBlur4" />
<feColorMatrix
in="shadowBlurOuter1"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.236309558 0"
id="feColorMatrix6" />
</filter>
<rect
id="fewk321u5b"
width="24"
height="24"
x="0"
y="0"
rx="5" />
</defs>
<g
fill="none"
fill-rule="evenodd"
id="g30">
<g
id="g28">
<g
id="g26">
<g
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000)"
id="g16">
<use
fill="#000"
filter="url(#s47nlu1tya)"
xlink:href="#fewk321u5b"
id="use12" />
<use
fill="#A1A1A1"
xlink:href="#fewk321u5b"
id="use14" />
</g>
<g
fill="#595759"
transform="translate(-675.000000, -388.000000) translate(677.000000, 390.000000) translate(12.000000, 12.000000) rotate(90.000000) translate(-12.000000, -12.000000) translate(10.000000, 4.000000)"
id="g24">
<circle
cx="2"
cy="2"
r="2"
transform="translate(2.000000, 2.000000) rotate(90.000000) translate(-2.000000, -2.000000)"
id="circle18" />
<circle
cx="2"
cy="8"
r="2"
transform="translate(2.000000, 8.000000) rotate(90.000000) translate(-2.000000, -8.000000)"
id="circle20" />
<circle
cx="2"
cy="14"
r="2"
transform="translate(2.000000, 14.000000) rotate(90.000000) translate(-2.000000, -14.000000)"
id="circle22" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -66,6 +66,9 @@
<file>assets/images/chat_delivered.svg</file>
<file>assets/images/chat_error.svg</file>
<file>assets/images/chat_hovered.svg</file>
<file>assets/images/chat_menu_hovered.svg</file>
<file>assets/images/chat_menu_normal.svg</file>
<file>assets/images/chat_menu_pressed.svg</file>
<file>assets/images/chat_is_composing_0.svg</file>
<file>assets/images/chat_is_composing_1.svg</file>
<file>assets/images/chat_is_composing_2.svg</file>

View file

@ -23,8 +23,12 @@ Item {
property string content
property int deliveryCount : 0
signal deliveryStatusClecked()
signal deliveryStatusClicked()
signal removeEntryRequested()
function open(){
messageMenu.open()
}
Menu {
@ -61,7 +65,7 @@ Item {
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
visible: container.deliveryCount > 0
onTriggered: container.deliveryStatusClecked()
onTriggered: container.deliveryStatusClicked()
}
MenuItem {
//: 'Delete' : Item menu to delete a message
@ -83,6 +87,7 @@ Item {
// width: rectangle.width
acceptedButtons: Qt.RightButton
propagateComposedEvents:true
cursorShape: parent.hoveredLink
? Qt.PointingHandCursor
: Qt.IBeamCursor

View file

@ -8,80 +8,90 @@ import Utils 1.0
// =============================================================================
Row {
property string _type: {
var status = $chatEntry.state
if (status === ChatRoomModel.CallStatusSuccess) {
if (!$chatEntry.isStart) {
return 'ended_call'
}
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusDeclined) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
if (status === ChatRoomModel.CallStatusMissed) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatRoomModel.CallStatusAborted) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusEarlyAborted) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatRoomModel.CallStatusAcceptedElsewhere) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusDeclinedElsewhere) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
return 'unknown_call_event'
}
height: ChatStyle.entry.lineHeight
spacing: ChatStyle.entry.message.extraContent.spacing
Icon {
height: parent.height
icon: _type
iconSize: ChatStyle.entry.event.iconSize
width: ChatStyle.entry.metaWidth
}
Text {
Component {
// Never created.
// Private data for `lupdate`.
Item {
property var i18n: [
QT_TR_NOOP('declinedIncomingCall'),
QT_TR_NOOP('declinedOutgoingCall'),
QT_TR_NOOP('endedCall'),
QT_TR_NOOP('incomingCall'),
QT_TR_NOOP('missedIncomingCall'),
QT_TR_NOOP('missedOutgoingCall'),
QT_TR_NOOP('outgoingCall')
]
}
}
color: ChatStyle.entry.event.text.color
font {
bold: true
pointSize: ChatStyle.entry.event.text.pointSize
}
height: parent.height
text: qsTr(Utils.snakeToCamel(_type))
verticalAlignment: Text.AlignVCenter
}
ActionButton {
height: ChatStyle.entry.lineHeight
icon: 'delete'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: removeEntry()
}
property string _type: {
var status = $chatEntry.state
if (status === ChatRoomModel.CallStatusSuccess) {
if (!$chatEntry.isStart) {
return 'ended_call'
}
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusDeclined) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
if (status === ChatRoomModel.CallStatusMissed) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatRoomModel.CallStatusAborted) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusEarlyAborted) {
return $chatEntry.isOutgoing ? 'missed_outgoing_call' : 'missed_incoming_call'
}
if (status === ChatRoomModel.CallStatusAcceptedElsewhere) {
return $chatEntry.isOutgoing ? 'outgoing_call' : 'incoming_call'
}
if (status === ChatRoomModel.CallStatusDeclinedElsewhere) {
return $chatEntry.isOutgoing ? 'declined_outgoing_call' : 'declined_incoming_call'
}
return 'unknown_call_event'
}
height: ChatStyle.entry.lineHeight
spacing: ChatStyle.entry.message.extraContent.spacing
Icon {
height: parent.height
icon: _type
iconSize: ChatStyle.entry.event.iconSize
width: ChatStyle.entry.metaWidth
}
Text {
id:textArea
Component {
// Never created.
// Private data for `lupdate`.
Item {
property var i18n: [
QT_TR_NOOP('declinedIncomingCall'),
QT_TR_NOOP('declinedOutgoingCall'),
QT_TR_NOOP('endedCall'),
QT_TR_NOOP('incomingCall'),
QT_TR_NOOP('missedIncomingCall'),
QT_TR_NOOP('missedOutgoingCall'),
QT_TR_NOOP('outgoingCall')
]
}
}
color: ChatStyle.entry.event.text.color
font {
bold: true
pointSize: ChatStyle.entry.event.text.pointSize
}
height: parent.height
text: qsTr(Utils.snakeToCamel(_type))
verticalAlignment: Text.AlignVCenter
ChatMenu{
id:chatMenu
height: parent.height
width: textArea.width
deliveryCount: 0
onRemoveEntryRequested: removeEntry()
}
}
ActionButton {
height: ChatStyle.entry.lineHeight
icon: 'chat_menu'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: chatMenu.open()
}
}

View file

@ -8,6 +8,7 @@ import LinphoneUtils 1.0
import LinphoneEnums 1.0
import Linphone.Styles 1.0
import Utils 1.0
import Units 1.0
// =============================================================================
@ -253,6 +254,7 @@ Row {
}
Icon {
id:downloadButton
anchors {
bottom: parent.bottom
bottomMargin: ChatStyle.entry.message.file.margins
@ -262,7 +264,7 @@ Row {
icon: 'download'
iconSize: ChatStyle.entry.message.file.iconSize
visible: (rectangle.contentModel?!isOutgoing&& !rectangle.contentModel.wasDownloaded : false)
visible: (rectangle.contentModel?!isOutgoing && !rectangle.contentModel.wasDownloaded : false)
}
MouseArea {
@ -273,7 +275,7 @@ Row {
}
anchors.fill: parent
visible: ((rectangle.isUploaded || rectangle.isRead) && !isOutgoing) || isOutgoing
visible: downloadButton.visible || ((rectangle.isUploaded || rectangle.isRead) && !isOutgoing) || isOutgoing
onClicked: {
if (Utils.pointIsInItem(this, thumbnailProvider, mouse)) {
@ -294,9 +296,34 @@ Row {
width: rectangle.width
deliveryCount: deliveryLayout.model.count
onDeliveryStatusClecked: deliveryLayout.visible = !deliveryLayout.visible
onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible
onRemoveEntryRequested: removeEntry()
}
Row{
id:ephemeralTimerRow
anchors.right:downloadButton.visible?downloadButton.left:parent.right
anchors.bottom:parent.bottom
anchors.bottomMargin: 5
anchors.rightMargin : 5
visible:$chatEntry.isEphemeral
spacing:5
Text{
text: $chatEntry.ephemeralExpireTime > 0 ? Utils.formatElapsedTime($chatEntry.ephemeralExpireTime) : Utils.formatElapsedTime($chatEntry.ephemeralLifetime)
color:"#FF5E00"
font.pointSize: Units.dp * 8
Timer{
running:parent.visible
interval: 1000
repeat:true
onTriggered: if($chatEntry.getEphemeralExpireTime() > 0 ) parent.text = Utils.formatElapsedTime($chatEntry.getEphemeralExpireTime())// Use the function
}
}
Icon{
icon:'timer'
iconSize: 15
}
}
}
ChatDeliveries{
@ -308,6 +335,20 @@ Row {
chatMessageModel: $chatEntry
}
ActionButton {
height: ChatStyle.entry.lineHeight
anchors.left:rectangle.right
anchors.leftMargin: -10
anchors.top:rectangle.top
anchors.topMargin: 5
icon: 'chat_menu'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: chatMenu.open()
}
}
// -------------------------------------------------------------------------
@ -363,15 +404,6 @@ Row {
: icon
) : undefined
}
ActionButton {
height: ChatStyle.entry.lineHeight
icon: 'delete'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: removeEntry()
}
}
}

View file

@ -60,14 +60,5 @@ RowLayout {
backgroundColor: ChatStyle.entry.message.incoming.backgroundColor
color: ChatStyle.entry.message.incoming.text.color
pointSize: ChatStyle.entry.message.incoming.text.pointSize
ActionButton {
height: ChatStyle.entry.lineHeight
icon: 'delete'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: removeEntry()
}
}
}

View file

@ -70,7 +70,7 @@ Item {
icon:'timer'
iconSize: 15
}
}
}
}
@ -112,13 +112,14 @@ Item {
}
ChatMenu{
id:chatMenu
height: parent.height
width: rectangle.width
lastTextSelected: message.lastTextSelected
content: $chatEntry.content
deliveryCount: deliveryLayout.model.count
onDeliveryStatusClecked: deliveryLayout.visible = !deliveryLayout.visible
onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible
onRemoveEntryRequested: removeEntry()
}
}
@ -144,4 +145,18 @@ Item {
chatMessageModel: $chatEntry
}
ActionButton {
height: ChatStyle.entry.lineHeight
anchors.left:rectangle.right
anchors.leftMargin: -10
anchors.top:rectangle.top
anchors.topMargin: 5
icon: 'chat_menu'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: chatMenu.open()
}
}

View file

@ -88,15 +88,6 @@ Item {
? indicator
: iconComponent
}
ActionButton {
height: ChatStyle.entry.lineHeight
icon: 'delete'
iconSize: ChatStyle.entry.deleteIconSize
visible: isHoverEntry()
onClicked: removeEntry()
}
}
}
}

View file

@ -106,7 +106,7 @@ Rectangle {
&& (entry.isOneToOne == undefined || entry.isOneToOne) && (entry.haveEncryption == undefined || !entry.haveEncryption)
? entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || ''
: '')
participants: entry && item.showContactAddress && sipAddress == '' && entry.isOneToOne ? entry.participants.addressesToString : ''
participants: entry && item.showContactAddress && sipAddress == '' && entry.isOneToOne && entry.participants ? entry.participants.addressesToString : ''
username: avatar.username
}

View file

@ -223,14 +223,14 @@ ColumnLayout {
icon: 'video_call'
visible: SettingsModel.videoSupported && SettingsModel.outgoingCallsEnabled && SettingsModel.showStartVideoCallButton && !conversation.haveMoreThanOneParticipants
onClicked: CallsListModel.launchVideoCall(conversation.peerAddress)
onClicked: CallsListModel.launchVideoCall(chatRoomModel.participants.addressesToString)
}
ActionButton {
icon: 'call'
visible: SettingsModel.outgoingCallsEnabled && !conversation.haveMoreThanOneParticipants
onClicked: CallsListModel.launchAudioCall(conversation.peerAddress)
onClicked: CallsListModel.launchAudioCall(chatRoomModel.participants.addressesToString)
}
ActionButton {
icon: 'chat'