Menus, admin mode, handle participants, format ephemerals, imdn, realtime reactions

This commit is contained in:
Julien Wadel 2021-07-31 01:33:27 +02:00
parent 3e6c2daf10
commit 466b199023
46 changed files with 1522 additions and 349 deletions

View file

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="47"
height="47"
viewBox="0 0 47 47"
version="1.1"
id="svg6"
sodipodi:docname="admin_selected.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="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
height="47px"
inkscape:zoom="13.244681"
inkscape:cx="13.024096"
inkscape:cy="17.252209"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
fill="none"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
id="g4"
transform="translate(0,7.5)">
<path
stroke="#96c11f"
stroke-width="5"
d="M 2.5,13.176 20.41,29.5 44.39,2.5"
id="path2" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="menu_copy_text.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">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="40"
inkscape:cy="40.045819"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="80"
height="80"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAQAAACQ9RH5AAABJWlDQ1BJQ0MgcHJvZmlsZQAAKJGd
kL9Kw1AUxn+pfypSFxUHccjgJBRczORSFYKgEGMFq1OapFhMYkhSim/gm+jDdBAE38AXUHD2u9HB
wSxeOHw/Dud8370XWnYSpuX8LqRZVbh+b3A5uLLbbyywSocd2kFY5j3PO6HxfL5iGX3pGq/muT/P
YhSXoXSmysK8qMDaFzvTKjesYv227x+KH8R2lGaR+Em8HaWRYbPrp8kk/PE0t+nE2cW56au2cDnm
FA+bIRPGJFR0pZk6RzjsSV0KAu4pCaUJsXpTzVTciEo5uRyI+iLdpiFvs87zlDKUx1heJuGOVJ4m
D/O/32sfZ/WmtTHLgyKoW3Oq1mgE74+wMoC1Z1i+bsha+v22hhmnnvnnG78A0OhQWeOWQkkAAAAC
YktHRAAAqo0jMgAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB+UFEgwrBi6kkc0AAAAZdEVY
dENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAADlUlEQVRYw+2ZXWgUVxSAv5OtiWKbtSBG
En9aCq1SfOqDAQVTbTRUqxbbGiqmCqaoVF2NGCNUExrBV7EV8a/tvjStUJRqYqmgUZBCpBCsYmzq
T2UTDcasij9N1NOHuUljspO9szsZS/G83DuzZ+bjzPm7965gLdF4czhGC1197gvDGckk1ggexFr5
I72VVGc6m8RncKGqld4bfCU+glfoH2aWRS7DEmj8yd9m9jo7xTfwOwoQovTbD5Yk1liq1zxanZFc
pXaeM87BDdstLwHQxGr1Bdxy0BlXJbVjJnMBOE9EfQC3eUiS1TIHgN9Zq2mDn3hJTyJSBMBZyjRN
sFdZL4UANLJBAwVDucwA4Dc2ahrgdjMenWaPrpACAM6wSa3zOBo/HHYvj9nMv10yInEeL2BFr/dV
6SkA8qkWC4s/0Wh4oKp8h2h4uVX93CJTAPiVzZoUHNGYxSubKbFCV0k+AKfZ2k//hd4Xx8ZvM7NR
vMXopox4719rJt/7t6iwRL+Rvh6L90NXS4U2AMepOVFc4Orjaj0BwFQqE3jlY20DxtPGAwDGsb9H
q0wbgUzyye7zVCfHeAIM5bC4WhwztyoHKI6vsk/e0wfAXyzTvUbzNRqBTk66PveQAzUfFrv4uAWA
3KS++0myALjCp8Z3KyU76VNnF7pa7PjwZYuwOSLvaidwieW6SwB+lD16mQ4SRd1VuoBW9+DyIrUG
3cxKdVp/qauDFmtrj1k+lMxaGQLART6zSq4u/2p1nTgf7IJV6/e1SRyVkGn9azVQMPxs0Mn67yC0
xfIRIYv+Owjg6bfXT8gw/bdCAwRDYdO6AieXGvhCBwn8OOHdovpIsYOu54eDPoNfNOvHxDL7+9JD
zuy7eTZv81C58rgEdJh9RX/Zbca7fn/qLdY7wQM1Pvt4ESErvfvv+/qpYanA8czrJx+94rLnyKlz
mn+mz2CAtzvJT7av1KDyOBV5Dv4/giV4cAcA4eDBD03JDRjcvRTM82d5O5CcIxoH6Aq3coYLxsOl
EgD4XLhfTeOXZxHVb1IuAadTiLGUFW2XtJuEjUzj86dAXwdVQHKel0w78ONArHlKZyQA11Pfwpkj
uFERj2DnEOJmyuB65+yGuds9gvN6dvCpYHdqQ8pNklna7eHh5HiIvHvc6DlenjrgqZELeIceSjOw
sjgiKQTgKllguWhPLOMssS7/wnypMWK0ox7szGUMEyvnV/Ffl38ALrX2dxz/dg0AAAAASUVORK5C
YII=
"
id="image10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
sodipodi:docname="menu_delete.svg"
id="svg8"
version="1.1"
viewBox="0 0 82 82"
height="82"
width="82"
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="10.646341"
inkscape:cx="32.546392"
inkscape:cy="33.532646"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g6" />
<g
fill="none"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
id="g6">
<g
stroke="#ff0000"
stroke-width="5"
id="g4"
transform="matrix(1.0343907,0,0,1.018301,7.4655577,-0.5091505)">
<path
d="m 32.523,78.526 h 5.354 C 49.4,78.526 51.46,67.98 51.46,67.98 L 61.339,13.97 H 3.5 l 9.88,54.01 c 0,0 2.061,10.546 13.585,10.546 z M 25.731,27.473 v 51.053 z m 13.378,0 V 78.526 Z M 20.585,3 h 23.672 z"
id="path2" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg10"
sodipodi:docname="menu_devices_selected.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="defs14" />
<sodipodi:namedview
id="namedview12"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.646341"
inkscape:cx="35.458192"
inkscape:cy="41.000002"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
width="13px" />
<g
fill="none"
fill-rule="evenodd"
id="g8"
transform="matrix(0.18571633,0,0,0.1875043,0.90699082,-0.28142708)">
<g
id="g6">
<path
stroke="#ff8600"
stroke-width="5"
d="m 33.308,74.729 c -0.042,0.027 -0.083,0.059 -0.13,0.081 -0.214,0.123 -0.457,0.19 -0.7,0.19 -0.23,0 -0.453,-0.058 -0.66,-0.176 C 31.47,74.629 23.18,69.882 15.068,60.131 7.58,51.118 -1.1,35.978 0.115,15.028 0.151,14.418 0.6,13.906 1.209,13.784 18.102,10.444 31.131,0.906 31.676,0.5 31.695,0.486 31.717,0.467 31.741,0.453 l 0.334,-0.221 c 0.486,-0.325 1.132,-0.308 1.599,0.05 0.128,0.1 13.13,9.919 30.109,13.276 0.61,0.118 1.058,0.633 1.096,1.244 2.3,39.737 -28.873,58.393 -31.571,59.927"
transform="translate(3,4)"
id="path2" />
<path
fill="#ff8600"
d="M 18.5,19 15.255,25.255 8,26.257 13.25,31.126 12.011,38 18.5,34.754 24.989,38 23.75,31.126 29,26.257 21.745,25.255 Z m 27,0 -3.245,6.255 L 35,26.257 40.25,31.126 39.011,38 45.5,34.754 51.989,38 50.75,31.126 56,26.257 48.745,25.255 Z"
transform="translate(3,4)"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="30"
height="30"
viewBox="0 0 30 30"
version="1.1"
id="svg12"
sodipodi:docname="timer.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="defs16" />
<sodipodi:namedview
id="namedview14"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
width="30px"
inkscape:zoom="4.4090909"
inkscape:cx="84.938144"
inkscape:cy="99"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
<g
fill="none"
fill-rule="evenodd"
id="g10"
transform="matrix(0.15097165,0,0,0.15318627,2.0162868,0)">
<g
fill="#ff5e00"
id="g8">
<path
d="M 45.544,46.242 36.54,33.206 c -1.61,-2.33 -4.76,-2.88 -7.032,-1.23 l -13.375,9.71 c -2.275,1.65 -2.811,4.88 -1.202,7.209 l 9.08,13.153 m 114.27,0 8.85,-11.353 c 1.603,-2.058 1.069,-4.909 -1.201,-6.37 L 132.59,35.74 c -2.267,-1.456 -5.407,-0.97 -7.011,1.09 l -9.067,11.629 M 93.498,38.78 v -4.83 c 0,-3.089 2.668,-5.619 5.928,-5.619 h 3.27 c 3.263,0 5.932,-2.53 5.932,-5.618 V 5.623 C 108.628,2.53 105.959,0 102.695,0 H 59.355 C 56.097,0 53.43,2.53 53.43,5.622 v 17.09 c 0,3.089 2.667,5.62 5.925,5.62 h 3.275 c 3.261,0 5.929,2.53 5.929,5.619 v 4.83"
transform="translate(3)"
id="path2" />
<path
fill-rule="nonzero"
d="m 83,32.963 c -45.726,0 -82.796,36.462 -82.796,81.439 0,44.976 37.07,81.438 82.798,81.438 45.727,0 82.796,-36.462 82.796,-81.438 0,-44.977 -37.07,-81.439 -82.796,-81.439 z m 0,11.634 c 39.195,0 70.97,31.253 70.97,69.805 0,38.55 -31.775,69.804 -70.97,69.804 -39.195,0 -70.97,-31.253 -70.97,-69.804 C 12.03,75.85 43.805,44.597 83,44.597 Z"
transform="translate(3)"
id="path4" />
<path
d="m 83.001,54.292 c -0.165,0 -0.327,0.015 -0.487,0.015 v 59.615 H 21.9 c -0.003,0.157 -0.012,0.316 -0.012,0.481 0,32.985 27.153,59.838 60.626,60.099 0.16,0 0.322,0.009 0.487,0.009 33.695,0 61.111,-26.96 61.111,-60.108 0,-0.165 -0.011,-0.324 -0.011,-0.481 -0.265,-32.921 -27.568,-59.63 -61.1,-59.63 z"
transform="translate(3)"
id="path6" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="menu_imdn_info.png.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">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="40"
inkscape:cy="40.045819"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="80"
height="80"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
"
id="image10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -4,9 +4,9 @@
<svg
version="1.1"
id="svg2"
width="15"
height="15"
viewBox="0 0 15 15"
width="172"
height="172"
viewBox="0 0 172 172"
sodipodi:docname="menu_infos.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@ -25,27 +25,54 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.270588"
inkscape:cx="42.402636"
inkscape:cy="42.500001"
inkscape:zoom="5.0755814"
inkscape:cx="86"
inkscape:cy="86"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8"
width="15px" />
inkscape:current-layer="g8" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="15"
height="15"
width="172"
height="172"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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 "
id="image10"
x="0"
y="0" />
xlink:href="data:image/png;base64,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
"
id="image10" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -1,61 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg12"
sodipodi:docname="menu_infos2.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="defs16" />
<sodipodi:namedview
id="namedview14"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.151163"
inkscape:cx="42.999999"
inkscape:cy="43.09851"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg12"
width="15px" />
<g
fill="none"
fill-rule="evenodd"
id="g10"
transform="matrix(0.17647011,0,0,0.17647155,-0.08823505,-0.08823577)">
<g
transform="translate(3,3)"
id="g8">
<circle
cx="40"
cy="40"
r="40"
stroke="#444444"
stroke-width="5"
id="circle2" />
<text
fill="#444444"
font-family="Baskerville-Bold, Baskerville"
font-size="65px"
font-weight="bold"
id="text6"><tspan
x="29"
y="61"
id="tspan4">i</tspan></text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,287 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg2"
width="229.33333"
height="229.33333"
viewBox="0 0 229.33333 229.33333"
sodipodi:docname="menu_infos_selected.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">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="3.8066861"
inkscape:cx="114.66666"
inkscape:cy="114.66666"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="229.33333"
height="229.33333"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
j7t3gFAtMs1qGwc03TYTsaiYSq+KgVcEMIQ+9GJYZpYxJ0lxeI6ve/j4ehfhWd7n/hxdasZigE8k
nmWGaRNvEE9v2gbnfeIQy8sq8TnxmEkXJH7kulLnN845lwWeGTKTiXniELGYa2GlhVne1IiniMOq
plO+kKqzynmLs1Yss8Y9+QuDGX1lmes0BxHDIpYgQYSCMgoowkaEVp0UCwnaj3r4B1y/RC6FXAUw
ciygBA2y6wf/g9/dWtnJiXpSMAq0vzjOxwgQ2AVqFcf5Pnac2gngfwau9Ka/VAVmPkmvNLXwEdC9
DVxcNzVlD7jcAfqfDNmUXclPU8hmgfcz+qY00HMLdK7Ve2vs4/QBSFJX8Rvg4BAYzVH2use7O1p7
+/dMo78fjEFyseG6Eu8AAA0aaVRYdFhNTDpjb20uYWRvYmUueG1wAAAAAAA8P3hwYWNrZXQgYmVn
aW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/Pgo8eDp4bXBtZXRhIHhtbG5z
Ong9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA0LjQuMC1FeGl2MiI+CiA8cmRm
OlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1u
cyMiPgogIDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiCiAgICB4bWxuczp4bXBNTT0iaHR0
cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIKICAgIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMu
YWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiCiAgICB4bWxuczpkYz0iaHR0
cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICB4bWxuczpHSU1QPSJodHRwOi8vd3d3
LmdpbXAub3JnL3htcC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYv
MS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgeG1w
TU06RG9jdW1lbnRJRD0iZ2ltcDpkb2NpZDpnaW1wOjJlM2NkYjk1LWQ1YmItNDk3My1hZTA3LTM4
OWM2NDgzZWQzYSIKICAgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDphZGE1NDI0NC02YjQzLTRk
M2QtYTBkOS1kOTM5MGRmMDlmN2IiCiAgIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRp
ZDozYzRhMjRjNy1mYTE4LTRmNzItOTVmNS0zMmQ1NDQ2MDcwMDAiCiAgIGRjOkZvcm1hdD0iaW1h
Z2UvcG5nIgogICBHSU1QOkFQST0iMi4wIgogICBHSU1QOlBsYXRmb3JtPSJMaW51eCIKICAgR0lN
UDpUaW1lU3RhbXA9IjE2Mjc2ODc0NjMyNDgxMjEiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4yNCIK
ICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiPgog
ICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6
YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFu
Y2VJRD0ieG1wLmlpZDoxYmJlOGJkNS1lMTFhLTRlZDYtYmZkZC1lZTA0YzUzZDJhMTQiCiAgICAg
IHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoTGludXgpIgogICAgICBzdEV2dDp3aGVu
PSIyMDIxLTA3LTMxVDAxOjI0OjIzKzAyOjAwIi8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06
SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAK
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg
ICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFj
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
gYT+B8frjb0gfwB5AAAAAElFTkSuQmCC
"
id="image10" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -15,6 +15,7 @@
<file>assets/images/add_participant_hovered.svg</file>
<file>assets/images/add_participant_normal.svg</file>
<file>assets/images/add_participant_pressed.svg</file>
<file>assets/images/admin_selected.svg</file>
<file>assets/images/attachment_disabled.svg</file>
<file>assets/images/attachment_hovered.svg</file>
<file>assets/images/attachment_normal.svg</file>
@ -145,12 +146,18 @@
<file>assets/images/led_orange.svg</file>
<file>assets/images/led_red.svg</file>
<file>assets/images/led_white.svg</file>
<file>assets/images/menu_copy_text.svg</file>
<file>assets/images/menu_delete.svg</file>
<file>assets/images/menu_imdn_info.svg</file>
<file>assets/images/menu_vdots_normal.svg</file>
<file>assets/images/menu_vdots_hovered.svg</file>
<file>assets/images/menu_vdots_pressed.svg</file>
<file>assets/images/menu_infos.svg</file>
<file>assets/images/menu_infos_selected.svg</file>
<file>assets/images/menu_devices.svg</file>
<file>assets/images/menu_devices_selected.svg</file>
<file>assets/images/menu_ephemeral.svg</file>
<file>assets/images/menu_ephemeral_selected.svg</file>
<file>assets/images/message_sign.svg</file>
<file>assets/images/micro_off_hovered.svg</file>
<file>assets/images/micro_off_normal.svg</file>
@ -439,6 +446,7 @@
<file>ui/modules/Linphone/Styles/TelKeypad/TelKeypadStyle.qml</file>
<file>ui/modules/Linphone/Styles/Timeline/TimelineStyle.qml</file>
<file>ui/modules/Linphone/Styles/View/SipAddressesViewStyle.qml</file>
<file>ui/modules/Linphone/Styles/View/ParticipantsViewStyle.qml</file>
<file>ui/modules/Linphone/TelKeypad/TelKeypadButton.qml</file>
<file>ui/modules/Linphone/TelKeypad/TelKeypad.js</file>
<file>ui/modules/Linphone/TelKeypad/TelKeypad.qml</file>
@ -541,6 +549,7 @@
<file>ui/views/App/Styles/Main/ConversationStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/AboutStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/AuthenticationRequestStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/InfoChatRoomStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/InfoEncryptionStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/ManageAccountsStyle.qml</file>
<file>ui/views/App/Styles/Main/HomeStyle.qml</file>

