Feature: Reply to a message.

This commit is contained in:
Julien Wadel 2021-11-05 21:25:12 +01:00
parent bc91382ca2
commit a5f9fcb4c4
39 changed files with 1078 additions and 114 deletions

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="80"
height="80"
viewBox="0 0 80 80"
version="1.1"
id="svg8"
sodipodi:docname="menu_forward_custom.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="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="4.85"
inkscape:cx="-16.597938"
inkscape:cy="43.917526"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<g
fill="none"
fill-rule="evenodd"
id="g6"
transform="matrix(0.94339623,0,0,0.90909091,15,19.609091)">
<g
fill="#444444"
fill-rule="nonzero"
id="g4">
<path
d="M 24.071,28.481 V 26.72 h 1.625 c 1.553,0 2.931,0.043 4.13,0.126 1.15,0.08 2.294,0.223 3.428,0.429 1.003,0.182 1.83,0.418 2.48,0.697 0.632,0.271 1.22,0.618 1.772,1.046 0.425,0.33 0.759,0.708 1.02,1.15 0.308,0.521 0.571,1.195 0.775,2.03 0.213,0.872 0.325,1.914 0.325,3.123 l -0.003,0.362 c -0.008,0.496 -0.033,1.038 -0.074,1.628 l -0.043,0.548 -0.018,0.125 c -0.073,0.46 -0.113,0.841 -0.113,1.229 0,1.225 0.446,2.401 1.308,3.312 0.95,0.999 2.203,1.475 3.496,1.475 1.48,0 2.772,-0.657 3.687,-1.716 l 0.04,-0.047 c 0.335,-0.388 0.616,-0.814 0.855,-1.277 l 0.245,-0.483 0.418,-0.853 C 51.77,34.91 53,30.994 53,27.76 53,24.254 52.46,21.216 51.328,18.652 l -0.15,-0.324 C 47.572,10.724 38.85,7.2 25.697,7.2 H 24.072 V 5.44 C 24.072,3.882 23.409,2.474 22.265,1.449 21.208,0.503 19.88,0 18.464,0 17.048,0 15.72,0.503 14.664,1.45 L 1.808,12.968 C 0.663,13.996 0,15.403 0,16.96 c 0,1.557 0.664,2.965 1.807,3.99 l 12.858,11.522 c 1.058,0.946 2.385,1.448 3.8,1.448 1.414,0 2.742,-0.502 3.797,-1.446 1.146,-1.027 1.81,-2.436 1.81,-3.994 z M 18.464,4 c 0.436,0 0.812,0.143 1.13,0.428 0.278,0.249 0.435,0.538 0.47,0.868 l 0.007,0.144 v 5.76 h 5.625 c 11.936,0 19.26,3.023 21.973,9.068 0.887,2.01 1.331,4.508 1.331,7.493 0,2.401 -0.989,5.632 -2.965,9.692 l -0.666,1.355 -0.16,0.314 c -0.102,0.196 -0.21,0.36 -0.327,0.496 C 44.681,39.873 44.447,40 44.179,40 c -0.251,0 -0.448,-0.075 -0.59,-0.225 -0.143,-0.15 -0.214,-0.337 -0.214,-0.562 l 0.003,-0.089 0.02,-0.223 0.087,-0.613 0.014,-0.148 0.002,-0.052 c 0.083,-1.02 0.125,-1.942 0.125,-2.767 0,-1.515 -0.147,-2.873 -0.44,-4.073 -0.292,-1.2 -0.698,-2.238 -1.217,-3.116 -0.52,-0.878 -1.189,-1.635 -2.01,-2.273 -0.82,-0.637 -1.703,-1.158 -2.649,-1.563 -0.946,-0.406 -2.06,-0.724 -3.34,-0.957 -1.28,-0.232 -2.57,-0.394 -3.867,-0.484 -1.135,-0.078 -2.402,-0.123 -3.8,-0.132 l -0.607,-0.002 h -5.625 v 5.76 c 0,0.39 -0.159,0.728 -0.477,1.013 -0.318,0.284 -0.695,0.427 -1.13,0.427 -0.38,0 -0.716,-0.11 -1.008,-0.327 L 17.334,29.494 4.477,17.973 C 4.16,17.688 4,17.351 4,16.961 4,16.619 4.122,16.318 4.365,16.057 L 4.477,15.947 17.334,4.427 C 17.652,4.143 18.029,4 18.464,4 Z"
transform="matrix(-1,0,0,1,53,0.43)"
id="path2" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="80"
height="80"
viewBox="0 0 80 80"
version="1.1"
id="svg8"
sodipodi:docname="menu_reply_custom.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="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs12" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="4.85"
inkscape:cx="45.670103"
inkscape:cy="13.608247"
inkscape:window-width="1920"
inkscape:window-height="1131"
inkscape:window-x="1920"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<g
fill="none"
fill-rule="evenodd"
id="g6"
transform="matrix(0.94339623,0,0,0.90909091,15,19.609091)">
<g
fill="#444444"
fill-rule="nonzero"
id="g4">
<path
d="M 24.071,28.481 V 26.72 h 1.625 c 1.553,0 2.931,0.043 4.13,0.126 1.15,0.08 2.294,0.223 3.428,0.429 1.003,0.182 1.83,0.418 2.48,0.697 0.632,0.271 1.22,0.618 1.772,1.046 0.425,0.33 0.759,0.708 1.02,1.15 0.308,0.521 0.571,1.195 0.775,2.03 0.213,0.872 0.325,1.914 0.325,3.123 l -0.003,0.362 c -0.008,0.496 -0.033,1.038 -0.074,1.628 l -0.043,0.548 -0.018,0.125 c -0.073,0.46 -0.113,0.841 -0.113,1.229 0,1.225 0.446,2.401 1.308,3.312 0.95,0.999 2.203,1.475 3.496,1.475 1.48,0 2.772,-0.657 3.687,-1.716 l 0.04,-0.047 c 0.335,-0.388 0.616,-0.814 0.855,-1.277 l 0.245,-0.483 0.418,-0.853 C 51.77,34.91 53,30.994 53,27.76 53,24.254 52.46,21.216 51.328,18.652 l -0.15,-0.324 C 47.572,10.724 38.85,7.2 25.697,7.2 H 24.072 V 5.44 C 24.072,3.882 23.409,2.474 22.265,1.449 21.208,0.503 19.88,0 18.464,0 17.048,0 15.72,0.503 14.664,1.45 L 1.808,12.968 C 0.663,13.996 0,15.403 0,16.96 c 0,1.557 0.664,2.965 1.807,3.99 l 12.858,11.522 c 1.058,0.946 2.385,1.448 3.8,1.448 1.414,0 2.742,-0.502 3.797,-1.446 1.146,-1.027 1.81,-2.436 1.81,-3.994 z M 18.464,4 c 0.436,0 0.812,0.143 1.13,0.428 0.278,0.249 0.435,0.538 0.47,0.868 l 0.007,0.144 v 5.76 h 5.625 c 11.936,0 19.26,3.023 21.973,9.068 0.887,2.01 1.331,4.508 1.331,7.493 0,2.401 -0.989,5.632 -2.965,9.692 l -0.666,1.355 -0.16,0.314 c -0.102,0.196 -0.21,0.36 -0.327,0.496 C 44.681,39.873 44.447,40 44.179,40 c -0.251,0 -0.448,-0.075 -0.59,-0.225 -0.143,-0.15 -0.214,-0.337 -0.214,-0.562 l 0.003,-0.089 0.02,-0.223 0.087,-0.613 0.014,-0.148 0.002,-0.052 c 0.083,-1.02 0.125,-1.942 0.125,-2.767 0,-1.515 -0.147,-2.873 -0.44,-4.073 -0.292,-1.2 -0.698,-2.238 -1.217,-3.116 -0.52,-0.878 -1.189,-1.635 -2.01,-2.273 -0.82,-0.637 -1.703,-1.158 -2.649,-1.563 -0.946,-0.406 -2.06,-0.724 -3.34,-0.957 -1.28,-0.232 -2.57,-0.394 -3.867,-0.484 -1.135,-0.078 -2.402,-0.123 -3.8,-0.132 l -0.607,-0.002 h -5.625 v 5.76 c 0,0.39 -0.159,0.728 -0.477,1.013 -0.318,0.284 -0.695,0.427 -1.13,0.427 -0.38,0 -0.716,-0.11 -1.008,-0.327 L 17.334,29.494 4.477,17.973 C 4.16,17.688 4,17.351 4,16.961 4,16.619 4.122,16.318 4.365,16.057 L 4.477,15.947 17.334,4.427 C 17.652,4.143 18.029,4 18.464,4 Z"
transform="translate(0,0.43)"
id="path2" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -533,6 +533,16 @@ Server url ikke konfigureret.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ Server url ikke konfigureret.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ Server URL ist nicht konfiguriert.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ Server URL ist nicht konfiguriert.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ Server URL not configured.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation>Hide delivery status</translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation>Forward</translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation>Reply</translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ Server URL not configured.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation>Reply</translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation>Reply to %1</translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ URL del servidor no configurada.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ URL del servidor no configurada.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -159,7 +159,7 @@
</message>
<message>
<source>usernameStatusInvalidCharacters</source>
<translation>Caractères invalides détectés (regex: `%1`).</translation>
<translation>Caractères invalides détectés (regex&#x202f;: `%1`).</translation>
</message>
<message>
<source>usernameStatusInvalid</source>
@ -175,7 +175,7 @@
</message>
<message>
<source>passwordStatusInvalidCharacters</source>
<translation>Caractères invalides détectés (regex: `%1`).</translation>
<translation>Caractères invalides détectés (regex&#x202f;: `%1`).</translation>
</message>
<message>
<source>passwordStatusMissingCharacters</source>
@ -533,6 +533,16 @@ URL du serveur non configurée.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation>Cacher le statut du message</translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ URL du serveur non configurée.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>
@ -978,7 +1004,7 @@ URL du serveur non configurée.</translation>
<message>
<source>ephemeralNotInConference!</source>
<extracomment>&apos;Ephemeral message is only supported in conference based chat room!&apos;</extracomment>
<translation>Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence!</translation>
<translation>Les messages éphémères ne sont disponibles que pour une conversation définie en mode conférence&#x202f;!</translation>
<extra-Context>Warning about not being in conference based chat room.</extra-Context>
</message>
<message>
@ -1917,7 +1943,7 @@ Cliquez ici : &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;
</message>
<message>
<source>serverTooltip</source>
<translation>Serveur LDAP. ie: ldap:// pour un serveur local ou ldap://ldap.example.org/</translation>
<translation>Serveur LDAP. ie&#x202f;: ldap:// pour un serveur local ou ldap://ldap.example.org/</translation>
</message>
<message>
<source>bindDNLabel</source>

View file

@ -532,6 +532,16 @@ A kiszolgáló URL-je nincs konfigurálva.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation>Kézbesítési állapot elrejtése</translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -560,6 +570,22 @@ A kiszolgáló URL-je nincs konfigurálva.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ URL del server non configurato.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation>Nascondi lo stato del messaggio</translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ URL del server non configurato.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -532,6 +532,16 @@
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -560,6 +570,22 @@
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -534,6 +534,16 @@ Nesukonfigūruotas serverio url.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -570,6 +580,22 @@ Nesukonfigūruotas serverio url.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ URL do servidor não configurado.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation>Ocultar status de entrega</translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ URL do servidor não configurado.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -534,6 +534,16 @@
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -570,6 +580,22 @@
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -533,6 +533,16 @@ Serverwebbadressen är inte konfigurerad.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -565,6 +575,22 @@ Serverwebbadressen är inte konfigurerad.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -532,6 +532,16 @@ Sunucu url&apos;si yapılandırılmadı.</translation>
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -560,6 +570,22 @@ Sunucu url&apos;si yapılandırılmadı.</translation>
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -534,6 +534,16 @@
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -570,6 +580,22 @@
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -532,6 +532,16 @@
<extracomment>&apos;Hide delivery status&apos; : Item menu that lead to IMDN of a message</extracomment>
<translation></translation>
</message>
<message>
<source>menuForward</source>
<extracomment>&apos;Forward&apos; : Forward a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<source>menuReply</source>
<extracomment>&apos;Reply&apos; : Reply to a message from menu</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatNoticeModel</name>
@ -560,6 +570,22 @@
</translation>
</message>
</context>
<context>
<name>ChatReplyMessage</name>
<message>
<source>headerReply</source>
<extracomment>&apos;Reply&apos; : Header on a message that contains a reply.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>ChatReplyPreview</name>
<message>
<source>titleReply</source>
<extracomment>&apos;Reply to %1&apos; : Title for a reply preview to know who said what.</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>Cli</name>
<message>

View file

@ -82,6 +82,8 @@
<file>assets/images/led_red.svg</file>
<file>assets/images/led_white.svg</file>
<file>assets/images/menu_copy_text_custom.svg</file>
<file>assets/images/menu_reply_custom.svg</file>
<file>assets/images/menu_forward_custom.svg</file>
<file>assets/images/menu_imdn_info_custom.svg</file>
<file>assets/images/menu_vdots_custom.svg</file>
<file>assets/images/menu_info_custom.svg</file>
@ -134,7 +136,7 @@
<file>assets/images/tooltip_arrow_right_custom.svg</file>
<file>assets/images/tooltip_arrow_top_custom.svg</file>
<file>assets/images/transfer_custom.svg</file>
<file>assets/images/update_sign.svg</file>
<file>assets/images/update_sign.svg</file>
<file>assets/images/video_call_accept_custom.svg</file>
<file>assets/images/video_call_custom.svg</file>
<file>assets/images/warning.svg</file>
@ -268,6 +270,9 @@
<file>ui/modules/Linphone/Chat/Chat.qml</file>
<file>ui/modules/Linphone/Chat/ChatDeliveries.qml</file>
<file>ui/modules/Linphone/Chat/ChatMenu.qml</file>
<file>ui/modules/Linphone/Chat/ChatMessagePreview.qml</file>
<file>ui/modules/Linphone/Chat/ChatReplyMessage.qml</file>
<file>ui/modules/Linphone/Chat/ChatReplyPreview.qml</file>
<file>ui/modules/Linphone/Chat/Event.qml</file>
<file>ui/modules/Linphone/Chat/FileMessage.qml</file>
<file>ui/modules/Linphone/Chat/IncomingMessage.qml</file>
@ -307,6 +312,7 @@
<file>ui/modules/Linphone/Styles/Calls/CallStatisticsStyle.qml</file>
<file>ui/modules/Linphone/Styles/Calls/ConferenceControlsStyle.qml</file>
<file>ui/modules/Linphone/Styles/Chat/ChatStyle.qml</file>
<file>ui/modules/Linphone/Styles/Chat/ChatReplyMessageStyle.qml</file>
<file>ui/modules/Linphone/Styles/Codecs/CodecsViewerStyle.qml</file>
<file>ui/modules/Linphone/Styles/Contact/AvatarStyle.qml</file>
<file>ui/modules/Linphone/Styles/Contact/ContactDescriptionStyle.qml</file>

View file

@ -82,7 +82,6 @@ QString ContentModel::getThumbnail() const{
return mThumbnail;
}
void ContentModel::setFileOffset(quint64 fileOffset){
if( mFileOffset != fileOffset) {
mFileOffset = fileOffset;
@ -302,6 +301,12 @@ ChatMessageModel::ChatMessageModel ( std::shared_ptr<linphone::ChatMessage> chat
mWasDownloaded = false;
mChatMessage->addListener(mChatMessageListener);
mTimestamp = QDateTime::fromMSecsSinceEpoch(chatMessage->getTime() * 1000);
if( mChatMessage->isReply()){
auto replyMessage = mChatMessage->getReplyMessage();
if( replyMessage)// Reply message could be inexistant (for example : when locally deleted)
mReplyChatMessageModel = create(replyMessage, parent);
}
connect(this, &ChatMessageModel::remove, dynamic_cast<ChatRoomModel*>(parent), &ChatRoomModel::removeEntry);
std::list<std::shared_ptr<linphone::Content>> contents = chatMessage->getContents();
@ -365,6 +370,13 @@ QString ChatMessageModel::getFromDisplayName() const{
return Utils::getDisplayName(mChatMessage->getFromAddress());
}
QString ChatMessageModel::getFromDisplayNameReplyMessage() const{
if( isReply())
return Utils::getDisplayName(mChatMessage->getReplyMessageSenderAddress());
else
return "";
}
QString ChatMessageModel::getFromSipAddress() const{
return Utils::cleanSipAddress(Utils::coreStringToAppString(mChatMessage->getFromAddress()->asStringUriOnly()));
}
@ -424,6 +436,13 @@ std::shared_ptr<ParticipantImdnStateListModel> ChatMessageModel::getParticipantI
return mParticipantImdnStateListModel;
}
bool ChatMessageModel::isReply() const{
return mChatMessage->isReply();
}
ChatMessageModel * ChatMessageModel::getReplyChatMessageModel() const{
return mReplyChatMessageModel.get();
}
//-----------------------------------------------------------------------------------------------------------------------

View file

@ -60,6 +60,7 @@ public:
Q_PROPERTY(QString thumbnail READ getThumbnail WRITE setThumbnail NOTIFY thumbnailChanged)
Q_PROPERTY(bool wasDownloaded MEMBER mWasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged)
std::shared_ptr<linphone::Content> getContent()const;
quint64 getFileSize() const;
@ -135,6 +136,7 @@ public:
Q_PROPERTY(QString fromDisplayName READ getFromDisplayName CONSTANT)
Q_PROPERTY(QString fromDisplayNameReplyMessage READ getFromDisplayNameReplyMessage CONSTANT)
Q_PROPERTY(QString fromSipAddress READ getFromSipAddress CONSTANT)
Q_PROPERTY(QString toDisplayName READ getToDisplayName CONSTANT)
Q_PROPERTY(QString toSipAddress READ getToSipAddress CONSTANT)
@ -155,6 +157,9 @@ public:
Q_PROPERTY(ContentModel * fileContentModel READ getFileContentModel NOTIFY fileContentChanged)
//Q_PROPERTY(QList<ContentModel *> contents READ getContents CONSTANT)
Q_PROPERTY(bool isReply READ isReply CONSTANT)
Q_PROPERTY(ChatMessageModel* replyChatMessageModel READ getReplyChatMessageModel CONSTANT)
std::shared_ptr<linphone::ChatMessage> getChatMessage();
std::shared_ptr<ContentModel> getContentModel(std::shared_ptr<linphone::Content> content);
Q_INVOKABLE ContentModel * getContent(int i);
@ -162,6 +167,7 @@ public:
//----------------------------------------------------------------------------
QString getFromDisplayName() const;
QString getFromDisplayNameReplyMessage() const;
QString getFromSipAddress() const;
QString getToDisplayName() const;
QString getToSipAddress() const;
@ -176,6 +182,9 @@ public:
Q_INVOKABLE ParticipantImdnStateProxyModel * getProxyImdnStates();
std::shared_ptr<ParticipantImdnStateListModel> getParticipantImdnStates() const;
bool isReply() const;
ChatMessageModel * getReplyChatMessageModel() const;
//----------------------------------------------------------------------------
void setWasDownloaded(bool wasDownloaded);
@ -219,6 +228,8 @@ private:
std::shared_ptr<linphone::ChatMessage> mChatMessage;
std::shared_ptr<ParticipantImdnStateListModel> mParticipantImdnStateListModel;
std::shared_ptr<ChatMessageListener> mChatMessageListener;
std::shared_ptr<ChatMessageModel> mReplyChatMessageModel;
};
Q_DECLARE_METATYPE(ChatMessageModel*)
Q_DECLARE_METATYPE(std::shared_ptr<ChatMessageModel>)

View file

@ -187,7 +187,7 @@ std::shared_ptr<ChatRoomModel> ChatRoomModel::create(std::shared_ptr<linphone::C
ChatRoomModel::ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObject * parent) : QAbstractListModel(parent){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
CoreManager *coreManager = CoreManager::getInstance();
mReply = nullptr;
mCoreHandlers = coreManager->getHandlers();
mChatRoom = chatRoom;
@ -592,6 +592,14 @@ void ChatRoomModel::setEphemeralLifetime(long lifetime){
}
}
void ChatRoomModel::setReply(ChatMessageModel * model){
if(mReply)
clearReply();
mReply = model->getChatMessage();
}
void ChatRoomModel::clearReply(){
mReply = nullptr;
}
//------------------------------------------------------------------------------------------------
void ChatRoomModel::deleteChatRoom(){
@ -630,9 +638,15 @@ void ChatRoomModel::updateParticipants(const QVariantList& participants){
// -----------------------------------------------------------------------------
void ChatRoomModel::sendMessage (const QString &message) {
shared_ptr<linphone::ChatMessage> _message = mChatRoom->createMessageFromUtf8(message.toUtf8().toStdString());
_message->send();
shared_ptr<linphone::ChatMessage> _message;
if(mReply){
_message = mChatRoom->createReplyMessage(mReply);
_message->addUtf8TextContent(message.toUtf8().toStdString());
}else{
_message= mChatRoom->createMessageFromUtf8(message.toUtf8().toStdString());
}
_message->send();
emit messageSent(_message);
}

View file

@ -35,6 +35,7 @@ class ParticipantListModel;
class ChatEvent;
class ContactModel;
class ChatRoomModel;
class ChatMessageModel;
class ChatRoomModelListener : public QObject, public linphone::ChatRoomListener {
Q_OBJECT
@ -207,6 +208,9 @@ public:
void addMissedCallsCount(std::shared_ptr<linphone::Call> call);
void setEphemeralEnabled(bool enabled);
void setEphemeralLifetime(long lifetime);
void setReply(ChatMessageModel * model);
void clearReply();
// Tools
@ -336,6 +340,8 @@ private:
std::shared_ptr<linphone::ChatRoom> mChatRoom;
std::shared_ptr<ChatRoomModelListener> mChatRoomModelListener;
std::shared_ptr<linphone::ChatMessage> mReply;
std::weak_ptr<ChatRoomModel> mSelf;
};

View file

@ -120,6 +120,8 @@ CREATE_PARENT_MODEL_FUNCTION(removeAllEntries)
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendFileMessage, const QString &)
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendMessage, const QString &)
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(setReply, ChatMessageModel*)
CREATE_PARENT_MODEL_FUNCTION(clearReply)
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeRow)

View file

@ -70,6 +70,9 @@ public:
Q_INVOKABLE void setFilterText(const QString& text);
Q_INVOKABLE void setReply(ChatMessageModel* model);
Q_INVOKABLE void clearReply();
signals:
void peerAddressChanged (const QString &peerAddress);
void localAddressChanged (const QString &localAddress);

View file

@ -23,6 +23,9 @@ Item {
property string dropDisabledReason
property bool isEphemeral : false
property int textLeftMargin: (fileChooserButton.visible? fileChooserButton.totalWidth + DroppableTextAreaStyle.fileChooserButton.margins: 0)
property int textRightMargin: sendButton.visible ? sendButton.totalWidth + DroppableTextAreaStyle.fileChooserButton.margins : 0
// ---------------------------------------------------------------------------
signal dropped (var files)
@ -55,6 +58,7 @@ Item {
// Handle click to select files.
ActionButton {
id: fileChooserButton
property int totalWidth: DroppableTextAreaStyle.fileChooserButton.margins + width
Layout.leftMargin: DroppableTextAreaStyle.fileChooserButton.margins
Layout.alignment: Qt.AlignVCenter
@ -189,6 +193,7 @@ Item {
// Handle click to select files.
ActionButton {
id: sendButton
property int totalWidth: Layout.rightMargin + Layout.leftMargin + width
Layout.rightMargin: DroppableTextAreaStyle.fileChooserButton.margins+15
Layout.leftMargin: 10
Layout.alignment: Qt.AlignVCenter

View file

@ -18,6 +18,14 @@ QtObject {
property int iconSize: 30
property string icon : 'menu_copy_text_custom'
}
property QtObject reply: QtObject {
property int iconSize: 30
property string icon : 'menu_reply_custom'
}
property QtObject forward: QtObject {
property int iconSize: 30
property string icon : 'menu_forward_custom'
}
property QtObject imdn: QtObject {
property int iconSize: 30
property string icon : 'menu_imdn_info_custom'

View file

@ -5,8 +5,11 @@ import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
import Utils 1.0
import UtilsCpp 1.0
import Units 1.0
import 'Chat.js' as Logic
// =============================================================================
@ -20,6 +23,8 @@ Rectangle {
property string noticeBannerText : '' // When set, show a banner with text and hide after some time
onNoticeBannerTextChanged: if(noticeBannerText!='') messageBlock.state = "showed"
property alias replyChatMessageModel: chatMessagePreview.replyChatMessageModel
// ---------------------------------------------------------------------------
signal messageToSend (string text)
@ -259,31 +264,38 @@ Rectangle {
source: Logic.getComponentFromEntry($chatEntry)
}
Connections{
target: loader.item
ignoreUnknownSignals: true
//: "Copied to clipboard" : when a user copy a text from the menu, this message show up.
onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied")
//: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up.
onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied")
target: loader.item
ignoreUnknownSignals: true
//: "Copied to clipboard" : when a user copy a text from the menu, this message show up.
onCopyAllDone: container.noticeBannerText = qsTr("allTextCopied")
//: "Selection copied to clipboard" : when a user copy a text from the menu, this message show up.
onCopySelectionDone: container.noticeBannerText = qsTr("selectedTextCopied")
onReplyClicked: {
proxyModel.setReply($chatEntry)
container.replyChatMessageModel = $chatEntry
}
}
}
}
}
}
footer: Item{
Text {
property var composers : container.proxyModel.composers
color: ChatStyle.composingText.color
font.pointSize: ChatStyle.composingText.pointSize
height: visible ? undefined : 0
leftPadding: ChatStyle.composingText.leftPadding
visible: composers.length > 0 && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
wrapMode: Text.Wrap
//: '%1 is typing...' indicate that someone is composing in chat
text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
}
}
Text {
property var composers : container.proxyModel.composers
color: ChatStyle.composingText.color
font.pointSize: ChatStyle.composingText.pointSize
height: visible ? undefined : 0
leftPadding: ChatStyle.composingText.leftPadding
visible: composers.length > 0 && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
wrapMode: Text.Wrap
//: '%1 is typing...' indicate that someone is composing in chat
text:(composers.length==0?'': qsTr('chatTyping','',composers.length).arg(container.proxyModel.getDisplayNameComposers()))
}
}
ChatMessagePreview{
id: chatMessagePreview
}
Rectangle{
id: messageBlock
height: 32
@ -315,30 +327,30 @@ Rectangle {
Layout.fillWidth: true
text: container.noticeBannerText
font {
pointSize: ChatStyle.messageBanner.pointSize
}
pointSize: ChatStyle.messageBanner.pointSize
}
color: ChatStyle.messageBanner.textColor
}
}
states: [
State {
name: "hidden"
PropertyChanges { target: messageBlock; opacity: 0 }
},
State {
name: "showed"
PropertyChanges { target: messageBlock; opacity: 1 }
}
]
transitions: [
Transition {
from: "*"; to: "showed"
SequentialAnimation{
State {
name: "hidden"
PropertyChanges { target: messageBlock; opacity: 0 }
},
State {
name: "showed"
PropertyChanges { target: messageBlock; opacity: 1 }
}
]
transitions: [
Transition {
from: "*"; to: "showed"
SequentialAnimation{
NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 500 }
ScriptAction{ script: hideNoticeBanner.start()}
ScriptAction{ script: hideNoticeBanner.start()}
}
},
Transition {
},
Transition {
SequentialAnimation{
NumberAnimation{ properties: "opacity"; duration: 1000 }
ScriptAction{ script: container.noticeBannerText = '' }
@ -360,7 +372,7 @@ Rectangle {
borderColor: ChatStyle.sendArea.border.color
topWidth: ChatStyle.sendArea.border.width
visible: proxyModel.chatRoomModel && !proxyModel.chatRoomModel.hasBeenLeft && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
DroppableTextArea {
id: textArea
@ -385,9 +397,10 @@ Rectangle {
onValidText: {
textArea.text = ''
chat.bindToEnd = true
if(proxyModel.chatRoomModel)
if(proxyModel.chatRoomModel) {
proxyModel.sendMessage(text)
else{
}else{
console.log("Peer : " +proxyModel.peerAddress+ "/"+chat.model.peerAddress)
proxyModel.chatRoomModel = CallsListModel.createChat(proxyModel.peerAddress)
proxyModel.sendMessage(text)

View file

@ -28,6 +28,8 @@ Item {
signal removeEntryRequested()
signal copyAllDone()
signal copySelectionDone()
signal replyClicked()
signal forwardClicked()
function open(){
messageMenu.popup()
@ -68,6 +70,27 @@ Item {
onTriggered: TextToSpeech.say(container.content)
visible: content != ''
}
MenuItem {
//: 'Forward' : Forward a message from menu
text: qsTr('menuForward')
iconMenu: MenuItemStyle.forward.icon
iconSizeMenu: MenuItemStyle.forward.iconSize
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
onTriggered: container.forwardClicked()
visible: content != ''
}
MenuItem {
//: 'Reply' : Reply to a message from menu
text: qsTr('menuReply')
iconMenu: MenuItemStyle.reply.icon
iconSizeMenu: MenuItemStyle.reply.iconSize
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
onTriggered: container.replyClicked()
visible: content != ''
}
MenuItem {
//: 'Hide delivery status' : Item menu that lead to IMDN of a message
text: (deliveryVisible ? qsTr('menuHideDeliveryStatus')
@ -97,8 +120,6 @@ Item {
// Handle hovered link.
MouseArea {
anchors.fill: parent
//height: messageMenu.height
//width: messageMenu.width
acceptedButtons: Qt.RightButton
propagateComposedEvents:true

View file

@ -0,0 +1,28 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
import Utils 1.0
import UtilsCpp 1.0
import Units 1.0
import 'Chat.js' as Logic
// =============================================================================
ColumnLayout{
property alias replyChatMessageModel : replyPreview.replyChatMessageModel
property int maxHeight: parent.height
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: replyPreview.height
ChatReplyPreview{
id: replyPreview
Layout.fillWidth: true
}
}

View file

@ -0,0 +1,126 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import Clipboard 1.0
import Common 1.0
import Linphone 1.0
import Common.Styles 1.0
import Linphone.Styles 1.0
import TextToSpeech 1.0
import Utils 1.0
import Units 1.0
import UtilsCpp 1.0
import LinphoneEnums 1.0
import ColorsList 1.0
import 'Message.js' as Logic
// =============================================================================
Item {
id: mainItem
property ChatMessageModel chatMessageModel
property ChatMessageModel mainChatMessageModel
property int maxWidth : parent.width
property int contentWidth: Math.max(usernameReplied.implicitWidth + replyMessage.implicitWidth , headerArea.width) + 7 + ChatReplyMessageStyle.padding * 2
property int contentHeight: headerArea.height + replyArea.height
property font customFont : SettingsModel.textMessageFont
width: maxWidth > contentWidth ? contentWidth : maxWidth
onMainChatMessageModelChanged: if( mainChatMessageModel.replyChatMessageModel) chatMessageModel = mainChatMessageModel.replyChatMessageModel
ColumnLayout{
anchors.fill: parent
spacing: 5
Row{
id: headerArea
Layout.preferredHeight: icon.height
Layout.topMargin: 5
Icon{
id: icon
icon: ChatReplyMessageStyle.header.replyIcon.icon
iconSize: ChatReplyMessageStyle.header.replyIcon.iconSize
height: iconSize
overwriteColor: ChatReplyMessageStyle.header.color
}
Text{
height: icon.height
verticalAlignment: Qt.AlignVCenter
//: 'Reply' : Header on a message that contains a reply.
text: qsTr('headerReply')
+ (chatMessageModel || !mainChatMessageModel? '' : ' - ' + mainChatMessageModel.fromDisplayNameReplyMessage)
font.family: mainItem.customFont.family
font.pointSize: Units.dp * (mainItem.customFont.pointSize + ChatReplyMessageStyle.header.pointSizeOffset)
color: ChatReplyMessageStyle.header.color
}
}
Rectangle{
id: replyArea
Layout.fillWidth: true
Layout.preferredHeight: (chatMessageModel ? replyMessage.implicitHeight + usernameReplied.implicitHeight + ChatStyle.entry.message.padding : 0)
Layout.bottomMargin: ChatStyle.entry.message.padding
Layout.leftMargin: 10
Layout.rightMargin: 10
Rectangle{
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 7
color: chatMessageModel && chatMessageModel.isOutgoing ? ChatReplyMessageStyle.replyArea.outgoingMarkColor : ChatReplyMessageStyle.replyArea.incomingMarkColor
}
radius: 5
color: ChatReplyMessageStyle.replyArea.backgroundColor
visible: chatMessageModel != undefined
Text{
id: usernameReplied
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 3
leftPadding: 2 * ChatStyle.entry.message.padding
text: mainChatMessageModel && mainChatMessageModel.fromDisplayNameReplyMessage
font.family: mainItem.customFont.family
font.pointSize: Units.dp * (mainItem.customFont.pointSize + ChatReplyMessageStyle.replyArea.usernamePointSizeOffset)
font.weight: Font.Bold
color: ChatReplyMessageStyle.replyArea.foregroundColor
}
TextEdit {
id: replyMessage
property string lastTextSelected : ''
property font customFont : SettingsModel.textMessageFont
anchors.top: usernameReplied.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.topMargin: 3
clip: true
leftPadding: 2*ChatStyle.entry.message.padding
rightPadding: ChatStyle.entry.message.padding
bottomPadding: ChatStyle.entry.message.padding
readOnly: true
selectByMouse: true
font.family: customFont.family
font.pointSize: Units.dp * (customFont.pointSize + ChatReplyMessageStyle.replyArea.pointSizeOffset)
font.weight: Font.Light
color: ChatReplyMessageStyle.replyArea.foregroundColor
text: (visible ? Utils.encodeTextToQmlRichFormat(chatMessageModel.content, {
imagesHeight: ChatStyle.entry.message.images.height,
imagesWidth: ChatStyle.entry.message.images.width
})
: '')
textFormat: Text.RichText // To supports links and imgs.
wrapMode: TextEdit.Wrap
}
}
}
}

View file

@ -0,0 +1,139 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import Common 1.0
import Linphone 1.0
import Linphone.Styles 1.0
import Utils 1.0
import UtilsCpp 1.0
import Units 1.0
import 'Chat.js' as Logic
// =============================================================================
Rectangle{
id: replyPreviewBlock
property ChatMessageModel replyChatMessageModel
onReplyChatMessageModelChanged: if(replyChatMessageModel) replyPreviewBlock.state = "showed"
Layout.preferredHeight: Math.min(replayPreviewText.implicitHeight + replyPreviewHeaderArea.implicitHeight + 10, parent.maxHeight)
property int leftMargin: textArea.textLeftMargin
property int rightMargin: textArea.textRightMargin
color: ChatStyle.replyPreview.backgroundColor
radius: 10
state: "hidden"
visible: container.replyChatMessageModel
// Remove bottom corners
clip: false
Rectangle{
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: parent.radius
color: parent.color
}
//-------------------------
ColumnLayout{
anchors.fill: parent
anchors.leftMargin: replyPreviewBlock.leftMargin
anchors.rightMargin: replyPreviewBlock.rightMargin
spacing: 0
RowLayout{
id: replyPreviewHeaderArea
Layout.fillWidth: true
Layout.preferredHeight: replyPreviewTitleText.implicitHeight
Layout.topMargin: 10
spacing: 5
Icon{
icon: ChatStyle.replyPreview.icon
overwriteColor: ChatStyle.replyPreview.iconColor
iconSize: 20
}
Text{
id: replyPreviewTitleText
Layout.fillWidth: true
Layout.preferredHeight: implicitHeight
//: 'Reply to %1' : Title for a reply preview to know who said what.
text: container.replyChatMessageModel ? qsTr('titleReply').arg(container.replyChatMessageModel.fromDisplayName) : ''
font.pointSize: ChatStyle.replyPreview.headerPointSize
font.weight: Font.Bold
color: ChatStyle.replyPreview.headerTextColor
}
}
Flickable {
id: replayPreviewTextArea
ScrollBar.vertical: ForceScrollBar {visible: replayPreviewTextArea.height < replayPreviewText.implicitHeight}
boundsBehavior: Flickable.StopAtBounds
clip: true
contentHeight: replayPreviewText.implicitHeight
contentWidth: width - ScrollBar.vertical.width
flickableDirection: Flickable.VerticalFlick
Layout.fillHeight: true
Layout.fillWidth: true
TextEdit {
id: replayPreviewText
property font customFont : SettingsModel.textMessageFont
anchors.left: parent.left
anchors.right: parent.right
clip: true
padding: ChatStyle.entry.message.padding
readOnly: true
selectByMouse: true
font.family: customFont.family
font.pointSize: Units.dp * (customFont.pointSize - 2)
text: replyChatMessageModel ? Utils.encodeTextToQmlRichFormat(replyChatMessageModel.content, {
imagesHeight: ChatStyle.entry.message.images.height,
imagesWidth: ChatStyle.entry.message.images.width
})
: ''
textFormat: Text.RichText // To supports links and imgs.
wrapMode: TextEdit.Wrap
onLinkActivated: Qt.openUrlExternally(link)
}
}
}
ActionButton{
anchors.right:parent.right
anchors.rightMargin: 14
anchors.verticalCenter: parent.verticalCenter
height: ChatStyle.replyPreview.closeButton.iconSize
isCustom: true
backgroundRadius: 90
colorSet: ChatStyle.replyPreview.closeButton
onClicked: parent.state = 'hidden'
}
states: [
State {
name: "hidden"
PropertyChanges { target: replyPreviewBlock; opacity: 0 }
},
State {
name: "showed"
PropertyChanges { target: replyPreviewBlock; opacity: 1 }
}
]
transitions: [
Transition {
from: "*"; to: "showed"
SequentialAnimation{
NumberAnimation{ properties: "opacity"; easing.type: Easing.OutBounce; duration: 500 }
}
},
Transition {
SequentialAnimation{
NumberAnimation{ properties: "opacity"; duration: 250 }
ScriptAction{ script: container.replyChatMessageModel = null }
}
}
]
}

View file

@ -13,6 +13,8 @@ RowLayout {
signal copyAllDone()
signal copySelectionDone()
signal replyClicked()
signal forwardClicked()
implicitHeight: message.height
spacing: 0
@ -61,6 +63,8 @@ RowLayout {
onCopyAllDone: parent.copyAllDone()
onCopySelectionDone: parent.copySelectionDone()
onReplyClicked: parent.replyClicked()
onForwardClicked: parent.forwardClicked()
Layout.fillWidth: true

View file

@ -34,26 +34,28 @@ Item {
signal copyAllDone()
signal copySelectionDone()
signal replyClicked()
signal forwardClicked()
// ---------------------------------------------------------------------------
implicitHeight: message.contentHeight
implicitHeight: message.contentHeight +
+ (replyMessage.visible ? replyMessage.contentHeight + 5 : 0)
+ (ephemeralTimerRow.visible? message.padding * 4 : message.padding * 2)
+ (deliveryLayout.visible? deliveryLayout.height : 0)
Rectangle {
id: rectangle
property int maxWidth: parent.width
property int dataWidth: Math.max(message.implicitWidth + 2*ChatStyle.entry.message.padding + 10, replyMessage.contentWidth)
height: parent.height - (deliveryLayout.visible? deliveryLayout.height : 0)
radius: ChatStyle.entry.message.radius
width: (
ephemeralTimerRow.visible && message.contentWidth < ephemeralTimerRow.width
ephemeralTimerRow.visible && dataWidth < ephemeralTimerRow.width
? ephemeralTimerRow.width
: message.contentWidth < parent.width
? message.contentWidth
: parent.width
) + message.padding * 2
: Math.min(dataWidth, maxWidth)
)
Row{
id:ephemeralTimerRow
anchors.right:parent.right
@ -78,64 +80,73 @@ Item {
overwriteColor: ChatStyle.ephemeralTimer.timerColor
iconSize: ChatStyle.ephemeralTimer.iconSize
}
}
}
}
// ---------------------------------------------------------------------------
// Message.
// ---------------------------------------------------------------------------
TextEdit {
id: message
property string lastTextSelected : ''
property font customFont : SettingsModel.textMessageFont
anchors {
left: container.left
right: container.right
}
clip: true
padding: ChatStyle.entry.message.padding
readOnly: true
selectByMouse: true
font.family: customFont.family
font.pointSize: Units.dp * customFont.pointSize
text: Utils.encodeTextToQmlRichFormat($chatEntry.content, {
imagesHeight: ChatStyle.entry.message.images.height,
imagesWidth: ChatStyle.entry.message.images.width
})
// See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop
// and http://doc.qt.io/qt-5/richtext-html-subset.html
textFormat: Text.RichText // To supports links and imgs.
wrapMode: TextEdit.Wrap
onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle)
onLinkActivated: Qt.openUrlExternally(link)
onSelectedTextChanged:if(selectedText != '') lastTextSelected = selectedText
onActiveFocusChanged: {
if(activeFocus)
lastTextSelected = ''
deselect()
}
ChatMenu{
id:chatMenu
height: parent.height
width: rectangle.width
lastTextSelected: message.lastTextSelected
content: $chatEntry.content
deliveryCount: deliveryLayout.model.count
onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible
onRemoveEntryRequested: removeEntry()
deliveryVisible: deliveryLayout.visible
onCopyAllDone: container.copyAllDone()
onCopySelectionDone: container.copySelectionDone()
Column{
anchors.left: parent.left
anchors.right: parent.right
spacing: 5
ChatReplyMessage{
id: replyMessage
mainChatMessageModel: $chatEntry
visible: $chatEntry.isReply
maxWidth: container.width
height: contentHeight
}
TextEdit {
id: message
property string lastTextSelected : ''
property font customFont : SettingsModel.textMessageFont
anchors.left: parent.left
anchors.right: parent.right
clip: true
padding: ChatStyle.entry.message.padding
readOnly: true
selectByMouse: true
font.family: customFont.family
font.pointSize: Units.dp * customFont.pointSize
text: Utils.encodeTextToQmlRichFormat($chatEntry.content, {
imagesHeight: ChatStyle.entry.message.images.height,
imagesWidth: ChatStyle.entry.message.images.width
})
// See http://doc.qt.io/qt-5/qml-qtquick-text.html#textFormat-prop
// and http://doc.qt.io/qt-5/richtext-html-subset.html
textFormat: Text.RichText // To supports links and imgs.
wrapMode: TextEdit.Wrap
onCursorRectangleChanged: Logic.ensureVisible(cursorRectangle)
onLinkActivated: Qt.openUrlExternally(link)
onSelectedTextChanged:if(selectedText != '') lastTextSelected = selectedText
onActiveFocusChanged: {
if(activeFocus)
lastTextSelected = ''
deselect()
}
ChatMenu{
id:chatMenu
height: parent.height
width: rectangle.width
lastTextSelected: message.lastTextSelected
content: $chatEntry.content
deliveryCount: deliveryLayout.model.count
onDeliveryStatusClicked: deliveryLayout.visible = !deliveryLayout.visible
onRemoveEntryRequested: removeEntry()
deliveryVisible: deliveryLayout.visible
onCopyAllDone: container.copyAllDone()
onCopySelectionDone: container.copySelectionDone()
onReplyClicked: container.replyClicked()
onForwardClicked: container.forwardClicked()
}
}
}
}

View file

@ -16,12 +16,16 @@ Item {
signal copyAllDone()
signal copySelectionDone()
signal replyClicked()
signal forwardClicked()
Message {
id: message
onCopyAllDone: parent.copyAllDone()
onCopySelectionDone: parent.copySelectionDone()
onReplyClicked: parent.replyClicked()
onForwardClicked: parent.forwardClicked()
anchors {
left: parent.left

View file

@ -0,0 +1,31 @@
pragma Singleton
import QtQml 2.2
import Units 1.0
import ColorsList 1.0
// =============================================================================
QtObject {
property string sectionName : 'ChatReplyMessage'
property color color: ColorsList.add(sectionName, 'q').color
property QtObject header: QtObject{
property color color: ColorsList.add(sectionName+'_header', 'h').color
property int pointSizeOffset: -3
property QtObject replyIcon: QtObject{
property string icon : 'menu_reply_custom'
property int iconSize: 22
}
}
property QtObject replyArea: QtObject{
property color outgoingMarkColor: ColorsList.add(sectionName+'_reply_outgoing_mark', 'm').color
property color incomingMarkColor: ColorsList.add(sectionName+'_reply_incoming_mark', 'r').color
property color backgroundColor: ColorsList.add(sectionName+'_reply_bg', 'q').color
property color foregroundColor: ColorsList.add(sectionName+'_reply_fg', 'h').color
property int usernamePointSizeOffset: -2
property int pointSizeOffset: -2
}
property int padding: 8
}

View file

@ -41,7 +41,28 @@ QtObject {
property int leftPadding: 20
property int pointSize: Units.dp * 9
}
property QtObject replyPreview: QtObject {
id: replyPreviewObject
property string name: 'replyPreview'
property string icon: 'menu_reply_custom'
property color backgroundColor: ColorsList.add(sectionName+'_'+name+'_bg', 'e').color
property color headerTextColor: ColorsList.add(sectionName+'_'+name+'_header_fg', 'i').color
property color iconColor: ColorsList.add(sectionName+'_'+name+'_header_fg', 'i').color
property color textColor: ColorsList.add(sectionName+'_'+name+'_fg', 'd').color
property int pointSize: Units.dp * 9
property int headerPointSize: Units.dp * 9
property QtObject closeButton: QtObject{
property int iconSize: 30
property string name : 'close'
property string icon : 'close_custom'
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_n', icon, 'l_n_b_bg').color
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_h', icon, 'l_h_b_bg').color
property color backgroundPressedColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_b_p', icon, 'l_p_b_bg').color
property color foregroundNormalColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_n', icon, 'l_n_b_fg').color
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_h', icon, 'l_h_b_fg').color
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+replyPreviewObject.name+'_'+name+'_f_p', icon, 'l_p_b_fg').color
}
}
property QtObject messageBanner: QtObject {
property color color: ColorsList.add(sectionName+'_message_banner', '', 'Background of message banner', '#9ecd1d').color
property color textColor: ColorsList.add(sectionName+'_message_banner_text', 'q', 'Text of message banner').color

View file

@ -10,6 +10,7 @@ singleton CardBlockStyle 1.0 Blocks/CardBlockStyle.qml
singleton RequestBlockStyle 1.0 Blocks/RequestBlockStyle.qml
singleton ChatStyle 1.0 Chat/ChatStyle.qml
singleton ChatReplyMessageStyle 1.0 Chat/ChatReplyMessageStyle.qml
singleton CallControlsStyle 1.0 Calls/CallControlsStyle.qml
singleton CallsStyle 1.0 Calls/CallsStyle.qml

View file

@ -15,6 +15,9 @@ Calls 1.0 Calls/Calls.qml
CallStatistics 1.0 Calls/CallStatistics.qml
Chat 1.0 Chat/Chat.qml
ChatMessagePreview 1.0 Chat/ChatMessagePreview.qml
ChatReplyMessage 1.0 Chat/ChatReplyMessage.qml
ChatReplyPreview 1.0 Chat/ChatReplyPreview.qml
History 1.0 History/History.qml

@ -1 +1 @@
Subproject commit 6f1485a2de0507a51087c81d6f457df8e6a496cd
Subproject commit ec7245a7a8a64d6f8e7f077e48e046907f524399