View file

@ -352,7 +352,13 @@ int ChatRoomModel::getSecurityLevel() const{
bool ChatRoomModel::isGroupEnabled() const{
return mChatRoom && mChatRoom->getCurrentParams()->groupEnabled();
}
bool ChatRoomModel::isMeAdmin() const{
return mChatRoom->getMe()->isAdmin();
}
bool ChatRoomModel::canHandleParticipants() const{
return mChatRoom->canHandleParticipants();
}
/*
bool ChatRoomModel::getIsRemoteComposing () const {
return mIsRemoteComposing;
@ -687,7 +693,7 @@ void ChatRoomModel::onChatMessageSent(const std::shared_ptr<linphone::ChatRoom>
void ChatRoomModel::onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
auto events = chatRoom->getHistoryEvents(0);
auto e = std::find(events.begin(), events.end(), eventLog);
if( e == events.end() )
if( e != events.end() )
insertNotice(*e);
emit participantAdded(chatRoom, eventLog);
emit fullPeerAddressChanged();
@ -704,6 +710,7 @@ void ChatRoomModel::onParticipantRemoved(const std::shared_ptr<linphone::ChatRoo
void ChatRoomModel::onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
emit participantAdminStatusChanged(chatRoom, eventLog);
emit isMeAdminChanged(); // It is not the case all the time but calling getters is not a heavy request
}
void ChatRoomModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){

View file

@ -65,6 +65,8 @@ public:
Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(bool groupEnabled READ isGroupEnabled NOTIFY groupEnabledChanged)
Q_PROPERTY(bool haveEncryption READ haveEncryption CONSTANT)
Q_PROPERTY(bool isMeAdmin READ isMeAdmin NOTIFY isMeAdminChanged)
Q_PROPERTY(bool canHandleParticipants READ canHandleParticipants CONSTANT)
//Q_PROPERTY(bool isComposing MEMBER mIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
@ -120,11 +122,13 @@ public:
Q_INVOKABLE bool isSecure() const;
int getSecurityLevel() const;
bool isGroupEnabled() const;
bool isMeAdmin() const;
bool canHandleParticipants() const;
bool getIsRemoteComposing () const;
ParticipantListModel* getParticipants() const;
std::shared_ptr<linphone::ChatRoom> getChatRoom();
QList<QString> getComposers();
//---- Setters
void setLastUpdateTime(const QDateTime& lastUpdateDate);
@ -209,6 +213,7 @@ signals:
void securityLevelChanged(int securityLevel);
void groupEnabledChanged(bool groupEnabled);
void isMeAdminChanged();
void stateChanged(int state);
void hasBeenLeftChanged();
void ephemeralEnabledChanged();

View file

@ -61,17 +61,17 @@ class Colors : public QObject {
// Primary color for hovered items.
ADD_COLOR(b, "#D64D00")
ADD_COLOR(c, "#CBCBCB")
ADD_COLOR(c, "#CBCBCB") // Button pressed / separators / fields
ADD_COLOR(d, "#5A585B")
ADD_COLOR(e, "#F3F3F3")
ADD_COLOR(f, "#E8E8E8")
ADD_COLOR(g, "#6B7A86")// SipAddress
ADD_COLOR(g, "#6B7A86")// SipAddress / Contact Text
ADD_COLOR(h, "#687680")
// Primary color.
ADD_COLOR(i, "#FE5E00")
ADD_COLOR(j, "#4B5964")// Username
ADD_COLOR(j, "#4B5964")// Username, Background cancel button hovered
// Popups, home, call, assistant and settings background.
ADD_COLOR(k, "#FFFFFF")
@ -82,7 +82,7 @@ class Colors : public QObject {
ADD_COLOR(m, "#FF8600")
ADD_COLOR(n, "#A1A1A1")
ADD_COLOR(o, "#D0D8DE")
ADD_COLOR(o, "#D0D8DE")// Disabled button
// Progress bar.
ADD_COLOR(p, "#17A81A")
@ -90,9 +90,14 @@ class Colors : public QObject {
// Fields, backgrounds and text color on some items.
ADD_COLOR(q, "#FFFFFF")
ADD_COLOR(r, "#909fab")//Background button
ADD_COLOR(r, "#909fab")//Background button normal
ADD_COLOR(s, "#96be64")// Security
ADD_COLOR(t, "#C2C2C2")// Title Header
ADD_COLOR(u, "#D2D2D2")// Menu border (message)
ADD_COLOR(v, "#E7E7E7")// Menu pressed (message)
ADD_COLOR(w, "#EDEDED")// Menu background (conversation)
// Field error.
ADD_COLOR(error, "#FF0000")
@ -130,7 +135,11 @@ signals:
void colorTqChanged (const QColor &color);
void colorTrChanged (const QColor &color);
void colorTsChanged (const QColor &color);
void colorTtChanged (const QColor &color);
void colorTuChanged (const QColor &color);
void colorTvChanged (const QColor &color);
void colorTwChanged (const QColor &color);
void colorTerrorChanged (const QColor &color);
private:

View file

@ -177,27 +177,43 @@ void ParticipantListModel::updateParticipants () {
while(itParticipant != mParticipants.end()) {
auto itDbParticipant = dbParticipants.begin();
while(itDbParticipant != dbParticipants.end()
&& !(*itDbParticipant)->getAddress()->weakEqual((*itParticipant)->getParticipant()->getAddress())){
&& ((*itParticipant)->getParticipant() && !(*itDbParticipant)->getAddress()->weakEqual((*itParticipant)->getParticipant()->getAddress())
|| !(*itParticipant)->getParticipant() && !(*itDbParticipant)->getAddress()->weakEqual(Utils::interpretUrl((*itParticipant)->getSipAddress()))
)
){
++itDbParticipant;
}
if( itDbParticipant == dbParticipants.end()){
int row = itParticipant - mParticipants.begin();
beginRemoveRows(QModelIndex(), row, row);
itParticipant = mParticipants.erase(itParticipant);
endRemoveRows();
changed = true;
}else
++itParticipant;
}
// Add new
for(auto dbParticipant : dbParticipants){
auto itParticipant = mParticipants.begin();
while(itParticipant != mParticipants.end() && !dbParticipant->getAddress()->weakEqual((*itParticipant)->getParticipant()->getAddress())){
auto itParticipant = mParticipants.begin();
while(itParticipant != mParticipants.end() && ( (*itParticipant)->getParticipant() && !dbParticipant->getAddress()->weakEqual((*itParticipant)->getParticipant()->getAddress())
|| (!(*itParticipant)->getParticipant() && !dbParticipant->getAddress()->weakEqual(Utils::interpretUrl((*itParticipant)->getSipAddress())))
)
){
++itParticipant;
}
if( itParticipant == mParticipants.end()){
auto participant = std::make_shared<ParticipantModel>(dbParticipant);
connect(this, &ParticipantListModel::deviceSecurityLevelChanged, participant.get(), &ParticipantModel::onDeviceSecurityLevelChanged);
connect(this, &ParticipantListModel::securityLevelChanged, participant.get(), &ParticipantModel::onSecurityLevelChanged);
connect(participant.get(),&ParticipantModel::updateAdminStatus, this, &ParticipantListModel::setAdminStatus);
int row = mParticipants.count();
beginInsertRows(QModelIndex(), row, row);
mParticipants << participant;
endInsertRows();
changed = true;
}else if(!(*itParticipant)->getParticipant()){
(*itParticipant)->setParticipant(dbParticipant);
}
}
if( changed)
@ -249,6 +265,12 @@ const std::shared_ptr<ParticipantModel> ParticipantListModel::getParticipant(con
}
//-------------------------------------------------------------
void ParticipantListModel::setAdminStatus(const std::shared_ptr<linphone::Participant> participant, const bool& isAdmin){
mChatRoomModel->getChatRoom()->setParticipantAdminStatus(participant, isAdmin);
}
void ParticipantListModel::onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
auto address = eventLog->getParticipantAddress();
if(address) {

View file

@ -61,6 +61,8 @@ public:
public slots:
void setAdminStatus(const std::shared_ptr<linphone::Participant> participant, const bool& isAdmin);
void onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);

View file

@ -33,9 +33,10 @@ using namespace std;
ParticipantModel::ParticipantModel (shared_ptr<linphone::Participant> linphoneParticipant, QObject *parent) : QObject(parent) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mAdminStatus = false;
mParticipant = linphoneParticipant;
mAdminStatus = false;
if(mParticipant){
mAdminStatus = mParticipant->isAdmin();
mParticipantDevices = std::make_shared<ParticipantDeviceListModel>(mParticipant);
connect(this, &ParticipantModel::deviceSecurityLevelChanged, mParticipantDevices.get(), &ParticipantDeviceListModel::securityLevelChanged);
}
@ -55,6 +56,11 @@ int ParticipantModel::getDeviceCount() const{
return (mParticipant ? mParticipant->getDevices().size() : 0);
}
bool ParticipantModel::getInviting() const{
bool is = !mParticipant;
return is;
}
QString ParticipantModel::getSipAddress() const{
return (mParticipant ? Utils::coreStringToAppString(mParticipant->getAddress()->asString()) : mSipAddress);
}
@ -72,7 +78,6 @@ bool ParticipantModel::isFocus() const{
return (mParticipant ? mParticipant->isFocus() : false);
}
//------------------------------------------------------------------------
void ParticipantModel::setSipAddress(const QString& address){
@ -85,10 +90,22 @@ void ParticipantModel::setSipAddress(const QString& address){
void ParticipantModel::setAdminStatus(const bool& status){
if(status != mAdminStatus){
mAdminStatus = status;
emit adminStatusChanged();
if(mParticipant)
emit updateAdminStatus(mParticipant, mAdminStatus);
else
emit adminStatusChanged();
}
}
void ParticipantModel::setParticipant(std::shared_ptr<linphone::Participant> participant){
mParticipant = participant;
if(mParticipant){
mAdminStatus = mParticipant->isAdmin();
mParticipantDevices = std::make_shared<ParticipantDeviceListModel>(mParticipant);
connect(this, &ParticipantModel::deviceSecurityLevelChanged, mParticipantDevices.get(), &ParticipantDeviceListModel::securityLevelChanged);
}
emit invitingChanged();
}
//------------------------------------------------------------------------
void ParticipantModel::onSecurityLevelChanged(){

View file

@ -45,6 +45,8 @@ public:
Q_PROPERTY(bool focus READ isFocus CONSTANT)
Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged)
Q_PROPERTY(bool inviting READ getInviting NOTIFY invitingChanged)
ContactModel *getContactModel() const;
QString getSipAddress() const;
@ -54,9 +56,11 @@ public:
bool isFocus() const;
int getSecurityLevel() const;
int getDeviceCount() const;
bool getInviting() const;
void setSipAddress(const QString& address);
void setAdminStatus(const bool& status);
void setParticipant(std::shared_ptr<linphone::Participant> participant);
std::shared_ptr<linphone::Participant> getParticipant();
Q_INVOKABLE ParticipantDeviceProxyModel * getProxyDevices();
@ -74,8 +78,10 @@ signals:
void securityLevelChanged();
void deviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void sipAddressChanged();
void updateAdminStatus(const std::shared_ptr<linphone::Participant> participant, const bool& isAdmin);// Split in two signals in order to sequancialize execution between SDK and GUI
void adminStatusChanged();
void deviceCountChanged();
void invitingChanged();
// void contactUpdated ();

View file

@ -83,15 +83,20 @@ void ParticipantProxyModel::setChatRoomModel(ChatRoomModel * chatRoomModel){
void ParticipantProxyModel::add(const QString& address){
ParticipantListModel * participantsModel = dynamic_cast<ParticipantListModel*>(sourceModel());
if(!participantsModel->contains(address)){
std::shared_ptr<ParticipantModel> participant = std::make_shared<ParticipantModel>(nullptr);
std::shared_ptr<ParticipantModel> participant = std::make_shared<ParticipantModel>(nullptr);
participant->setSipAddress(address);
participantsModel->add(participant);
if(mChatRoomModel && mChatRoomModel->getChatRoom())// Invite and wait for its creation
mChatRoomModel->getChatRoom()->addParticipant(Utils::interpretUrl(address));
}
}
void ParticipantProxyModel::remove(ParticipantModel * participant){
if(participant)
dynamic_cast<ParticipantListModel*>(sourceModel())->remove(participant);
if(participant) {
if(mChatRoomModel && mChatRoomModel->getChatRoom() && participant->getParticipant() )
mChatRoomModel->getChatRoom()->removeParticipant(participant->getParticipant());
//dynamic_cast<ParticipantListModel*>(sourceModel())->remove(participant);
}
}
// -----------------------------------------------------------------------------

View file

@ -78,7 +78,10 @@ bool Utils::hasCapability(const QString& address, const LinphoneEnums::FriendCap
}
QString Utils::toDateTimeString(QDateTime date){
return date.toString("yyyy/MM/dd hh:mm:ss");
if(date.date() == QDate::currentDate())
return toTimeString(date);
else
return date.toString("yyyy/MM/dd hh:mm:ss");
}
QString Utils::toTimeString(QDateTime date){

View file

@ -17,6 +17,17 @@ Rectangle {
property int buttonsAlignment : Qt.AlignLeft
property bool flat : false // Remove margins
property alias showCloseCross : titleBar.showCloseCross
property int buttonsLeftMargin :(buttonsAlignment & Qt.AlignLeft )== Qt.AlignLeft
? DialogStyle.buttons.leftMargin
: (buttonsAlignment & Qt.AlignRight) == Qt.AlignRight
? DialogStyle.buttons.rightMargin
: DialogStyle.buttons.leftMargin
property int buttonsRightMargin : (buttonsAlignment & Qt.AlignRight )== Qt.AlignRight
? DialogStyle.buttons.rightMargin
: (buttonsAlignment & Qt.AlignLeft) == Qt.AlignLeft
? DialogStyle.buttons.leftMargin
: DialogStyle.buttons.rightMargin
default property alias _content: content.data
property bool _disableExitStatus
@ -90,12 +101,8 @@ Rectangle {
Layout.alignment: buttonsAlignment
Layout.bottomMargin: DialogStyle.buttons.bottomMargin
Layout.leftMargin: (buttonsAlignment & Qt.AlignLeft )== Qt.AlignLeft
? DialogStyle.buttons.leftMargin
: (buttonsAlignment & Qt.AlignRight) == Qt.AlignRight
? DialogStyle.buttons.rightMargin
: DialogStyle.buttons.leftMargin
Layout.rightMargin: DialogStyle.buttons.rightMargin
Layout.leftMargin: buttonsLeftMargin
Layout.rightMargin: buttonsRightMargin
Layout.topMargin: DialogStyle.buttons.topMargin
spacing: DialogStyle.buttons.spacing
visible: children.length>0

View file

@ -19,9 +19,15 @@ Item {
property color textColorHovered: textColorNormal
property color textColorNormal
property color textColorPressed: textColorNormal
property color borderColorDisabled
property color borderColorHovered
property color borderColorNormal
property color borderColorPressed
property alias text: button.text
property bool enabled: true
property bool showBorder : false
signal clicked
@ -36,6 +42,16 @@ Item {
? colorPressed
: (button.hovered ? colorHovered : colorNormal)
}
function _getBorderColor () {
if (!wrappedButton.enabled) {
return borderColorDisabled
}
return button.down
? borderColorPressed
: (button.hovered ? borderColorHovered : borderColorNormal)
}
function _getTextColor () {
if (!wrappedButton.enabled) {
@ -60,6 +76,8 @@ Item {
background: Rectangle {
color: _getBackgroundColor()
radius: AbstractTextButtonStyle.background.radius
border.color: _getBorderColor()
border.width: (showBorder ? 1 : 0)
}
contentItem: Text {

View file

@ -3,13 +3,20 @@ import Common.Styles 1.0
// =============================================================================
AbstractTextButton {
colorDisabled: TextButtonAStyle.backgroundColor.disabled
colorHovered: TextButtonAStyle.backgroundColor.hovered
colorNormal: TextButtonAStyle.backgroundColor.normal
colorPressed: TextButtonAStyle.backgroundColor.pressed
textColorDisabled: TextButtonAStyle.textColor.disabled
textColorHovered: TextButtonAStyle.textColor.hovered
textColorNormal: TextButtonAStyle.textColor.normal
textColorPressed: TextButtonAStyle.textColor.pressed
property var textButtonStyle : TextButtonAStyle
colorDisabled: textButtonStyle.backgroundColor.disabled
colorHovered: textButtonStyle.backgroundColor.hovered
colorNormal: textButtonStyle.backgroundColor.normal
colorPressed: textButtonStyle.backgroundColor.pressed
textColorDisabled: textButtonStyle.textColor.disabled
textColorHovered: textButtonStyle.textColor.hovered
textColorNormal: textButtonStyle.textColor.normal
textColorPressed: textButtonStyle.textColor.pressed
borderColorDisabled: textButtonStyle.borderColor.disabled
borderColorHovered: textButtonStyle.borderColor.hovered
borderColorNormal: textButtonStyle.borderColor.normal
borderColorPressed: textButtonStyle.borderColor.pressed
}

View file

@ -14,4 +14,9 @@ AbstractTextButton {
textColorHovered: textButtonStyle.textColor.hovered
textColorNormal: textButtonStyle.textColor.normal
textColorPressed: textButtonStyle.textColor.pressed
borderColorDisabled: textButtonStyle.borderColor.disabled
borderColorHovered: textButtonStyle.borderColor.hovered
borderColorNormal: textButtonStyle.borderColor.normal
borderColorPressed: textButtonStyle.borderColor.pressed
}

View file

@ -85,6 +85,7 @@ Item {
}
// Record audio
ActionButton {
visible:false // TODO
id: recordAudioButton
//anchors.verticalCenter: parent.verticalCenter

View file

@ -8,14 +8,21 @@ import Common.Styles 1.0
Controls.Menu {
id: menu
property var menuStyle : MenuStyle.normal
background: Rectangle {
implicitWidth: MenuStyle.width
color: MenuStyle.color
implicitWidth: menuStyle.width
color: menuStyle.color
radius: menuStyle.radius
border{
color:menuStyle.border.color
width: menuStyle.border.width
}
layer {
enabled: true
enabled: menuStyle.shadowEnabled
effect: PopupShadow {}
}
}
}
}

View file

@ -1,5 +1,6 @@
import QtQuick 2.7
import QtQuick.Controls 2.2 as Controls
import QtQuick.Layouts 1.3
import Common 1.0
@ -14,48 +15,76 @@ Controls.MenuItem {
id: button
property alias iconMenu : iconArea.icon
property alias iconSizeMenu : iconArea.iconSize
property alias iconLayoutDirection : rowArea.layoutDirection
property var menuItemStyle : MenuItemStyle.normal
background: Rectangle {
property alias textWeight : rowText.font.bold
property int offsetTopMargin : 0
property int offsetBottomMargin : 0
height:visible?undefined:0
background: Rectangle {
color: button.down
? MenuItemStyle.background.color.pressed
? menuItemStyle.background.color.pressed
: (
button.hovered
? MenuItemStyle.background.color.hovered
: MenuItemStyle.background.color.normal
? menuItemStyle.background.color.hovered
: menuItemStyle.background.color.normal
)
implicitHeight: MenuItemStyle.background.height
implicitHeight: button.menuItemStyle.background.height
}
contentItem:Row{
leftPadding: MenuItemStyle.leftPadding
rightPadding: MenuItemStyle.rightPadding
contentItem:RowLayout{
id:rowArea
spacing:20
Icon{
id: iconArea
visible: icon
width: icon?iconSize:0
Layout.leftMargin:(iconLayoutDirection == Qt.LeftToRight ? menuItemStyle.leftMargin : 0)
Layout.rightMargin:(iconLayoutDirection == Qt.LeftToRight ? 0 : menuItemStyle.rightMargin)
}
Text {
id:rowText
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin:(iconLayoutDirection == Qt.LeftToRight ? 0 : menuItemStyle.leftMargin)
Layout.rightMargin:(iconLayoutDirection == Qt.LeftToRight ? menuItemStyle.rightMargin : 0)
color: button.enabled
? MenuItemStyle.text.color.enabled
: MenuItemStyle.text.color.disabled
? (button.down
? menuItemStyle.text.color.pressed
: (
button.hovered
? menuItemStyle.text.color.hovered
: menuItemStyle.text.color.normal
))
: menuItemStyle.text.color.disabled
elide: Text.ElideRight
font {
bold: true
pointSize: MenuItemStyle.text.pointSize
weight: menuItemStyle.text.weight
pointSize: menuItemStyle.text.pointSize
}
text: button.text
//leftPadding: MenuItemStyle.leftPadding
//rightPadding: MenuItemStyle.rightPadding
//leftPadding: menuItemStyle.leftPadding
//rightPadding: menuItemStyle.rightPadding
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
anchors.top: parent.top
anchors.bottom : parent.bottom
//anchors.top: parent.top
//anchors.bottom : parent.bottom
}
}
hoverEnabled: true
MouseArea{
anchors.fill:parent
propagateComposedEvents:true
acceptedButtons: Qt.NoButton
cursorShape: parent.hovered
? Qt.PointingHandCursor
: Qt.ArrowCursor
}
}

View file

@ -6,17 +6,18 @@ import Colors 1.0
// =============================================================================
QtObject {
property QtObject backgroundColor: QtObject {
property color disabled: Colors.o
property color hovered: Colors.j
property color normal: Colors.r
property color pressed: Colors.i
}
property QtObject textColor: QtObject {
property color disabled: Colors.q
property color hovered: Colors.q
property color normal: Colors.q
property color pressed: Colors.q
}
property QtObject backgroundColor: QtObject {
property color disabled: Colors.o
property color hovered: Colors.j
property color normal: Colors.r
property color pressed: Colors.i
}
property QtObject textColor: QtObject {
property color disabled: Colors.q
property color hovered: Colors.q
property color normal: Colors.q
property color pressed: Colors.q
}
property QtObject borderColor : backgroundColor
}

View file

@ -20,4 +20,5 @@ QtObject {
property color normal: Colors.q
property color pressed: Colors.q
}
property QtObject borderColor : backgroundColor
}

View file

@ -1,5 +1,6 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.3
import Colors 1.0
import Units 1.0
@ -7,25 +8,108 @@ import Units 1.0
// =============================================================================
QtObject {
property int leftPadding: 5
property int rightPadding: 5
property QtObject background: QtObject {
property int height: 30
property QtObject color: QtObject {
property color hovered: Colors.o
property color normal: Colors.q
property color pressed: Colors.o
}
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property QtObject color: QtObject {
property color enabled: Colors.j
property color disabled: Colors.l50
}
}
property QtObject normal : QtObject{
property int leftMargin: 5
property int rightMargin: 5
property QtObject background: QtObject {
property int height: 30
property QtObject color: QtObject {
property color hovered: Colors.o
property color normal: Colors.q
property color pressed: Colors.o
}
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property int weight : Font.Bold
property QtObject color: QtObject {
property color hovered: Colors.j
property color normal: Colors.j
property color pressed: Colors.j
property color disabled: Colors.l50
}
}
}
property QtObject aux : QtObject{
property int leftMargin: 10
property int rightMargin: 10
property QtObject background: QtObject {
property int height: 40
property QtObject color: QtObject {
property color hovered: Colors.v
property color normal: Colors.a
property color pressed: Colors.v
}
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property int weight : Font.Normal
property QtObject color: QtObject {
property color hovered: Colors.j
property color normal: Colors.j
property color pressed: Colors.j
property color disabled: Colors.l50
}
}
}
property QtObject auxRed : QtObject{
property int leftMargin: 10
property int rightMargin: 10
property QtObject background: QtObject {
property int height: 40
property QtObject color: QtObject {
property color hovered: Colors.v
property color normal: Colors.a
property color pressed: Colors.v
}
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 10
property int weight : Font.Normal
property QtObject color: QtObject {
property color hovered: Colors.error
property color normal: Colors.error
property color pressed: Colors.error
property color disabled: Colors.l50
}
}
}
property QtObject aux2 : QtObject{
property int leftMargin: 10
property int rightMargin: 10
property QtObject background: QtObject {
property int height: 50
property QtObject color: QtObject {
property color hovered: Colors.w
property color normal: Colors.w
property color pressed: Colors.w
}
}
property QtObject text: QtObject {
property int pointSize: Units.dp * 11
property int weight : Font.Normal
property QtObject color: QtObject {
property color hovered: Colors.m
property color normal: Colors.j
property color pressed: Colors.m
property color disabled: Colors.l50
}
}
}
}

View file

@ -6,6 +6,37 @@ import Colors 1.0
// =============================================================================
QtObject {
property color color: Colors.q
property int width: 130
property QtObject normal : QtObject {
property color color: Colors.q
property int width: 130
property bool shadowEnabled: true
property int radius : 0
property QtObject border : QtObject {
property color color: Colors.u
property int width: 0
}
}
property QtObject aux : QtObject {
property color color: Colors.q
property int width: 200
property bool shadowEnabled: false
property int radius : 5
property QtObject border : QtObject {
property color color: Colors.u
property int width: 1
}
}
property QtObject aux2 : QtObject {
property color color: Colors.q
property int width: 250
property bool shadowEnabled: false
property int radius : 0
property QtObject border : QtObject {
property color color: Colors.u
property int width: 0
}
}
}

View file

@ -31,16 +31,16 @@ Core.ToolTip {
}
function _getRelativeXArrowCenter () {
return tooltip.parent.width / 2 - icon.width / 2
return (tooltip.parent ? tooltip.parent.width / 2 - icon.width / 2 : 0)
}
function _getRelativeYArrowCenter () {
return tooltip.parent.height / 2 - icon.height / 2
return (tooltip.parent ? tooltip.parent.height / 2 - icon.height / 2 : 0)
}
function _setArrowEdge () {
var a = container.mapToItem(null, 0, 0)
var b = tooltip.parent.mapToItem(null, 0, 0)
var b = (tooltip.parent ?tooltip.parent.mapToItem(null, 0, 0) : {x:0,y:0})
if (a.x + container.width < b.x) {
_edge = 'left'
@ -59,7 +59,7 @@ Core.ToolTip {
// Called when new image is loaded. (When the is edge is updated.)
function _setArrowPosition () {
var a = container.mapToItem(null, 0, 0)
var b = tooltip.parent.mapToItem(null, 0, 0)
var b = (tooltip.parent ?tooltip.parent.mapToItem(null, 0, 0) : {x:0,y:0})
if (_edge === 'left') {
icon.x = container.width - TooltipStyle.margins - _getArrowWidthMargin()

View file

@ -3,11 +3,13 @@ import QtQuick.Layouts 1.3
import Clipboard 1.0
import Common 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 'Message.js' as Logic
@ -102,24 +104,44 @@ Item {
Menu {
id: messageMenu
menuStyle : MenuStyle.aux
MenuItem {
text: qsTr('menuCopy')
iconMenu: 'menu_copy_text'
iconSizeMenu: 17
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
onTriggered: Clipboard.text = $chatEntry.content
}
MenuItem {
enabled: TextToSpeech.available
text: qsTr('menuPlayMe')
iconMenu: 'speaker'
iconSizeMenu: 17
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
onTriggered: TextToSpeech.say($chatEntry.content)
}
MenuItem {
text: 'Delivery Status'
iconMenu: 'menu_imdn_info'
iconSizeMenu: 17
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.aux
visible: deliveryLayout.model.rowCount() > 0
onTriggered: deliveryLayout.visible = !deliveryLayout.visible
}
MenuItem {
text: 'Delete'
iconMenu: 'menu_delete'
iconSizeMenu: 17
iconLayoutDirection: Qt.RightToLeft
menuItemStyle : MenuItemStyle.auxRed
onTriggered: deliveryLayout.visible = !deliveryLayout.visible
}
}
// Handle hovered link.
@ -169,10 +191,27 @@ Item {
}
}*/
model: $chatEntry.getProxyImdnStates()
property var i18n: [
'Envoyé à %1 - %2', // LinphoneEnums.ChatMessageStateDelivered
'Reçu par %1 - %2', // LinphoneEnums.ChatMessageStateDeliveredToUser
'Lu par %1 - %2' , // LinphoneEnums.ChatMessageStateDisplayed
"%1 n'a encore rien reçu" // LinphoneEnums.ChatMessageStateNotDelivered
]
function getText(state){
if(state == LinphoneEnums.ChatMessageStateDelivered)
return i18n[0]
else if(state == LinphoneEnums.ChatMessageStateDeliveredToUser)
return i18n[1]
else if(state == LinphoneEnums.ChatMessageStateDisplayed)
return i18n[2]
else if(state == LinphoneEnums.ChatMessageStateNotDelivered)
return i18n[3]
else return ''
}
delegate:Text{
height:ChatStyle.composingText.height-5
width:parent.width
text:'Vu par %1 le %2'.arg(modelData.displayName).arg(UtilsCpp.toDateTimeString(modelData.stateChangeTime))
text:deliveryLayout.getText(modelData.state).arg(modelData.displayName).arg(UtilsCpp.toDateTimeString(modelData.stateChangeTime))
color:"#B1B1B1"
font.pointSize: Units.dp * 8
elide: Text.ElideMiddle

View file

@ -18,6 +18,7 @@ Rectangle {
property alias sipAddressColor: description.sipAddressColor
property alias usernameColor: description.usernameColor
property alias statusText : description.statusText
property bool displayUnreadMessageCount: false
property bool showContactAddress : true

View file

@ -9,11 +9,20 @@ import Common 1.0
Column {
property alias username: username.text
property string sipAddress
property alias statusText : status.text
property color sipAddressColor: ContactDescriptionStyle.sipAddress.color
property color usernameColor: ContactDescriptionStyle.username.color
property var contactDescriptionStyle : ContactDescriptionStyle
property color sipAddressColor: contactDescriptionStyle.sipAddress.color
property color usernameColor: contactDescriptionStyle.username.color
property int horizontalTextAlignment
property int contentWidth : Math.max(username.implicitWidth, address.implicitWidth)+10
property int contentWidth : Math.max(username.implicitWidth, address.implicitWidth)
+10
+statusWidth
property int contentHeight : Math.max(username.implicitHeight, address.implicitHeight)+10
readonly property int statusWidth : (status.visible ? status.width + 5 : 0)
// ---------------------------------------------------------------------------
@ -23,14 +32,25 @@ Column {
color: usernameColor
elide: Text.ElideRight
font.bold: true
font.pointSize: ContactDescriptionStyle.username.pointSize
font.weight: contactDescriptionStyle.username.weight
font.pointSize: contactDescriptionStyle.username.pointSize
horizontalAlignment: horizontalTextAlignment
verticalAlignment: (address.visible?Text.AlignBottom:Text.AlignVCenter)
width: parent.width
width: Math.min(parent.width-statusWidth, implicitWidth)
height: (parent.height-parent.topPadding-parent.bottomPadding)/parent.visibleChildren.length
//onTextChanged: console.log("username width: "+text+"=>"+contentWidth+"/"+width)
//onContentWidthChanged: console.log("usr : "+text+"=>"+contentWidth)
Text{
id:status
anchors.top:parent.top
anchors.bottom : parent.bottom
anchors.left:parent.right
anchors.leftMargin:5
verticalAlignment: Text.AlignVCenter
visible: text != ''
text : ''
color: contactDescriptionStyle.username.status.color
font.pointSize: contactDescriptionStyle.username.status.pointSize
font.italic : true
}
}
Text {
@ -38,14 +58,13 @@ Column {
text: SipAddressesModel.cleanSipAddress(sipAddress)
color: sipAddressColor
elide: Text.ElideRight
font.pointSize: ContactDescriptionStyle.sipAddress.pointSize
font.weight: contactDescriptionStyle.sipAddress.weight
font.pointSize: contactDescriptionStyle.sipAddress.pointSize
horizontalAlignment: horizontalTextAlignment
verticalAlignment: (username.visible?Text.AlignTop:Text.AlignVCenter)
width: parent.width
width: Math.min(parent.width-statusWidth, implicitWidth)
height: (parent.height-parent.topPadding-parent.bottomPadding)/parent.visibleChildren.length
visible: text != ''
//onTextChanged: console.log("address width: "+text+"=>"+contentWidth+"/"+width)
//onContentWidthChanged: console.log("addr : "+text+"=>"+contentWidth)
}
}

View file

@ -1,5 +1,6 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.7
import Colors 1.0
import Units 1.0
@ -7,13 +8,20 @@ import Units 1.0
// =============================================================================
QtObject {
property QtObject sipAddress: QtObject {
property color color: Colors.n
property int pointSize: Units.dp * 10
}
property QtObject username: QtObject {
property color color: Colors.j
property int pointSize: Units.dp * 11
}
property QtObject sipAddress: QtObject {
property color color: Colors.n
property int pointSize: Units.dp * 10
property int weight: Font.Normal
}
property QtObject username: QtObject {
property color color: Colors.j
property int pointSize: Units.dp * 11
property int weight: Font.Bold
property QtObject status : QtObject{
property color color : Colors.g
property int pointSize : Units.dp * 9
}
}
}

View file

@ -0,0 +1,17 @@
pragma Singleton
import QtQml 2.2
import Colors 1.0
import Units 1.0
// =============================================================================
QtObject {
property QtObject entry: QtObject {
property QtObject status: QtObject {
property color color : Colors.g
property int pointSize : Units.dp * 8
}
}
}

View file

@ -42,3 +42,4 @@ singleton TelKeypadStyle 1.0 TelKeypad/TelKeypadStyle.qml
singleton TimelineStyle 1.0 Timeline/TimelineStyle.qml
singleton SipAddressesViewStyle 1.0 View/SipAddressesViewStyle.qml
singleton ParticipantsViewStyle 1.0 View/ParticipantsViewStyle.qml

View file

@ -21,7 +21,7 @@ ScrollableListView {
property string genSipAddress
// Optional parameters.
// Optional parameters.chatRoomModel.isMeAdmin
property string headerButtonDescription
property string headerButtonIcon
property var headerButtonAction
@ -29,6 +29,7 @@ ScrollableListView {
property bool showContactAddress : true
property bool showSwitch : false
property bool showSeparator : true
property bool showAdminStatus : false
property bool isSelectable : true
property var switchHandler : function(checked, index){
@ -226,16 +227,25 @@ ScrollableListView {
Layout.fillHeight: true
Layout.fillWidth: true
showContactAddress: sipAddressesView.showContactAddress
statusText : showAdminStatus && modelData.adminStatus ? '(Admin)' : ''
entry: modelData
MouseArea {
anchors.fill: parent
onClicked: sipAddressesView.entryClicked(entry)
onClicked: sipAddressesView.entryClicked(parent.entry, index)
}
BusyIndicator{
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width:15
height:15
running: modelData.inviting
}
}
// ---------------------------------------------------------------------
// Actions
// ---------------------------------------------------------------------

View file

@ -477,27 +477,39 @@ function findIndex (array, cb, context) {
}
// -----------------------------------------------------------------------------
function formatElapsedTime (seconds) {
seconds = parseInt(seconds, 10)
var h = Math.floor(seconds / 3600)
var m = Math.floor((seconds - h * 3600) / 60)
var s = seconds - h * 3600 - m * 60
if (h < 10 && h > 0) {
h = '0' + h
}
if (m < 10) {
m = '0' + m
}
if (s < 10) {
s = '0' + s
}
return (h === 0 ? '' : h + ':') + m + ':' + s
//s, m, h, d, W, M, Y
//1, 60, 3600, 86400, 604800, 2592000, 31104000
var y = Math.floor(seconds / 31104000)
if(y > 0)
return y+ ' years'
var M = Math.floor(seconds / 2592000)
if(M > 0)
return M+' months'
var w = Math.floor(seconds / 604800)
if(w>0)
return w+' week';
var d = Math.floor(seconds / 86400)
if(d>0)
return d+' days'
var h = Math.floor(seconds / 3600)
var m = Math.floor((seconds - h * 3600) / 60)
var s = seconds - h * 3600 - m * 60
if (h < 10 && h > 0) {
h = '0' + h
}
if (m < 10) {
m = '0' + m
}
if (s < 10) {
s = '0' + s
}
return (h === 0 ? '' : h + ':') + m + ':' + s
}
// -----------------------------------------------------------------------------

View file

@ -6,6 +6,9 @@ import Linphone 1.0
import Utils 1.0
import App.Styles 1.0
import Common.Styles 1.0
import Units 1.0
import Colors 1.0
import 'Conversation.js' as Logic
@ -74,40 +77,71 @@ ColumnLayout {
Icon {
id: groupChat
Layout.preferredHeight: ConversationStyle.bar.avatarSize
Layout.preferredWidth: ConversationStyle.bar.avatarSize
Layout.preferredHeight: ConversationStyle.bar.groupChatSize
Layout.preferredWidth: ConversationStyle.bar.groupChatSize
icon:'chat_room'
iconSize: ConversationStyle.bar.avatarSize
iconSize: ConversationStyle.bar.groupChatSize
visible: chatRoomModel.groupEnabled
}
RowLayout{
Layout.fillHeight: true
Layout.fillWidth: true
spacing:0
ContactDescription {
ColumnLayout{
Layout.fillHeight: true
Layout.minimumWidth: 20
Layout.maximumWidth: contactBar.width-avatar.width-actionBar.width-3*ConversationStyle.bar.spacing
Layout.preferredWidth: contentWidth
//sipAddress: conversation.peerAddress
sipAddressColor: ConversationStyle.bar.description.sipAddressColor
username: avatar.username
usernameColor: ConversationStyle.bar.description.usernameColor
sipAddress: {
if(chatRoomModel) {
if(chatRoomModel.groupEnabled) {
return chatRoomModel.participants.displayNamesToString();
}else if(chatRoomModel.isSecure()) {
return chatRoomModel.participants.addressesToString();
}else {
return chatRoomModel.sipAddress;
}
}else {
return conversation.sipAddress || conversation.fullPeerAddress || conversation.peerAddress || '';
}
Layout.preferredWidth: contactDescription.contentWidth
spacing: 5
Row{
Layout.topMargin: 15
Layout.preferredHeight: implicitHeight
Layout.alignment: Qt.AlignBottom
visible:chatRoomModel.isMeAdmin
Icon{
id:adminIcon
icon : 'admin_selected'
iconSize:14
}
Text{
anchors.verticalCenter: parent.verticalCenter
text:'Admin'
color:"#9FA6AB"
font.pointSize: Units.dp * 8
}
}
ContactDescription {
id:contactDescription
Layout.minimumWidth: 20
Layout.maximumWidth: contactBar.width-avatar.width-actionBar.width-3*ConversationStyle.bar.spacing
Layout.preferredWidth: contentWidth
Layout.preferredHeight: contentHeight
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
contactDescriptionStyle: ConversationStyle.bar.contactDescription
username: avatar.username
sipAddress: {
if(chatRoomModel) {
if(chatRoomModel.groupEnabled) {
return chatRoomModel.participants.displayNamesToString();
}else if(chatRoomModel.isSecure()) {
return chatRoomModel.participants.addressesToString();
}else {
return chatRoomModel.sipAddress;
}
}else {
return conversation.sipAddress || conversation.fullPeerAddress || conversation.peerAddress || '';
}
}
}
Item{
Layout.fillHeight: true
Layout.fillWidth: true
visible: chatRoomModel.isMeAdmin
}
}
Icon{
@ -213,31 +247,44 @@ ColumnLayout {
id:conversationMenu
x:mainBar.width-width
y:mainBar.height
width:250
menuStyle : MenuStyle.aux2
MenuItem{
text:'Groupe informations'
iconMenu: 'menu_infos'
iconSizeMenu: 20
iconMenu: (hovered ? 'menu_infos_selected' : 'menu_infos')
iconSizeMenu: 25
menuItemStyle : MenuItemStyle.aux2
onTriggered: {
window.detachVirtualWindow()
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/InfoChatRoom.qml')
,{chatRoomModel:chatRoomModel})
}
}
Rectangle{
height:1
width:parent.width
color:Colors.u
}
MenuItem{
text:"Conversation's devices"
iconMenu: 'menu_devices'
iconSizeMenu: 20
iconMenu: (hovered ? 'menu_devices_selected' : 'menu_devices' )
iconSizeMenu: 25
menuItemStyle : MenuItemStyle.aux2
onTriggered: {
window.detachVirtualWindow()
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/ParticipantsDevices.qml')
,{chatRoomModel:chatRoomModel, window:window})
}
}
Rectangle{
height:1
width:parent.width
color:Colors.u
}
MenuItem{
text:'Ephemeral messages'
iconMenu: 'menu_ephemeral'
iconSizeMenu: 20
iconMenu: (hovered ? 'menu_ephemeral_selected' : 'menu_ephemeral')
iconSizeMenu: 25
menuItemStyle : MenuItemStyle.aux2
onTriggered: {
window.detachVirtualWindow()
window.attachVirtualWindow(Qt.resolvedUrl('Dialogs/EphemeralChatRoom.qml')

View file

@ -19,57 +19,69 @@ DialogPlus {
buttons: [
TextButtonA {
text: 'QUITTER LE GROUPE'
textButtonStyle: InfoChatRoomStyle.leaveButton
showBorder: true
onClicked:{
chatRoomModel.leaveChatRoom();
exit(0)
}
enabled:!chatRoomModel.hasBeenLeft
},Item{
Layout.fillWidth: true
},
TextButtonB {
text: 'OK'
onClicked: {
chatRoomModel.updateParticipants(selectedParticipants.getParticipants()) // Remove/New
if(!chatRoomModel.hasBeenLeft)
chatRoomModel.updateParticipants(selectedParticipants.getParticipants()) // Remove/New
exit(1)
}
}
]
flat : true
showCloseCross: true
title: "Group information"
property ChatRoomModel chatRoomModel
buttonsAlignment: Qt.AlignCenter
buttonsAlignment: Qt.AlignBottom
buttonsLeftMargin: InfoChatRoomStyle.mainLayout.leftMargin
buttonsRightMargin: InfoChatRoomStyle.mainLayout.rightMargin
height: ManageAccountsStyle.height
width: ManageAccountsStyle.width
height: InfoChatRoomStyle.height
width: InfoChatRoomStyle.width
readonly property bool adminMode : chatRoomModel.isMeAdmin && !chatRoomModel.hasBeenLeft
// ---------------------------------------------------------------------------
ColumnLayout {
id:mainLayout
anchors.fill: parent
anchors.topMargin: 15
anchors.leftMargin: 10
anchors.rightMargin: 10
spacing: 0
anchors.topMargin: InfoChatRoomStyle.mainLayout.topMargin
anchors.leftMargin: InfoChatRoomStyle.mainLayout.leftMargin
anchors.rightMargin: InfoChatRoomStyle.mainLayout.rightMargin
spacing: InfoChatRoomStyle.mainLayout.spacing
SmartSearchBar {
id: smartSearchBar
Layout.fillWidth: true
Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing
Layout.topMargin: InfoChatRoomStyle.searchBar.topMargin
showHeader:false
visible: dialog.adminMode && chatRoomModel.canHandleParticipants
maxMenuHeight: MainWindowStyle.searchBox.maxHeight
placeholderText: 'toto'
tooltipText: 'tooltip'
placeholderText: 'Ajouter des participants'
tooltipText: "Rechercher des participants dans votre liste de contact pour les inviter dans le groupe. L'ajout est effectif une fois le formulaire validé."
actions:[{
icon: 'add_participant',
secure:0,
handler: function (entry) {
selectedParticipants.add(entry.sipAddress)
smartSearchBar.addAddressToIgnore(entry.sipAddress);
//++lastContacts.reloadCount;
},
}]
@ -78,60 +90,92 @@ DialogPlus {
}
}
Text{
Layout.preferredHeight: 20
Layout.rightMargin: 65
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
Layout.topMargin: ConferenceManagerStyle.columns.selector.spacing
text : 'Admin'
color: Colors.g
font.pointSize: Units.dp * 11
font.weight: Font.Light
visible: participantView.count > 0
}
ScrollableListViewField {
Layout.fillHeight: true
Layout.fillWidth: true
Layout.bottomMargin: 5
//readOnly: toAddView.count >= conferenceManager.maxParticipants
textFieldStyle: TextFieldStyle.unbordered
textFieldStyle: TextFieldStyle.normal
ParticipantsView {
id: participantView
anchors.fill: parent
showContactAddress:false
showSwitch : true
showSeparator: false
isSelectable: false
actions: [{
icon: 'remove_participant',
tooltipText: 'Remove this participant from the selection',
handler: function (entry) {
smartSearchBar.removeAddressToIgnore(entry.sipAddress)
selectedParticipants.remove(entry)
// ++lastContacts.reloadCount
}
}]
genSipAddress: ''
model: ParticipantProxyModel {
id:selectedParticipants
chatRoomModel:dialog.chatRoomModel
ColumnLayout{
anchors.fill:parent
spacing:0
Text{
Layout.topMargin: InfoChatRoomStyle.results.title.topMargin
Layout.leftMargin: InfoChatRoomStyle.results.title.leftMargin
text:'Liste des participants'
color: InfoChatRoomStyle.results.title.color
font.pointSize:InfoChatRoomStyle.results.title.pointSize
font.weight: InfoChatRoomStyle.results.title.weight
}
Text{
Layout.preferredHeight: implicitHeight
Layout.rightMargin: InfoChatRoomStyle.results.header.rightMargin
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
//Layout.topMargin: InfoChatRoomStyle.results.topMargin
text : 'Admin'
color: InfoChatRoomStyle.results.header.color
font.pointSize: InfoChatRoomStyle.results.header.pointSize
font.weight: InfoChatRoomStyle.results.header.weight
visible: dialog.adminMode && participantView.count > 0
}
onEntryClicked: actions[0].handler(entry)
ParticipantsView {
id: participantView
Layout.fillHeight: true
Layout.fillWidth: true
//anchors.fill: parent
showContactAddress:false
showSwitch : dialog.adminMode
showSeparator: false
showAdminStatus:!dialog.adminMode
isSelectable: false
actions: dialog.adminMode ? [{
icon: 'remove_participant',
tooltipText: 'Remove this participant from the selection',
handler: function (entry) {
smartSearchBar.removeAddressToIgnore(entry.sipAddress)
selectedParticipants.remove(entry)
// ++lastContacts.reloadCount
}
}]
: []
genSipAddress: ''
model: ParticipantProxyModel {
id:selectedParticipants
chatRoomModel:dialog.chatRoomModel
}
onEntryClicked: {//actions[0].handler(entry)
if(tooltip.delay>0) {
tooltip.oldDelay = tooltip.delay
tooltip.delay = 0
}
tooltip.show(entry.sipAddress, -1);
}
ToolTip{
id:tooltip
property int oldDelay : 0
MouseArea{
anchors.fill:parent
onClicked : {
tooltip.hide()
tooltip.delay = tooltip.oldDelay
}
}
}
}
}
}
}
}

View file

@ -1,50 +1,68 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.7
import Colors 1.0
import Units 1.0
// =============================================================================
QtObject {
property QtObject bar: QtObject {
property color backgroundColor: Colors.e
property int avatarSize: 60
property int height: 80
property int leftMargin: 40
property int rightMargin: 30
property int spacing: 20
property QtObject actions: QtObject {
property int spacing: 40
property QtObject call: QtObject {
property int iconSize: 40
}
property QtObject del: QtObject {
property int iconSize: 22
}
property QtObject edit: QtObject {
property int iconSize: 22
}
}
property QtObject description: QtObject {
property color sipAddressColor: Colors.g
property color usernameColor: Colors.j
}
}
property QtObject filters: QtObject {
property color backgroundColor: Colors.q
property int height: 51
property int leftMargin: 40
property QtObject border: QtObject {
property color color: Colors.g10
property int bottomWidth: 1
property int topWidth: 0
}
}
property QtObject bar: QtObject {
property color backgroundColor: Colors.e
property int avatarSize: 60
property int groupChatSize: 55
property int height: 80
property int leftMargin: 40
property int rightMargin: 10
property int spacing: 20
property QtObject actions: QtObject {
property int spacing: 20
property QtObject call: QtObject {
property int iconSize: 40
}
property QtObject del: QtObject {
property int iconSize: 22
}
property QtObject edit: QtObject {
property int iconSize: 22
}
}
property QtObject contactDescription : QtObject {
property QtObject sipAddress: QtObject {
property color color: Colors.n
property int pointSize: Units.dp * 10
property int weight: Font.Light
}
property QtObject username: QtObject {
property color color: Colors.j
property int pointSize: Units.dp * 11
property int weight: Font.Normal
property QtObject status : QtObject{
property color color : Colors.g
property int pointSize : Units.dp * 9
}
}
}
}
property QtObject filters: QtObject {
property color backgroundColor: Colors.q
property int height: 51
property int leftMargin: 40
property QtObject border: QtObject {
property color color: Colors.g10
property int bottomWidth: 1
property int topWidth: 0
}
}
}

View file

@ -0,0 +1,64 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.7
import Colors 1.0
import Units 1.0
// =============================================================================
QtObject {
property int height: 500
property int width: 450
property QtObject mainLayout: QtObject {
property int topMargin: 15
property int leftMargin: 25
property int rightMargin: 25
property int spacing: 7
}
property QtObject searchBar : QtObject{
property int topMargin : 10
}
property QtObject results : QtObject{
property int topMargin : 10
property color color : Colors.g
property QtObject title : QtObject{
property int topMargin: 10
property int leftMargin: 20
property color color: Colors.j
property int pointSize : Units.dp * 11
property int weight : Font.DemiBold
}
property QtObject header: QtObject{
property int rightMargin: 55
property color color: Colors.t
property int weight : Font.Light
property int pointSize : Units.dp * 10
}
}
property QtObject leaveButton :
QtObject {
property QtObject backgroundColor: QtObject {
property color disabled: Colors.o
property color hovered: Colors.j
property color normal: Colors.k
property color pressed: Colors.i
}
property QtObject textColor: QtObject {
property color disabled: Colors.q
property color hovered: Colors.q
property color normal: Colors.i
property color pressed: Colors.q
}
property QtObject borderColor : QtObject{
property color disabled: Colors.q
property color hovered: Colors.q
property color normal: Colors.i
property color pressed: Colors.q
}
}
}

View file

@ -1,7 +1,10 @@
pragma Singleton
import QtQml 2.2
import QtQuick 2.7
import Colors 1.0
import Units 1.0
// =============================================================================

View file

@ -4,11 +4,11 @@ import QtQml 2.2
// =============================================================================
QtObject {
property int height: 353
property int heightWithoutPresence: 284
property int width: 450
property QtObject accountSelector: QtObject {
property int height: 176
}
property int height: 353
property int heightWithoutPresence: 284
property int width: 450
property QtObject accountSelector: QtObject {
property int height: 176
}
}

View file

@ -36,6 +36,7 @@ singleton MainWindowStyle 1.0 Main/MainWindowStyl
singleton AboutStyle 1.0 Main/Dialogs/AboutStyle.qml
singleton AuthenticationRequestStyle 1.0 Main/Dialogs/AuthenticationRequestStyle.qml
singleton ManageAccountsStyle 1.0 Main/Dialogs/ManageAccountsStyle.qml
singleton InfoChatRoomStyle 1.0 Main/Dialogs/InfoChatRoomStyle.qml
singleton InfoEncryptionStyle 1.0 Main/Dialogs/InfoEncryptionStyle.qml
# Settings Window --------------------------------------------------------------