This commit is contained in:
Julien Wadel 2021-07-30 00:42:40 +02:00
parent 6f4b12c61e
commit 3e6c2daf10
149 changed files with 6436 additions and 4009 deletions

View file

@ -122,7 +122,10 @@ set(SOURCES
src/components/calls/CallsListProxyModel.cpp
src/components/camera/Camera.cpp
src/components/camera/CameraPreview.cpp
src/components/chat-message/ChatMessageModel.cpp
src/components/chat-events/ChatCallModel.cpp
src/components/chat-events/ChatEvent.cpp
src/components/chat-events/ChatMessageModel.cpp
src/components/chat-events/ChatNoticeModel.cpp
src/components/chat-room/ChatRoomModel.cpp
src/components/chat-room/ChatRoomListModel.cpp
src/components/chat-room/ChatRoomProxyModel.cpp
@ -161,17 +164,21 @@ set(SOURCES
src/components/participant/ParticipantDeviceModel.cpp
src/components/participant/ParticipantDeviceListModel.cpp
src/components/participant/ParticipantDeviceProxyModel.cpp
src/components/participant-imdn/ParticipantImdnStateModel.cpp
src/components/participant-imdn/ParticipantImdnStateListModel.cpp
src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
src/components/presence/OwnPresenceModel.cpp
src/components/presence/Presence.cpp
src/components/search/SearchHandler.cpp
src/components/search/SearchResultModel.cpp
src/components/search/SearchSipAddressesModel.cpp
src/components/search/SearchSipAddressesProxyModel.cpp
src/components/settings/AccountSettingsModel.cpp
src/components/settings/SettingsModel.cpp
src/components/sip-addresses/SipAddressesModel.cpp
src/components/sip-addresses/SipAddressesProxyModel.cpp
src/components/sip-addresses/SipAddressesSorter.cpp
src/components/sip-addresses/SipAddressObserver.cpp
src/components/sip-addresses/SearchSipAddressesModel.cpp
src/components/sip-addresses/SearchSipAddressesProxyModel.cpp
src/components/sound-player/SoundPlayer.cpp
src/components/telephone-numbers/TelephoneNumbersModel.cpp
src/components/timeline/TimelineModel.cpp
@ -182,7 +189,7 @@ set(SOURCES
src/utils/MediastreamerUtils.cpp
src/utils/QExifImageHeader.cpp
src/utils/Utils.cpp
src/utils/Tools.cpp
src/utils/hacks/ChatRoomInitializer.cpp
src/utils/plugins/PluginsManager.cpp
)
set(PLUGIN_SOURCES src/utils/plugins/PluginDataAPI.cpp
@ -209,7 +216,10 @@ set(HEADERS
src/components/calls/CallsListProxyModel.hpp
src/components/camera/Camera.hpp
src/components/camera/CameraPreview.hpp
src/components/chat-message/ChatMessageModel.hpp
src/components/chat-events/ChatCallModel.hpp
src/components/chat-events/ChatEvent.hpp
src/components/chat-events/ChatMessageModel.hpp
src/components/chat-events/ChatNoticeModel.hpp
src/components/chat-room/ChatRoomModel.hpp
src/components/chat-room/ChatRoomListModel.hpp
src/components/chat-room/ChatRoomProxyModel.hpp
@ -250,17 +260,21 @@ set(HEADERS
src/components/participant/ParticipantDeviceModel.hpp
src/components/participant/ParticipantDeviceListModel.hpp
src/components/participant/ParticipantDeviceProxyModel.hpp
src/components/participant-imdn/ParticipantImdnStateModel.hpp
src/components/participant-imdn/ParticipantImdnStateListModel.cpp
src/components/participant-imdn/ParticipantImdnStateProxyModel.cpp
src/components/presence/OwnPresenceModel.hpp
src/components/presence/Presence.hpp
src/components/search/SearchHandler.hpp
src/components/search/SearchResultModel.hpp
src/components/search/SearchSipAddressesModel.hpp
src/components/search/SearchSipAddressesProxyModel.hpp
src/components/settings/AccountSettingsModel.hpp
src/components/settings/SettingsModel.hpp
src/components/sip-addresses/SipAddressesModel.hpp
src/components/sip-addresses/SipAddressesProxyModel.hpp
src/components/sip-addresses/SipAddressesSorter.hpp
src/components/sip-addresses/SipAddressObserver.hpp
src/components/sip-addresses/SearchSipAddressesModel.hpp
src/components/sip-addresses/SearchSipAddressesProxyModel.hpp
src/components/sound-player/SoundPlayer.hpp
src/components/telephone-numbers/TelephoneNumbersModel.hpp
src/components/timeline/TimelineModel.hpp
@ -271,7 +285,7 @@ set(HEADERS
src/utils/MediastreamerUtils.hpp
src/utils/QExifImageHeader.hpp
src/utils/Utils.hpp
src/utils/Tools.hpp
src/utils/hacks/ChatRoomInitializer.hpp
src/utils/plugins/PluginsManager.hpp
)
set(PLUGIN_HEADERS

View file

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="25"
height="25"
viewBox="0 0 25 25"
version="1.1"
id="svg12"
sodipodi:docname="chat_micro.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="34.92"
inkscape:cx="9.0063001"
inkscape:cy="12.5"
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="translate(4)">
<g
fill="#444444"
fill-rule="nonzero"
id="g8">
<g
id="g6">
<g
id="g4">
<path
d="m 1.69,12.667 c 0.627,3.413 3.617,6 7.212,6 3.595,0 6.585,-2.587 7.212,-6 h 1.69 C 17.208,16.68 13.962,19.83 9.901,20.278 V 25 h -2 V 20.278 C 3.842,19.83 0.597,16.68 0,12.666 H 1.69 Z M 8.902,0 c 3.13,0 5.667,2.537 5.667,5.667 v 5 c 0,3.13 -2.537,5.666 -5.667,5.666 -3.13,0 -5.667,-2.537 -5.667,-5.666 v -5 C 3.235,2.537 5.772,0 8.902,0 Z m 0,1.667 c -2.175,0 -3.945,1.736 -3.999,3.898 L 4.902,5.667 v 5 c 0,2.209 1.79,4 4,4 2.175,0 3.945,-1.737 3.999,-3.899 V 5.667 c 0,-2.21 -1.79,-4 -4,-4 z"
id="path2" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
<title>contact_default</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols-vecto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.5">
<g id="contact_default" fill="#FFFFFF">
<path d="M16.8061559,6.80739857 C16.8061559,8.04777355 16.3417672,9.21099173 15.5204136,10.0967799 C15.4434922,10.1798811 15.4365738,10.1883818 15.3574501,10.2897899 C14.8712019,10.7074152 14.9187969,11.4869099 15.4594834,11.8549776 L15.6994402,12.0183261 L15.859758,12.1071437 C18.0426652,13.0666913 19.5879248,14.2312064 20.5911168,15.5459618 C21.9323211,17.3037066 22.209108,19.1412082 21.8904449,20.7591593 C21.8516838,20.9559612 21.8158733,21.0853677 21.7984541,21.1355667 L22.4381495,20.511055 C20.3066086,21.1938061 18.1017272,21.6205507 15.9222911,21.8384954 C14.462433,21.984482 13.2209671,22.0194037 12.2962639,21.9927551 C12.2052904,21.9901334 12.1455704,21.9876214 12.1189614,21.9861682 L11.9358329,21.9846803 L11.9358329,22.9846803 L12.9358329,22.9846803 L11.9108224,21.9849931 C11.8628815,21.9870261 11.8628815,21.9870261 11.8423479,21.9879051 C11.7889591,21.9900363 11.7889591,21.9900363 11.7035112,21.9926929 C10.7769249,22.0192234 9.53621081,21.984275 8.07648162,21.8382841 C5.89725134,21.6203341 3.69283284,21.1936639 1.56185338,20.5110593 L2.20153524,21.1355667 C2.18411742,21.0853718 2.14830897,20.9559724 2.1095499,20.7591801 C1.79088868,19.1412341 2.06769549,17.3037306 3.40895961,15.545977 C4.41219415,14.2312179 5.95751214,13.0666988 8.14049436,12.1071484 L8.30082278,12.0183261 L8.54077958,11.8549776 C9.08146603,11.4869099 9.12906109,10.7074152 8.63717186,10.2762996 C8.56368915,10.1883818 8.55677078,10.1798811 8.48044484,10.0974226 C7.65859291,9.21084479 7.19410709,8.0475319 7.19410709,6.80739857 C7.19410709,4.15018114 9.32330008,2 11.9448621,2 L12.0554009,2 C14.6769629,2 16.8061559,4.15018114 16.8061559,6.80739857 Z M11.9448621,0 C8.21431525,0 5.19410709,3.04997933 5.19410709,6.80739857 C5.19410709,8.55620797 5.85198152,10.203866 7.01320556,11.456543 C7.03781127,11.4831261 7.02183844,11.4635001 7.06599939,11.5200985 C7.14632933,11.6207546 7.21387737,11.6883003 7.31892913,11.7803728 L7.97805049,11.0283362 L7.41532141,10.2016948 L7.1753646,10.3650434 L7.73809369,11.1916847 L7.33569302,10.2762211 C4.85488983,11.3666815 3.03679647,12.7367584 1.81897884,14.3327329 C0.0899618353,16.5986445 -0.273330095,19.0102549 0.147247578,21.1456637 C0.204787561,21.4378128 0.265278163,21.6564049 0.312059712,21.7912208 C0.415188143,22.0884181 0.652154443,22.3197632 0.951741577,22.4157282 C3.2260852,23.1442558 5.56632944,23.5972155 7.87744985,23.828356 C9.42772204,23.9834024 10.7529177,24.0207305 11.7607528,23.9918736 C11.8595647,23.9888037 11.8595647,23.9888037 11.925618,23.9861709 C10.9358329,23.536965 12.0644301,23.9846803 12.0644301,23.9846803 C12.0534187,23.9855691 12.1302768,23.988802 12.2386508,23.9919252 C13.2447467,24.0209193 14.5708311,23.9836174 16.1212996,23.8285697 C18.4326271,23.5974358 20.7733351,23.1444026 23.0482343,22.4157325 C23.3478275,22.3197702 23.5847996,22.0884228 23.6879296,21.7912208 C23.7347124,21.6564012 23.795205,21.4378024 23.852747,21.145644 C24.2733244,19.0102426 23.9100607,16.5986484 22.1811207,14.3327481 C20.9633485,12.7367699 19.1453124,11.366689 16.6645805,10.2762257 L16.2621693,11.1916847 L16.8248984,10.3650434 L16.5849415,10.2016948 L16.0222125,11.0283362 L16.6813338,11.7803728 C16.7863856,11.6883003 16.8539336,11.6207546 16.9213349,11.5364713 C16.9784245,11.4635001 16.9624517,11.4831261 16.9875565,11.4560042 C18.1483583,10.204139 18.8061559,8.55646302 18.8061559,6.80739857 C18.8061559,3.04997933 15.7859477,0 12.0554009,0 L11.9448621,0 Z"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
<title>contact_default</title>
<title>contact_selected</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Symbols-vecto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" opacity="0.5">
<g id="contact_default" fill="#FFFFFF">
<g id="Symbols-vecto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="contact_selected" fill="#FFFFFF">
<path d="M16.8061559,6.80739857 C16.8061559,8.04777355 16.3417672,9.21099173 15.5204136,10.0967799 C15.4434922,10.1798811 15.4365738,10.1883818 15.3574501,10.2897899 C14.8712019,10.7074152 14.9187969,11.4869099 15.4594834,11.8549776 L15.6994402,12.0183261 L15.859758,12.1071437 C18.0426652,13.0666913 19.5879248,14.2312064 20.5911168,15.5459618 C21.9323211,17.3037066 22.209108,19.1412082 21.8904449,20.7591593 C21.8516838,20.9559612 21.8158733,21.0853677 21.7984541,21.1355667 L22.4381495,20.511055 C20.3066086,21.1938061 18.1017272,21.6205507 15.9222911,21.8384954 C14.462433,21.984482 13.2209671,22.0194037 12.2962639,21.9927551 C12.2052904,21.9901334 12.1455704,21.9876214 12.1189614,21.9861682 L11.9358329,21.9846803 L11.9358329,22.9846803 L12.9358329,22.9846803 L11.9108224,21.9849931 C11.8628815,21.9870261 11.8628815,21.9870261 11.8423479,21.9879051 C11.7889591,21.9900363 11.7889591,21.9900363 11.7035112,21.9926929 C10.7769249,22.0192234 9.53621081,21.984275 8.07648162,21.8382841 C5.89725134,21.6203341 3.69283284,21.1936639 1.56185338,20.5110593 L2.20153524,21.1355667 C2.18411742,21.0853718 2.14830897,20.9559724 2.1095499,20.7591801 C1.79088868,19.1412341 2.06769549,17.3037306 3.40895961,15.545977 C4.41219415,14.2312179 5.95751214,13.0666988 8.14049436,12.1071484 L8.30082278,12.0183261 L8.54077958,11.8549776 C9.08146603,11.4869099 9.12906109,10.7074152 8.63717186,10.2762996 C8.56368915,10.1883818 8.55677078,10.1798811 8.48044484,10.0974226 C7.65859291,9.21084479 7.19410709,8.0475319 7.19410709,6.80739857 C7.19410709,4.15018114 9.32330008,2 11.9448621,2 L12.0554009,2 C14.6769629,2 16.8061559,4.15018114 16.8061559,6.80739857 Z M11.9448621,0 C8.21431525,0 5.19410709,3.04997933 5.19410709,6.80739857 C5.19410709,8.55620797 5.85198152,10.203866 7.01320556,11.456543 C7.03781127,11.4831261 7.02183844,11.4635001 7.06599939,11.5200985 C7.14632933,11.6207546 7.21387737,11.6883003 7.31892913,11.7803728 L7.97805049,11.0283362 L7.41532141,10.2016948 L7.1753646,10.3650434 L7.73809369,11.1916847 L7.33569302,10.2762211 C4.85488983,11.3666815 3.03679647,12.7367584 1.81897884,14.3327329 C0.0899618353,16.5986445 -0.273330095,19.0102549 0.147247578,21.1456637 C0.204787561,21.4378128 0.265278163,21.6564049 0.312059712,21.7912208 C0.415188143,22.0884181 0.652154443,22.3197632 0.951741577,22.4157282 C3.2260852,23.1442558 5.56632944,23.5972155 7.87744985,23.828356 C9.42772204,23.9834024 10.7529177,24.0207305 11.7607528,23.9918736 C11.8595647,23.9888037 11.8595647,23.9888037 11.925618,23.9861709 C10.9358329,23.536965 12.0644301,23.9846803 12.0644301,23.9846803 C12.0534187,23.9855691 12.1302768,23.988802 12.2386508,23.9919252 C13.2447467,24.0209193 14.5708311,23.9836174 16.1212996,23.8285697 C18.4326271,23.5974358 20.7733351,23.1444026 23.0482343,22.4157325 C23.3478275,22.3197702 23.5847996,22.0884228 23.6879296,21.7912208 C23.7347124,21.6564012 23.795205,21.4378024 23.852747,21.145644 C24.2733244,19.0102426 23.9100607,16.5986484 22.1811207,14.3327481 C20.9633485,12.7367699 19.1453124,11.366689 16.6645805,10.2762257 L16.2621693,11.1916847 L16.8248984,10.3650434 L16.5849415,10.2016948 L16.0222125,11.0283362 L16.6813338,11.7803728 C16.7863856,11.6883003 16.8539336,11.6207546 16.9213349,11.5364713 C16.9784245,11.4635001 16.9624517,11.4831261 16.9875565,11.4560042 C18.1483583,10.204139 18.8061559,8.55646302 18.8061559,6.80739857 C18.8061559,3.04997933 15.7859477,0 12.0554009,0 L11.9448621,0 Z"></path>
</g>
</g>

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg10"
sodipodi:docname="current_account_status_busy.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="54.5625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<g
fill="none"
fill-rule="evenodd"
id="g8">
<g
id="g6">
<circle
cx="8"
cy="8"
r="8"
fill="#EFAE00"
transform="translate(8.000000, 8.000000) rotate(-180.000000) translate(-8.000000, -8.000000)"
id="circle2" />
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4.571 6.857L8 10.286m3.429-3.426L8 10.286"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg10"
sodipodi:docname="current_account_status_dnd.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="54.5625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<g
fill="none"
fill-rule="evenodd"
id="g8">
<g
id="g6">
<circle
cx="8"
cy="8"
r="8"
fill="#DC4100"
transform="translate(8.000000, 8.000000) rotate(-180.000000) translate(-8.000000, -8.000000)"
id="circle2" />
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4.571 6.857L8 10.286m3.429-3.426L8 10.286"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg10"
sodipodi:docname="current_account_status_offline.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="54.5625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<g
fill="none"
fill-rule="evenodd"
id="g8">
<g
id="g6">
<circle
cx="8"
cy="8"
r="8"
fill="#B1B1B1"
transform="translate(8.000000, 8.000000) rotate(-180.000000) translate(-8.000000, -8.000000)"
id="circle2" />
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4.571 6.857L8 10.286m3.429-3.426L8 10.286"
id="path4" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg29"
sodipodi:docname="group_chat_hovered.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview31"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="19.954181"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg29" />
<defs
id="defs5">
<filter
id="hf1nvdl9pa"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<g
fill="none"
fill-rule="evenodd"
id="g27">
<g
id="g25">
<g
fill="#4B5964"
id="g9">
<circle
cx="20"
cy="20"
r="20"
id="circle7" />
</g>
<g
id="g23">
<g
filter="url(#hf1nvdl9pa)"
transform="translate(5.873063, 10.000000)"
id="g19">
<g
id="g17">
<g
fill="#444"
fill-rule="nonzero"
id="g15">
<path
d="M4.657 13.441c1.211.363 2.457.595 3.69.718.898.09 1.662.111 2.231.095l.11-.004.112-.001.142.005c.57.016 1.333-.005 2.232-.095 1.232-.123 2.478-.355 3.69-.718.182-.987.005-2.102-.81-3.17-.618-.81-1.57-1.528-2.915-2.12-.034-.014-.066-.032-.097-.053l-.147-.1c-.326-.222-.356-.692-.06-.953.046-.055.056-.067.099-.112.507-.547.794-1.266.794-2.031 0-1.641-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.969 0 .765.287 1.484.794 2.031.043.046.05.055.088.104.307.268.278.74-.05.961l-.148.1c-.03.021-.062.039-.096.054-1.344.59-2.296 1.308-2.915 2.119-.814 1.068-.992 2.183-.81 3.17zm6.079 2.016l-.123.005c-.618.018-1.434-.005-2.387-.1-1.42-.143-2.86-.421-4.259-.87-.18-.057-.324-.197-.386-.377-.029-.082-.066-.216-.101-.395-.258-1.31-.035-2.791 1.026-4.182.653-.857 1.59-1.609 2.833-2.232-.486-.695-.754-1.529-.754-2.404 0-2.306 1.852-4.177 4.141-4.177h.068c2.29 0 4.142 1.871 4.142 4.177 0 .875-.269 1.71-.755 2.404 1.244.624 2.18 1.375 2.834 2.232 1.061 1.39 1.284 2.871 1.026 4.182-.036.179-.073.313-.101.395-.063.18-.206.32-.387.378-1.399.448-2.838.726-4.259.868-.953.096-1.768.119-2.387.1-.053 0-.095-.002-.122-.004h-.05z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path11" />
<path
d="M14.878 4.902c0 .875-.268 1.709-.755 2.404 1.863.933 3.02 2.14 3.574 3.523 1.058-.08 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.634-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.952.027-.034.038-.046.072-.083.387-.418.606-.966.606-1.551 0-1.253-1.004-2.267-2.239-2.267h-.054c-.866 0-1.637.502-2.008 1.263.498.7.773 1.545.773 2.43zm2.835.227v-.001zm-4.146 1.916l-.243.554.34-.5-.045-.03-.052-.024zm-.69-.112c.506-.547.793-1.266.793-2.031 0-.724-.256-1.406-.714-1.942-.138-.16-.181-.38-.115-.581C13.305.97 14.616 0 16.113 0h.054c1.905 0 3.447 1.557 3.447 3.475 0 .681-.195 1.332-.552 1.887.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.334-.062.18-.205.32-.386.377-1.452.465-2.931.7-4.327.769-.278.014-.529-.164-.609-.43-.405-1.36-1.524-2.562-3.618-3.482-.034-.015-.066-.033-.097-.054l-.147-.1c-.326-.222-.355-.692-.06-.953.046-.055.056-.067.1-.112zM7.34 7.306c-.487-.695-.755-1.529-.755-2.404 0-1.11.432-2.148 1.177-2.918-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.014-2.238 2.267 0 .585.219 1.133.607 1.552.034.037.043.047.07.08.296.261.267.732-.06.954l-.12.081c-.03.02-.062.038-.095.053-1.063.467-1.812 1.032-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.247 1.695.415 2.546.516.565-1.355 1.715-2.537 3.545-3.454zM4.474 5.13zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.9l-.148.1c-.03.02-.062.038-.096.053-2.07.91-3.187 2.096-3.604 3.438-.085.272-.349.448-.633.422-1.193-.11-2.409-.338-3.591-.717-.181-.058-.324-.198-.387-.377-.024-.072-.056-.184-.085-.334C-.133 9.5.051 8.276.927 7.128c.516-.675 1.243-1.27 2.199-1.766-.357-.554-.552-1.206-.552-1.887C2.574 1.557 4.115 0 6.02 0h.055C7.34 0 8.484.693 9.088 1.786c.143.26.077.584-.156.767-.714.56-1.14 1.418-1.14 2.349 0 .765.288 1.484.795 2.031.043.046.05.055.088.104.307.268.278.74-.05.961z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path13" />
</g>
</g>
</g>
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
d="M30.278 6.994c-.907-2.01-3.608-3.397-5.857-3.397h-.047c-2.249 0-4.95 1.388-5.857 3.398l.331 2.602h2.898l.205-2.59h4.893l.205 2.59h2.898l.33-2.603h0z"
transform="translate(5.873063, 10.000000) translate(24.397663, 6.597392) rotate(-119.000000) translate(-24.397663, -6.597392)"
id="path21" />
</g>
</g>
</g>
<path
style="fill:#ffffff;stroke-width:0.045819"
d="M 15.166094,29.844075 C 13.87814,29.788111 12.328834,29.559882 11.065292,29.239984 9.786811,28.916304 9.5647637,28.814878 9.4658175,28.509382 9.3354584,28.1069 9.267805,27.482053 9.2935883,26.918671 l 0.026211,-0.572737 -0.640858,-0.104726 C 7.5236868,26.052422 6.3924205,25.735094 6.2044097,25.547083 5.9957122,25.338386 5.8579054,24.597276 5.9064941,23.944926 c 0.1180372,-1.584763 1.0812313,-2.949853 2.787664,-3.950825 0.1701031,-0.09978 0.3092783,-0.191334 0.3092783,-0.203451 0,-0.01212 -0.069846,-0.160727 -0.1552124,-0.330244 C 8.4084997,18.587231 8.3552576,17.61442 8.6973475,16.703674 9.5732363,14.371796 12.537478,13.69901 14.305167,15.430883 l 0.284548,0.278782 0.24237,-0.118598 c 0.640377,-0.313355 1.226703,-0.425396 2.029312,-0.387784 0.7707,0.03612 1.375593,0.221923 1.978932,0.607874 0.13877,0.08877 0.267991,0.155204 0.287159,0.14763 0.01917,-0.0076 0.138973,-0.139477 0.266234,-0.293119 0.419187,-0.506084 1.081053,-0.923376 1.751753,-1.104441 0.4109,-0.110928 1.332069,-0.110723 1.739673,3.88e-4 0.924216,0.251937 1.704888,0.874124 2.169781,1.72929 0.25306,0.465503 0.357779,0.864297 0.384419,1.463963 0.02874,0.646888 -0.07362,1.138768 -0.352301,1.693044 l -0.184481,0.366915 0.194765,0.09901 c 0.107121,0.05446 0.3618,0.209976 0.565953,0.345601 1.091444,0.725079 1.812228,1.623411 2.181451,2.718798 0.141062,0.418493 0.146797,0.464438 0.148702,1.191294 0.003,1.15988 -0.110817,1.419878 -0.699323,1.596941 -0.816586,0.245685 -1.844026,0.463566 -2.740785,0.581216 l -0.601311,0.07889 0.02331,0.491764 c 0.03978,0.839329 -0.116429,1.647701 -0.357624,1.850653 -0.408382,0.343631 -3.284961,0.935142 -5.15264,1.059539 -0.635215,0.04231 -2.482677,0.05101 -3.298969,0.01554 z m 3.894616,-1.226546 c 1.182292,-0.13755 2.179645,-0.317844 3.106027,-0.561485 0.414081,-0.108904 0.552206,-0.164567 0.59176,-0.238474 0.0654,-0.1222 0.06569,-1.087062 4.12e-4,-1.334179 -0.04933,-0.186719 -0.20815,-0.596843 -0.389863,-1.006754 -0.453704,-1.023467 -1.476,-1.950482 -3.008469,-2.728069 -0.731764,-0.3713 -0.872604,-0.5001 -0.872604,-0.797999 0,-0.206913 0.02647,-0.253918 0.425813,-0.756169 0.429245,-0.539859 0.630456,-1.13309 0.630456,-1.858776 0,-0.732703 -0.186883,-1.281402 -0.648472,-1.903947 -0.489183,-0.65976 -1.172593,-1.018856 -2.057282,-1.080993 -1.427808,-0.100283 -2.720604,0.830417 -3.096108,2.228927 -0.116905,0.435396 -0.104389,1.163534 0.02717,1.580756 0.142948,0.453334 0.292169,0.731315 0.588759,1.09679 0.340473,0.419552 0.368969,0.473188 0.370878,0.69809 0.0025,0.294688 -0.14356,0.427438 -0.883291,0.802784 -1.55186,0.787426 -2.471898,1.624229 -2.994977,2.724023 -0.294297,0.618772 -0.39009,1.029328 -0.393997,1.688622 -0.002,0.32926 0.01761,0.588635 0.04876,0.646566 0.120392,0.223887 2.466606,0.69735 4.156399,0.838756 0.637915,0.05338 3.850636,0.02529 4.398625,-0.03847 z m 5.933563,-3.5125 c 0.365406,-0.06093 0.926431,-0.175509 1.246721,-0.254629 l 0.582345,-0.143853 0.03093,-0.206266 c 0.04637,-0.309196 -0.01154,-0.827652 -0.13633,-1.220621 -0.318625,-1.003357 -1.118245,-1.80936 -2.504779,-2.524775 -0.667467,-0.344395 -0.776268,-0.454453 -0.776565,-0.785539 -1.37e-4,-0.163538 0.03299,-0.229461 0.230296,-0.45819 0.849545,-0.98484 0.837153,-2.322598 -0.02973,-3.209414 -0.535662,-0.547978 -1.315078,-0.790076 -2.056693,-0.638839 -0.198187,0.04042 -0.475075,0.12923 -0.615308,0.197364 -0.266049,0.129264 -0.800271,0.626614 -0.916625,0.85336 -0.0593,0.115552 -0.05599,0.142706 0.03623,0.297824 0.242037,0.407117 0.427012,0.813252 0.541256,1.188397 0.110144,0.361679 0.122704,0.474972 0.123386,1.112867 6.32e-4,0.591164 -0.01611,0.77163 -0.09987,1.076747 -0.09363,0.341053 -0.351076,0.924229 -0.5438,1.231857 -0.05324,0.08498 -0.06498,0.138662 -0.03287,0.150289 0.02747,0.0099 0.241366,0.127665 0.475315,0.26159 1.30543,0.7473 2.293657,1.721541 2.861514,2.821017 l 0.219429,0.424855 0.350388,-0.03163 c 0.192713,-0.0174 0.649357,-0.08148 1.014764,-0.142408 z M 9.8082992,24.937255 c 0.3315758,-0.705722 0.9784488,-1.50669 1.6621428,-2.058088 0.427198,-0.344534 1.079263,-0.778296 1.45052,-0.964904 0.151203,-0.076 0.280232,-0.142774 0.286731,-0.148387 0.0065,-0.0056 -0.0891,-0.204199 -0.212439,-0.441305 -0.370401,-0.712047 -0.508564,-1.259916 -0.509227,-2.01928 -7.88e-4,-0.905788 0.303007,-1.798472 0.847445,-2.490157 0.138659,-0.176159 0.265995,-0.349782 0.28297,-0.38583 0.04423,-0.09393 -0.30686,-0.385421 -0.69548,-0.577412 -0.890674,-0.440023 -1.955091,-0.249908 -2.643886,0.472222 -0.4224999,0.442947 -0.6321734,0.970675 -0.6321734,1.591121 0,0.597302 0.1895231,1.089283 0.6005674,1.559006 0.327412,0.374152 0.350269,0.663438 0.07315,0.92575 -0.08074,0.07642 -0.3942174,0.264383 -0.6966229,0.417692 -0.6509622,0.330015 -1.0770464,0.62736 -1.5039382,1.049533 -0.7377375,0.729581 -1.0624044,1.491124 -1.0303751,2.416862 l 0.014267,0.412371 0.3894616,0.103785 c 0.5147595,0.137174 1.6919852,0.367587 2.1336143,0.417602 0.026867,0.003 0.1093412,-0.123219 0.183276,-0.280581 z"
id="path70" />
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="71"
height="82"
viewBox="0 0 71 82"
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg10"
sodipodi:docname="menu_chatroom_devices.svg"
sodipodi:docname="menu_devices.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"
@ -23,30 +23,32 @@
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.646341"
inkscape:cx="35.45819"
inkscape:cy="41.046964"
inkscape:cx="35.458192"
inkscape:cy="41.000002"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
inkscape:current-layer="svg10"
width="13px" />
<g
fill="none"
fill-rule="evenodd"
id="g8">
id="g8"
transform="matrix(0.18571633,0,0,0.1875043,0.90699082,-0.28142708)">
<g
id="g6">
<path
stroke="#444"
stroke="#444444"
stroke-width="5"
d="M33.308 74.729c-.042.027-.083.059-.13.081-.214.123-.457.19-.7.19-.23 0-.453-.058-.66-.176-.348-.195-8.638-4.942-16.75-14.693C7.58 51.118-1.1 35.978.115 15.028c.036-.61.485-1.122 1.094-1.244C18.102 10.444 31.131.906 31.676.5c.019-.014.041-.033.065-.047l.334-.221c.486-.325 1.132-.308 1.599.05.128.1 13.13 9.919 30.109 13.276.61.118 1.058.633 1.096 1.244 2.3 39.737-28.873 58.393-31.571 59.927"
transform="translate(3.000000, 4.000000)"
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="#444"
d="M18.5 19L15.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.255zM45.5 19L42.255 25.255 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.255z"
transform="translate(3.000000, 4.000000)"
fill="#444444"
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>

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="69"
height="82"
viewBox="0 0 69 82"
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg12"
sodipodi:docname="menu_chatroom_ephemeral.svg"
sodipodi:docname="menu_ephemeral.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"
@ -23,30 +23,32 @@
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.646341"
inkscape:cx="34.5189"
inkscape:cy="41.046964"
inkscape:cx="34.518902"
inkscape:cy="41.000002"
inkscape:window-width="1920"
inkscape:window-height="1043"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
inkscape:current-layer="svg12"
width="13px" />
<g
fill="none"
fill-rule="evenodd"
id="g10">
id="g10"
transform="matrix(0.19288979,0,0,0.18473816,0.84530239,0)">
<g
fill="#444"
fill="#444444"
id="g8">
<path
d="M19.256 19.172l-3.665-5.405c-.656-.966-1.937-1.194-2.862-.51l-5.444 4.026c-.925.684-1.144 2.023-.489 2.989l3.696 5.453M56.999 25.725L60.6 21.02c.653-.854.436-2.036-.488-2.642l-5.429-3.559c-.922-.603-2.2-.401-2.853.452l-3.69 4.822M38.773 16.078v-2.002c0-1.28 1.085-2.33 2.412-2.33h1.33c1.33 0 2.415-1.049 2.415-2.33V2.332C44.93 1.049 43.844 0 42.516 0h-17.64c-1.325 0-2.41 1.049-2.41 2.331v7.086c0 1.28 1.085 2.33 2.41 2.33h1.334c1.327 0 2.413 1.048 2.413 2.329v2.002"
d="m 19.256,19.172 -3.665,-5.405 c -0.656,-0.966 -1.937,-1.194 -2.862,-0.51 L 7.285,17.283 C 6.36,17.967 6.141,19.306 6.796,20.272 l 3.696,5.453 m 46.507,0 3.601,-4.705 c 0.653,-0.854 0.436,-2.036 -0.488,-2.642 l -5.429,-3.559 c -0.922,-0.603 -2.2,-0.401 -2.853,0.452 l -3.69,4.822 m -9.367,-4.015 v -2.002 c 0,-1.28 1.085,-2.33 2.412,-2.33 h 1.33 c 1.33,0 2.415,-1.049 2.415,-2.33 V 2.332 C 44.93,1.049 43.844,0 42.516,0 h -17.64 c -1.325,0 -2.41,1.049 -2.41,2.331 v 7.086 c 0,1.28 1.085,2.33 2.41,2.33 h 1.334 c 1.327,0 2.413,1.048 2.413,2.329 v 2.002"
id="path2" />
<path
fill-rule="nonzero"
d="M34.5 13.667C15.89 13.667.802 28.784.802 47.43.802 66.08 15.89 81.196 34.5 81.196c18.61 0 33.698-15.117 33.698-33.765 0-18.647-15.087-33.764-33.698-33.764zm0 4.823c15.952 0 28.884 12.958 28.884 28.941 0 15.984-12.932 28.942-28.884 28.942S5.616 63.415 5.616 47.43c0-15.983 12.932-28.94 28.884-28.94z"
d="m 34.5,13.667 c -18.61,0 -33.698,15.117 -33.698,33.763 0,18.65 15.088,33.766 33.698,33.766 18.61,0 33.698,-15.117 33.698,-33.765 0,-18.647 -15.087,-33.764 -33.698,-33.764 z m 0,4.823 c 15.952,0 28.884,12.958 28.884,28.941 0,15.984 -12.932,28.942 -28.884,28.942 C 18.548,76.373 5.616,63.415 5.616,47.43 5.616,31.447 18.548,18.49 34.5,18.49 Z"
id="path4" />
<path
d="M34.5 22.51c-.067 0-.133.006-.198.006v24.717H9.633c-.001.065-.005.13-.005.199 0 13.676 11.051 24.81 24.674 24.917.066 0 .131.004.198.004 13.714 0 24.872-11.178 24.872-24.921 0-.068-.005-.134-.005-.2C59.26 33.584 48.147 22.51 34.5 22.51z"
d="m 34.5,22.51 c -0.067,0 -0.133,0.006 -0.198,0.006 V 47.233 H 9.633 c -10e-4,0.065 -0.005,0.13 -0.005,0.199 0,13.676 11.051,24.81 24.674,24.917 0.066,0 0.131,0.004 0.198,0.004 13.714,0 24.872,-11.178 24.872,-24.921 0,-0.068 -0.005,-0.134 -0.005,-0.2 C 59.26,33.584 48.147,22.51 34.5,22.51 Z"
id="path6" />
</g>
</g>

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View file

@ -4,9 +4,9 @@
<svg
version="1.1"
id="svg2"
width="85"
height="85"
viewBox="0 0 85 85"
width="15"
height="15"
viewBox="0 0 15 15"
sodipodi:docname="menu_infos.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
@ -26,81 +26,26 @@
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.270588"
inkscape:cx="42.5"
inkscape:cy="42.5"
inkscape:cx="42.402636"
inkscape:cy="42.500001"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="g8"
width="15px" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="85"
height="85"
width="15"
height="15"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFUAAABVCAYAAAA49ahaAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAA
GXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAADHBJREFUeJztnX9sU9cVx7/n+plA
CD8MzbRVE8gOA6apa0f41WbqjP1sFKGsazdDNZW2oqM/ALXVVol2ox0dbddV07q2FDparXSgiRZ1
7QoMGj+H/DEK/ZFuElJXaGtDKwVtQJxASAjxu2d/+AXIe9eOndhJHPKRLDnn/vTJfe/de+655xGG
AX6/v8Llcl1DRN8GMJOZZxLRNACTAIy3PhMBnAFwzvq0MvNXRHQUwBFm/tQ0zcONjY3tQ/U7eqCh
aLS2trbMNM0aKeUiIgow83wAWgGq7gbwARE1SCn3jxkz5r29e/d2FaDevBhMpVIoFLoBwHJmXgrA
MwhtJgG8LqXc1tDQ8N4gtAdgEJQaDofHSynvBrAKwIxit5eFzwFsEkJsqa+vP1fMhoqm1Jqamgnl
5eUrmPlhAF8vVjv94BSAF8vKyp7bs2dPshgNFFypkUjE1dLSspqIfoP0gyZXEkTUJKU8SkRHmPkz
IcQpIUS7EOLc3r17z9TW1k6UUo6XUlaYplkphJjBzLOEEDOZuRqAN4/2kgAe83g8m3fu3Gnm9SP7
oKBK1XV9IYBNAL6XQ/azAHYBMDRN279v375jA20/HA57pZSLAOgA6gBU5FCsSUq5qqGh4YOBtt9D
QZRaW1tblkqlnmHmNQBElqwmAIOZt5WXl7+1a9eujkK0ryIcDo9n5puZeTnSSs7WLwngOY/H8/DO
nTsvDLTtASs1EAhMF0LsALAwS7ZuADuEEE/V19d/OtA280XXdR8RPcDM9wAoy5K1SUq5rKGh4YuB
tDcgpYZCoZuZ+VVkvndKAK8AeNIwjC8H0lYhCAQC04loHRGtQOaR2wrgTsMw/t7fdvqt1FAotJqZ
n0fmzv0LwCrDMA71t41iEQgE5rhcrs3WokMFM/NDsVjsD/2p39WfQrqubwDwNNT/lC4iesjj8azc
vXv3V/2pv9gkEokT1dXVr3Z2drYR0SI49UBEtNjr9YpEItGYb/35jlTSdX0j0hN5FZ9b96SP8+3I
UBEKheYy8+sAfKp0Zn4xFoutyafOvEaqNUJ/kSH5bbfbXRuNRo/lU+dQE4/Hm30+32vM/B0immVP
J6L5VVVVrng8vj/XOnMeqbqu34f0HNQBM281TXNlY2NjKtf6MuH3+8dqmnY01/zMfHcsFts30HYj
kYgrmUxuAnC3Kp2IHoxGo8/lUldOStV1/RYAO6F+KD1hGMajudSTC3V1deWdnZ35rM1/bBjG3wrU
PFlX468UaRLALbnMCrJNiAEAgUCgCsCfVXmJaEMhFToMYMMw1gF4UpEmAGwNh8N9LoWzKrW6utot
hNgO9Tx0SzQafSynrpYY1kB5WZE0WUr5eiQSGZOtfFalTpky5fdQr5Te9ng8mWYAIwH2eDz3AXhH
kTYvmUz+LlvhjEoNBoPzrLW8nS8A3Floy85ww/p9twOIK5Lvt4xHSpRKjUQiLiL6kyK9S0q51DCM
tn73toQwDKONiJYBsG/JCAAbI5GIckqqVGpLS8tqKMx3RLS2lCb2hSAajX4E4BFFUnVLS8s9qjIO
pfr9/slE9Lgi70eTJ0/eOMA+liQej+d5pG0ZvSCiDbW1tRPtcscOpqZpawBMtomlEGLNYNxHx44d
29XZ2XlXrvmllE3F7A+Qvr8Gg8F7iOgQeg/EKd3d3auQtoNcpNfk39qkOwbgKlu9WwzDUA71K4lQ
KPQKM9v/4f8bN26c93KDe6/L39r1tCv0AtST4SsOl8v1BNIG98v52vnz51deLrDfU++1V0RE24aD
gXk4sG/fvmNE9Fe73Jp6XrzqL95TQ6FQDTPPtOU3AWSd6BYDv9+fy4YdAKCysrJzMOfMqVTqty6X
azl6D8gZuq4v6DHIX56wXFGHEY1GPytmJ+3U1dWVa5p2NtdPMpm8aTD7t3///iMAGuxyZr6t57sA
0ruhliuOPeO2ovawdHHohYhu7bEJCABIpVLfh9O3qd00zX5vfo1khBBvArB7F05ta2tbCFhKZeZF
irLvDAe3xOGI5Yu1xy6XUgaAS/fUgKKsUcR+jQQc91VYehTWk3auPVXTtJz3ZK5EpJQxhXhBOBwe
L4QQ3wXgtiUmCuHbNJKxvFiO28RjpJTXCCGEagex6OvpkQAzqyx2MwUAh1KZ+Ujxu1T6EJFDT8w8
SwCYnUvmUZyo9EREswWAb9oTmHlQV1EljEpP0wTSR2l6QUSni9+f0ieDniYIABPsUiHE6KQ/B1Kp
1FmFeIKAwoW7q6tLlXkUG11dXWcU4gkCwDi7tLKysrP4XSp9rr76apV7fbkA4FDgyZMnHYoexUlz
c3O5QtwhkD4l0ouysjLHfXYUJ2VlZY6HPICzAk4TFqSUOVver2Q0TVMNvrMC6ZPJvZBS2jf/RlHA
zFMV4jMCgMMvn4i+VfwulT6KPT0A+FIAUC1JVZlHcaK0myiVqvJ9H0WJysJ3RDCz4wSedXh2lL6Z
o5AdFaZpHobT68Kbixv2lczixYtnAJhmE18QQhwWjY2N7UT0ob2QdRp5lAykUqmgXcbMh+rr68/1
7KaqNrH0oveshCEih1KJaD9g7aYKIVSbfD/Mx/3mSiIcDo8HUGuXCyEaAEupLpfrAIAWW57xbrf7
R0XvYQlimuZP4LTunZo0adIlXyorzNAb9sKX+weNcgkiUvmd7egJwHDRQY2Z/6LIqAeDwdGFwGWE
w+HZABwPceu8Wfp7z5dYLHYQgP1MqIuIHi5aD0sQKeUjcPr1flZfX38xBos9cbOintsCgcD0Qneu
FNF13Qfgp3Y5M28EwD1/91KqEOJlACdtZdxEtK4YnSw1mPlROA+f/Le8vPyVywW9lGp5szmOXxPR
imAweH3Be1lCBAKB+UR0u11ORM/aoxapDqdtRDo4S698RJTxhNtIx+/3a0S0BU59ne7o6HDEQHCc
ozIMo03X9UcBvGBLmtPS0vIAgH4Fa8mV5ubmbo/Hozocl4n/FK0zFpqmPQjgWruciNYdOHDAsR2l
DKKwfv16ceDAgYOKaDjdAG4cjhF8ikUwGJxHRP8EYD+O3uTxeBaoDnFkjExhBWx5H84hf9zlcs15
99137SuwEYff75+sadrHcMYQlEKIG+rr699Xlct4NN066KqKGTI9lUptHen3V7/fr2math2KoIzM
/GwmhQJ9BFFIJpNrARy0y4moLplMvoohihQ8CJDb7X4JwBJF2odTpkz5ZbbCWUfbiRMnpM/niwK4
A05Plmt9Pp8Wj8dVZsOSJhQKPcXM9yuSWoUQoV27dmV14OvzEo7H420+n+8IgKVwjswbfT6fO5+Y
TcMcshSqOt9vMvMywzD6DAma8+VrHc1+SVkJ0Wvd3d0/K0RcqqHCiku1GcDKDFnuNwzDPs1UkvPD
JpFINHm9XkFEP1AkXyeEuM7n8+2Nx+ODHq18oCxZssTT3t7+BoBbM2R53DCMZ3KtL68neCKRaPR6
vZVEpIrmOAvA0qqqqvfi8XhzPvUOJYFAYL5pmkaG3wQAGw3DWJtPnXlPixKJxD+qqqpcAFQj1gPg
Dq/X2zF37twPPvnkE1bkGRb4/X5txowZPyei7USkct8B0iM0L4UCA5gSBYPBVUT0AjJPy/4tpVw9
mPH1c8Va2GwCMC9DFpOI1kSjUeUzpC8GNM/Udf0mAFvhjLnSgwSwVdO0DcPhsFs4HPaapvkYEd2B
zL89ycy3x2Kx3f1tZ8CTd13XpwHYASCbaVACeBPArw3DKLoBxI5lXF4LYAWyv07kIwDLDMNQBfjK
mYKsiCKRyJhkMvk0gAfQR5RyIooB2Nbd3f1WMU9p+/3+Ck3TbkE6CtqivvrFzM+2trY+0tTUZPfW
yZuCLjMDgcB8IcQmALn4Yp0DsBtATErZMNCI5UDaFcc0zQCAINJLzPE5FPuQiFZZto6CUJQ3UrS2
tt7LzBuQ30tnjgNoAnCUiI6YpnmUmU8TUbsQot2y806SUlYwc4WmaVdZ/qE9n7lw+jZl4zQRraup
qdmyfv16mUe5PimaQcTv91e43e67mHktgG8Uq51+cBLAplQq9cfGxkb7DkdBKLqVqa6urvz8+fMr
mXkVhtaZ+Cgzv9jR0fHywYMHi3qkaVBNd7quL2Tm24joVgCZJtyF5BTSb8LYns3+WWiGxB5aXV3t
njp16vVWzJEggAVwBnLoDxcAvA+ggZljra2thwrxNM+XYWFktmIMXkNEs5F+x98spB86E5F2BKvA
pXf8tVufMwCOE9FRKeURl8v1aVlZ2eFivuQmV/4PUneNf67+Z0cAAAAASUVORK5CYII=
"
id="image10" />
xlink:href="data:image/png;base64,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 "
id="image10"
x="0"
y="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

View file

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="86"
height="86"
viewBox="0 0 86 86"
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg12"
sodipodi:docname="menu_infos.svg"
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"
@ -30,25 +30,27 @@
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
inkscape:current-layer="svg12"
width="15px" />
<g
fill="none"
fill-rule="evenodd"
id="g10">
id="g10"
transform="matrix(0.17647011,0,0,0.17647155,-0.08823505,-0.08823577)">
<g
transform="translate(3.000000, 3.000000)"
transform="translate(3,3)"
id="g8">
<circle
cx="40"
cy="40"
r="40"
stroke="#444"
stroke="#444444"
stroke-width="5"
id="circle2" />
<text
fill="#444"
fill="#444444"
font-family="Baskerville-Bold, Baskerville"
font-size="65"
font-size="65px"
font-weight="bold"
id="text6"><tspan
x="29"

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -1,13 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g>
<path class="st0" d="M315.1,452.9c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,420.3,315.1,452.9z
M315.1,256c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,223.4,315.1,256z M315.1,59.1
c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1S223.4,0,256,0S315.1,26.5,315.1,59.1z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 30 30"
xml:space="preserve"
sodipodi:docname="menu_vdots_hovered.svg"
width="30"
height="30"
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="defs11" /><sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="false"
showgrid="false"
width="15px"
showguides="false"
borderlayer="false"
inkscape:zoom="27.28125"
inkscape:cx="2.7308133"
inkscape:cy="12.077892"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1"
height="30px" />
<style
type="text/css"
id="style2">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g
id="g6"
transform="matrix(0.05922166,0,0,0.05859375,-0.16074485,0)">
<path
class="st0"
d="m 315.1,452.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 C 196.9,26.5 223.4,0 256,0 c 32.6,0 59.1,26.5 59.1,59.1 z"
id="path4" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,13 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g>
<path class="st0" d="M315.1,452.9c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,420.3,315.1,452.9z
M315.1,256c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,223.4,315.1,256z M315.1,59.1
c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1S223.4,0,256,0S315.1,26.5,315.1,59.1z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 30 30"
xml:space="preserve"
sodipodi:docname="menu_vdots_hovered.svg"
width="30"
height="30"
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="defs11" /><sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="false"
showgrid="false"
width="15px"
showguides="false"
borderlayer="false"
inkscape:zoom="27.28125"
inkscape:cx="2.7308133"
inkscape:cy="12.077892"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1"
height="30px" />
<style
type="text/css"
id="style2">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g
id="g6"
transform="matrix(0.05922166,0,0,0.05859375,-0.16074485,0)">
<path
class="st0"
d="m 315.1,452.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 C 196.9,26.5 223.4,0 256,0 c 32.6,0 59.1,26.5 59.1,59.1 z"
id="path4" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,13 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g>
<path class="st0" d="M315.1,452.9c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,420.3,315.1,452.9z
M315.1,256c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1s26.5-59.1,59.1-59.1S315.1,223.4,315.1,256z M315.1,59.1
c0,32.6-26.5,59.1-59.1,59.1s-59.1-26.5-59.1-59.1S223.4,0,256,0S315.1,26.5,315.1,59.1z"/>
</g>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 24.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg
version="1.1"
id="Layer_1"
x="0px"
y="0px"
viewBox="0 0 30 30"
xml:space="preserve"
sodipodi:docname="menu_vdots_hovered.svg"
width="30"
height="30"
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="defs11" /><sodipodi:namedview
id="namedview9"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="false"
showgrid="false"
width="15px"
showguides="false"
borderlayer="false"
inkscape:zoom="27.28125"
inkscape:cx="2.7308133"
inkscape:cy="12.077892"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1"
height="30px" />
<style
type="text/css"
id="style2">
.st0{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g
id="g6"
transform="matrix(0.05922166,0,0,0.05859375,-0.16074485,0)">
<path
class="st0"
d="m 315.1,452.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 0,-32.6 26.5,-59.1 59.1,-59.1 32.6,0 59.1,26.5 59.1,59.1 z m 0,-196.9 c 0,32.6 -26.5,59.1 -59.1,59.1 -32.6,0 -59.1,-26.5 -59.1,-59.1 C 196.9,26.5 223.4,0 256,0 c 32.6,0 59.1,26.5 59.1,59.1 z"
id="path4" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
id="svg21"
sodipodi:docname="new_chat_group_hovered.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
id="namedview23"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,88 +20,74 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="22.130584"
inkscape:cy="40"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="19.954181"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="svg21" />
<defs
id="defs5">
<filter
id="inzgn8a8ga"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<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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
+C+VtQmfiJTG7gAAAABJRU5ErkJggg==
"
id="image10" />
fill="none"
fill-rule="evenodd"
id="g19">
<g
id="g17">
<path
fill="#4B5964"
d="M0 5.005C0 2.241 2.236 0 5.005 0h29.99C37.759 0 40 2.236 40 5.005v29.99C40 37.759 37.764 40 34.995 40H5.005C2.241 40 0 37.764 0 34.995V5.005z"
transform="translate(20.000000, 20.000000) scale(1, -1) translate(-20.000000, -20.000000)"
id="path7" />
<g
filter="url(#inzgn8a8ga)"
id="g15">
<g
fill="#444"
fill-rule="nonzero"
id="g13">
<path
d="M24.656 7.186c.547 0 1.074-.115 1.548-.331.026-.012.052-.022.08-.03.032-.01.112-.04.224-.095.194-.097.39-.225.572-.389.158-.141.298-.303.416-.486.232-.36.381-.7.464-1.01.028-.102.046-.192.056-.267l.006-.056.003-.05c.01-.091.014-.183.014-.275 0-1.636-1.501-2.989-3.383-2.989-1.882 0-3.383 1.353-3.383 2.99 0 .779.34 1.513.944 2.07.097.089.162.207.185.337l.008.04c.084.342.084.656.014.942.156-.098.285-.195.397-.291.038-.033.07-.063.099-.09l.023-.022.015-.015.017-.016c.01-.01.01-.01.057-.045l.054-.034.455-.054c.365.11.735.166 1.115.166zm0 1.208c-.38 0-.754-.042-1.116-.125-.138.115-.292.227-.461.333-.774.486-1.635.711-2.542.509-.61-.136-.637-.995-.038-1.17.015-.004.057-.019.116-.045.104-.045.207-.101.3-.169.27-.192.388-.405.338-.71-.757-.764-1.189-1.76-1.189-2.82 0-2.333 2.07-4.197 4.592-4.197 2.523 0 4.592 1.864 4.592 4.197 0 .126-.006.251-.018.376-.006.136-.035.336-.103.588-.115.426-.314.881-.615 1.348-.179.277-.39.52-.625.732-.268.24-.555.428-.842.571-.152.076-.28.127-.374.158-.623.278-1.308.424-2.015.424zM22.8 2.957h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zm0 1.514h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zM4.657 17.308c1.211.363 2.457.594 3.69.718.898.09 1.662.11 2.231.095l.11-.005h.112l.142.005c.57.016 1.333-.006 2.232-.095 1.232-.124 2.478-.355 3.69-.718.182-.987.005-2.103-.81-3.17-.618-.811-1.57-1.529-2.915-2.12-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.356-.692-.06-.953.046-.055.056-.067.099-.113.507-.547.794-1.265.794-2.03 0-1.642-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.968 0 .766.287 1.484.794 2.032.043.046.05.054.088.103.307.269.278.74-.05.962l-.148.1c-.03.02-.062.039-.096.053-1.344.591-2.296 1.309-2.915 2.12-.814 1.067-.992 2.183-.81 3.17zm6.079 2.016l-.123.004c-.618.018-1.434-.005-2.387-.1-1.42-.142-2.86-.42-4.259-.869-.18-.058-.324-.197-.386-.377-.029-.082-.066-.216-.101-.396-.258-1.31-.035-2.79 1.026-4.181.653-.858 1.59-1.609 2.833-2.232-.486-.695-.754-1.53-.754-2.405 0-2.305 1.852-4.176 4.141-4.176h.068c2.29 0 4.142 1.87 4.142 4.176 0 .876-.269 1.71-.755 2.405 1.244.623 2.18 1.374 2.834 2.232 1.061 1.39 1.284 2.87 1.026 4.181-.036.18-.073.314-.101.396-.063.18-.206.32-.387.377-1.399.448-2.838.727-4.259.869-.953.095-1.768.118-2.387.1l-.122-.004h-.05z"
transform="translate(6.873063, 9.879167)"
id="path9" />
<path
d="M14.878 8.768c0 .876-.268 1.71-.755 2.405 1.863.932 3.02 2.14 3.574 3.523 1.058-.081 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.635-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.953.027-.033.038-.046.072-.082.387-.418.606-.966.606-1.552 0-1.253-1.004-2.266-2.239-2.266h-.054c-.866 0-1.637.502-2.008 1.262.498.701.773 1.546.773 2.431zm2.835.227zm-4.146 1.917l-.243.553.34-.5-.045-.03-.052-.023zm-.69-.113c.506-.547.793-1.265.793-2.03 0-.725-.256-1.406-.714-1.942-.138-.16-.181-.381-.115-.582.464-1.408 1.775-2.378 3.272-2.378h.054c1.905 0 3.447 1.557 3.447 3.474 0 .682-.195 1.333-.552 1.888.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.333-.062.18-.205.32-.386.378-1.452.465-2.931.7-4.327.769-.278.013-.529-.164-.609-.431-.405-1.36-1.524-2.561-3.618-3.482-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.355-.692-.06-.953.046-.055.056-.067.1-.113zM7.34 11.173c-.487-.695-.755-1.53-.755-2.405 0-1.11.432-2.147 1.177-2.917-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.013-2.238 2.266 0 .586.219 1.134.607 1.552.034.037.043.047.07.081.296.26.267.732-.06.954l-.12.08c-.03.021-.062.04-.095.054-1.063.467-1.812 1.031-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.246 1.695.414 2.546.516.565-1.355 1.715-2.538 3.545-3.454zM4.474 8.996v-.001zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.899l-.148.1c-.03.02-.062.039-.096.053-2.07.91-3.187 2.097-3.604 3.438-.085.273-.349.449-.633.423-1.193-.11-2.409-.339-3.591-.717-.181-.058-.324-.198-.387-.378-.024-.07-.056-.184-.085-.334-.214-1.083-.03-2.307.846-3.455.516-.676 1.243-1.27 2.199-1.766-.357-.555-.552-1.206-.552-1.888 0-1.917 1.541-3.474 3.446-3.474h.055c1.265 0 2.409.693 3.013 1.785.143.26.077.585-.156.768-.714.56-1.14 1.417-1.14 2.348 0 .766.288 1.484.795 2.032.043.046.05.054.088.103.307.269.278.74-.05.962z"
transform="translate(6.873063, 9.879167)"
id="path11" />
</g>
</g>
</g>
</g>
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 16.517755,29.177847 c -1.742172,-0.05702 -3.562423,-0.349463 -5.282977,-0.84876 -0.617676,-0.179246 -0.718323,-0.275 -0.841605,-0.800682 -0.06349,-0.270704 -0.0839,-0.541807 -0.0839,-1.114402 V 25.65733 L 9.6678121,25.551643 C 8.8808501,25.421985 7.6782755,25.119886 7.3997709,24.981889 7.1338148,24.850109 7.0153048,24.620168 6.9400281,24.089864 6.6782829,22.24594 7.7050138,20.457029 9.6792669,19.317186 c 0.1827033,-0.105484 0.3321881,-0.202672 0.3321881,-0.215974 0,-0.0133 -0.051764,-0.112512 -0.1150309,-0.220469 C 9.6127674,18.39672 9.4261313,17.537006 9.4796654,16.961 c 0.1766349,-1.900522 1.7567216,-3.28644 3.6237396,-3.178437 0.821236,0.04751 1.565958,0.36182 2.150323,0.907553 l 0.335912,0.313704 0.379419,-0.164423 c 0.904146,-0.391816 1.996426,-0.446092 2.931285,-0.145658 0.343684,0.11045 0.765414,0.313589 1.035311,0.498692 l 0.187661,0.128702 0.224711,-0.281924 c 0.421979,-0.529418 1.124912,-0.986213 1.782557,-1.158378 0.913299,-0.239093 1.968791,-0.07144 2.746545,0.436268 0.344428,0.224838 0.834894,0.720203 1.048542,1.059016 0.645546,1.023742 0.704597,2.349477 0.151873,3.409681 -0.07883,0.151203 -0.149288,0.287211 -0.156579,0.302239 -0.0073,0.01503 0.1472,0.120659 0.343314,0.234734 1.168737,0.679831 2.095331,1.684398 2.484516,2.693588 0.2191,0.568146 0.292947,1.034066 0.264542,1.669062 -0.02903,0.648943 -0.111195,0.990176 -0.281134,1.167556 -0.235681,0.245996 -1.835101,0.642687 -3.360369,0.833444 l -0.424272,0.05306 0.02782,0.486503 c 0.04852,0.848484 -0.139423,1.729631 -0.406194,1.904426 -0.346214,0.226848 -2.549505,0.733755 -3.881901,0.893103 -1.078058,0.128929 -2.893104,0.196113 -4.16953,0.154335 z m 2.980532,-1.207138 c 1.270238,-0.09815 2.443538,-0.286873 3.555777,-0.571936 0.347892,-0.08916 0.653563,-0.183243 0.679268,-0.209065 0.0278,-0.02793 0.04674,-0.339145 0.04674,-0.768169 0,-0.575296 -0.01448,-0.743974 -0.07158,-0.833692 -0.03937,-0.06186 -0.127976,-0.269217 -0.196907,-0.460792 -0.444245,-1.234659 -1.519198,-2.271189 -3.206135,-3.091535 -0.556801,-0.270769 -0.743651,-0.420882 -0.806298,-0.647769 -0.06223,-0.225375 0.0019,-0.377739 0.316624,-0.752523 0.501087,-0.596669 0.732699,-1.22474 0.732699,-1.986889 0,-0.711476 -0.169888,-1.220929 -0.620259,-1.860007 -0.4856,-0.689069 -1.169755,-1.053625 -2.104618,-1.121457 -1.340168,-0.09724 -2.57947,0.740518 -3.022632,2.043275 -0.116565,0.342666 -0.132147,0.453054 -0.132429,0.938189 -2.75e-4,0.481556 0.01536,0.595288 0.12599,0.91594 0.14659,0.424891 0.360359,0.794637 0.640389,1.107649 0.24953,0.278921 0.303917,0.382409 0.303917,0.578307 0,0.300246 -0.150067,0.436783 -0.918813,0.835973 -0.949354,0.492975 -1.486101,0.867411 -2.036514,1.420679 -0.751836,0.755736 -1.190774,1.605583 -1.310186,2.53671 -0.05029,0.392121 -0.02702,1.025378 0.04175,1.136155 0.09156,0.147497 2.56409,0.641733 3.71975,0.743545 0.315006,0.02775 0.644903,0.05719 0.733105,0.06541 0.404972,0.03776 2.978514,0.02464 3.53036,-0.018 z m 6.504004,-3.552544 c 0.365407,-0.06116 0.924974,-0.175568 1.243482,-0.254246 l 0.579107,-0.143051 0.02749,-0.166219 C 27.972236,23.129911 27.658906,22.1528 27.083912,21.458233 26.660436,20.946693 25.975438,20.442047 25.191795,20.064287 24.682392,19.818726 24.5069,19.6781 24.449236,19.469257 c -0.0617,-0.223473 -0.0019,-0.383878 0.260767,-0.699515 0.636222,-0.764498 0.762693,-1.701087 0.346538,-2.566308 -0.502119,-1.04395 -1.726938,-1.527768 -2.857682,-1.128818 -0.398684,0.140664 -0.867266,0.516918 -1.103256,0.885875 l -0.127124,0.19875 0.163668,0.255853 c 0.859217,1.343174 0.86108,3.032285 0.0049,4.473838 -0.05838,0.09831 -0.08549,0.185949 -0.06024,0.194762 0.139337,0.04863 1.111358,0.655065 1.423055,0.88783 0.809325,0.604378 1.576815,1.498178 1.93411,2.252417 l 0.170806,0.360568 0.366552,-0.02757 c 0.201604,-0.01517 0.665521,-0.07761 1.030928,-0.13877 z m -15.17959,-0.19394 c 0.265312,-0.55403 0.613245,-1.024879 1.157728,-1.566722 0.566907,-0.564158 1.01498,-0.905531 1.673637,-1.275092 0.62985,-0.353399 0.599065,-0.308277 0.411037,-0.60246 -0.21024,-0.328934 -0.407889,-0.848395 -0.50482,-1.326769 -0.104641,-0.516427 -0.07209,-1.434693 0.06832,-1.927409 0.137353,-0.481978 0.461729,-1.112666 0.762129,-1.481815 0.140282,-0.172387 0.245113,-0.33935 0.232956,-0.37103 -0.04177,-0.108839 -0.581033,-0.477668 -0.843941,-0.577207 -1.242275,-0.470337 -2.582955,0.138839 -3.018037,1.371332 -0.131602,0.3728 -0.147816,1.000866 -0.03569,1.382592 0.101285,0.344828 0.306209,0.711944 0.545077,0.97649 0.230036,0.254764 0.282279,0.417535 0.207113,0.645288 -0.07025,0.212863 -0.244725,0.350714 -0.786867,0.621696 -1.0820556,0.540849 -1.7170263,1.083685 -2.2012095,1.881809 -0.3057974,0.504075 -0.4750842,1.228934 -0.4176479,1.788301 l 0.026499,0.258075 0.5782281,0.142624 c 0.4911105,0.121135 0.7862301,0.177285 1.7924323,0.341034 0.063,0.01025 0.135166,0.02029 0.160366,0.0223 0.0252,0.002 0.111911,-0.134354 0.19269,-0.303039 z"
id="path51" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 27.527906,18.989715 c -0.264205,-0.05219 -0.369883,-0.116175 -0.474058,-0.287026 -0.201486,-0.330443 -0.07575,-0.667754 0.314818,-0.844585 0.556427,-0.251923 0.787119,-0.496013 0.787119,-0.832833 0,-0.102208 -0.05066,-0.198279 -0.177556,-0.336718 -0.238042,-0.259697 -0.564517,-0.772782 -0.706414,-1.110196 -0.222949,-0.530143 -0.279377,-0.828921 -0.281219,-1.48901 -0.002,-0.733448 0.06859,-1.058586 0.363345,-1.672394 0.626448,-1.304554 1.88562,-2.206189 3.425602,-2.4529176 0.539255,-0.086397 1.509649,-0.03411 2.026872,0.1092126 1.483459,0.411066 2.641988,1.464842 3.093344,2.813647 0.126019,0.376587 0.152962,0.534109 0.172203,1.006766 0.03115,0.765078 -0.07983,1.289728 -0.414524,1.959718 -0.336852,0.67431 -0.77484,1.183786 -1.342243,1.561323 -1.038705,0.691131 -2.536472,0.994612 -3.688916,0.747457 -0.210653,-0.04518 -0.222146,-0.04177 -0.456278,0.135441 -0.751319,0.568652 -1.832861,0.851969 -2.642095,0.692115 z m 1.912071,-1.587087 c 0.06231,-0.04253 0.201752,-0.154112 0.309875,-0.247961 0.256635,-0.222755 0.510827,-0.261992 0.996819,-0.153869 0.271369,0.06038 0.490477,0.07337 0.954006,0.0566 0.521386,-0.01887 0.659457,-0.04132 1.034087,-0.168147 0.668794,-0.226415 1.010874,-0.427093 1.366863,-0.801856 0.349988,-0.368447 0.636685,-0.897562 0.761464,-1.405328 0.25034,-1.018704 -0.192051,-2.19232 -1.0772,-2.857698 -0.631794,-0.474929 -1.268552,-0.702581 -2.079133,-0.743325 -1.414353,-0.07109 -2.738308,0.647315 -3.290077,1.785274 -0.212556,0.438371 -0.282062,0.749507 -0.278335,1.245939 0.0053,0.710554 0.252971,1.31669 0.774514,1.895761 0.196294,0.217946 0.310106,0.389133 0.345093,0.519065 0.05519,0.204977 0.06951,0.82759 0.02084,0.906343 -0.04366,0.07064 0.03444,0.05572 0.161188,-0.0308 z"
id="path103" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,15.508159 c -0.49193,-0.14729 -0.560004,-0.852438 -0.103219,-1.069197 0.137886,-0.06543 0.400194,-0.0747 2.113789,-0.0747 2.235432,0 2.210772,-0.0037 2.367773,0.351267 0.150765,0.340831 -0.01604,0.691362 -0.378461,0.795303 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path142" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,13.996132 c -0.49193,-0.14729 -0.560004,-0.852439 -0.103219,-1.069197 0.137874,-0.06543 0.399963,-0.0747 2.110731,-0.0747 2.23954,0 2.213806,-0.0037 2.366539,0.341564 0.07597,0.171738 0.08357,0.237211 0.04444,0.382538 -0.05662,0.210256 -0.206658,0.36168 -0.41861,0.422467 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path181" />
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
id="svg21"
sodipodi:docname="new_chat_group_normal.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
id="namedview23"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,81 +20,74 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="22.130584"
inkscape:cy="40"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="19.862543"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="svg21" />
<defs
id="defs5">
<filter
id="mqanwmw2ka"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<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" />
fill="none"
fill-rule="evenodd"
id="g19">
<g
id="g17">
<path
fill="#FF5E00"
d="M0 5.005C0 2.241 2.236 0 5.005 0h29.99C37.759 0 40 2.236 40 5.005v29.99C40 37.759 37.764 40 34.995 40H5.005C2.241 40 0 37.764 0 34.995V5.005z"
transform="translate(20.000000, 20.000000) scale(1, -1) translate(-20.000000, -20.000000)"
id="path7" />
<g
filter="url(#mqanwmw2ka)"
id="g15">
<g
fill="#444"
fill-rule="nonzero"
id="g13">
<path
d="M24.656 7.186c.547 0 1.074-.115 1.548-.331.026-.012.052-.022.08-.03.032-.01.112-.04.224-.095.194-.097.39-.225.572-.389.158-.141.298-.303.416-.486.232-.36.381-.7.464-1.01.028-.102.046-.192.056-.267l.006-.056.003-.05c.01-.091.014-.183.014-.275 0-1.636-1.501-2.989-3.383-2.989-1.882 0-3.383 1.353-3.383 2.99 0 .779.34 1.513.944 2.07.097.089.162.207.185.337l.008.04c.084.342.084.656.014.942.156-.098.285-.195.397-.291.038-.033.07-.063.099-.09l.023-.022.015-.015.017-.016c.01-.01.01-.01.057-.045l.054-.034.455-.054c.365.11.735.166 1.115.166zm0 1.208c-.38 0-.754-.042-1.116-.125-.138.115-.292.227-.461.333-.774.486-1.635.711-2.542.509-.61-.136-.637-.995-.038-1.17.015-.004.057-.019.116-.045.104-.045.207-.101.3-.169.27-.192.388-.405.338-.71-.757-.764-1.189-1.76-1.189-2.82 0-2.333 2.07-4.197 4.592-4.197 2.523 0 4.592 1.864 4.592 4.197 0 .126-.006.251-.018.376-.006.136-.035.336-.103.588-.115.426-.314.881-.615 1.348-.179.277-.39.52-.625.732-.268.24-.555.428-.842.571-.152.076-.28.127-.374.158-.623.278-1.308.424-2.015.424zM22.8 2.957h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zm0 1.514h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zM4.657 17.308c1.211.363 2.457.594 3.69.718.898.09 1.662.11 2.231.095l.11-.005h.112l.142.005c.57.016 1.333-.006 2.232-.095 1.232-.124 2.478-.355 3.69-.718.182-.987.005-2.103-.81-3.17-.618-.811-1.57-1.529-2.915-2.12-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.356-.692-.06-.953.046-.055.056-.067.099-.113.507-.547.794-1.265.794-2.03 0-1.642-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.968 0 .766.287 1.484.794 2.032.043.046.05.054.088.103.307.269.278.74-.05.962l-.148.1c-.03.02-.062.039-.096.053-1.344.591-2.296 1.309-2.915 2.12-.814 1.067-.992 2.183-.81 3.17zm6.079 2.016l-.123.004c-.618.018-1.434-.005-2.387-.1-1.42-.142-2.86-.42-4.259-.869-.18-.058-.324-.197-.386-.377-.029-.082-.066-.216-.101-.396-.258-1.31-.035-2.79 1.026-4.181.653-.858 1.59-1.609 2.833-2.232-.486-.695-.754-1.53-.754-2.405 0-2.305 1.852-4.176 4.141-4.176h.068c2.29 0 4.142 1.87 4.142 4.176 0 .876-.269 1.71-.755 2.405 1.244.623 2.18 1.374 2.834 2.232 1.061 1.39 1.284 2.87 1.026 4.181-.036.18-.073.314-.101.396-.063.18-.206.32-.387.377-1.399.448-2.838.727-4.259.869-.953.095-1.768.118-2.387.1l-.122-.004h-.05z"
transform="translate(6.873063, 9.879167)"
id="path9" />
<path
d="M14.878 8.768c0 .876-.268 1.71-.755 2.405 1.863.932 3.02 2.14 3.574 3.523 1.058-.081 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.635-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.953.027-.033.038-.046.072-.082.387-.418.606-.966.606-1.552 0-1.253-1.004-2.266-2.239-2.266h-.054c-.866 0-1.637.502-2.008 1.262.498.701.773 1.546.773 2.431zm2.835.227zm-4.146 1.917l-.243.553.34-.5-.045-.03-.052-.023zm-.69-.113c.506-.547.793-1.265.793-2.03 0-.725-.256-1.406-.714-1.942-.138-.16-.181-.381-.115-.582.464-1.408 1.775-2.378 3.272-2.378h.054c1.905 0 3.447 1.557 3.447 3.474 0 .682-.195 1.333-.552 1.888.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.333-.062.18-.205.32-.386.378-1.452.465-2.931.7-4.327.769-.278.013-.529-.164-.609-.431-.405-1.36-1.524-2.561-3.618-3.482-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.355-.692-.06-.953.046-.055.056-.067.1-.113zM7.34 11.173c-.487-.695-.755-1.53-.755-2.405 0-1.11.432-2.147 1.177-2.917-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.013-2.238 2.266 0 .586.219 1.134.607 1.552.034.037.043.047.07.081.296.26.267.732-.06.954l-.12.08c-.03.021-.062.04-.095.054-1.063.467-1.812 1.031-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.246 1.695.414 2.546.516.565-1.355 1.715-2.538 3.545-3.454zM4.474 8.996v-.001zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.899l-.148.1c-.03.02-.062.039-.096.053-2.07.91-3.187 2.097-3.604 3.438-.085.273-.349.449-.633.423-1.193-.11-2.409-.339-3.591-.717-.181-.058-.324-.198-.387-.378-.024-.07-.056-.184-.085-.334-.214-1.083-.03-2.307.846-3.455.516-.676 1.243-1.27 2.199-1.766-.357-.555-.552-1.206-.552-1.888 0-1.917 1.541-3.474 3.446-3.474h.055c1.265 0 2.409.693 3.013 1.785.143.26.077.585-.156.768-.714.56-1.14 1.417-1.14 2.348 0 .766.288 1.484.795 2.032.043.046.05.054.088.103.307.269.278.74-.05.962z"
transform="translate(6.873063, 9.879167)"
id="path11" />
</g>
</g>
</g>
</g>
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 16.494845,29.178175 c -1.768895,-0.06448 -3.540258,-0.35045 -5.260067,-0.849187 -0.617674,-0.179123 -0.718313,-0.274855 -0.841605,-0.800583 -0.06362,-0.271286 -0.0839,-0.541986 -0.0839,-1.120246 V 25.645643 L 10.057274,25.61642 C 9.2497315,25.522777 7.4166963,25.063708 7.2458642,24.912324 6.889066,24.596146 6.791109,23.319917 7.0541971,22.415197 c 0.3542798,-1.218314 1.2195108,-2.260043 2.5233927,-3.038139 0.2386257,-0.1424 0.4338652,-0.268162 0.4338652,-0.27947 0,-0.01131 -0.051764,-0.108888 -0.1150309,-0.216845 C 9.8331572,18.772786 9.7316224,18.538126 9.6707912,18.359274 9.219476,17.032352 9.5623261,15.647722 10.577298,14.698265 c 1.316242,-1.231279 3.363424,-1.234352 4.677638,-0.007 l 0.337119,0.314832 0.312717,-0.140306 c 0.503414,-0.225867 0.909194,-0.321118 1.492803,-0.350416 0.960698,-0.04823 1.81064,0.178533 2.53808,0.67715 l 0.187661,0.128629 0.224711,-0.281924 c 0.421979,-0.529418 1.124912,-0.986213 1.782557,-1.158378 0.680573,-0.178168 1.541067,-0.121952 2.193924,0.143327 0.795352,0.323181 1.531624,1.060815 1.876332,1.879807 0.377346,0.896534 0.329572,2.013165 -0.123296,2.881831 -0.07883,0.151203 -0.149288,0.287211 -0.156579,0.302239 -0.0073,0.01503 0.1472,0.120659 0.343314,0.234734 1.062933,0.618287 1.873211,1.43704 2.3253,2.349625 0.329742,0.665615 0.41238,1.027594 0.413179,1.809851 0.0012,1.13309 -0.125967,1.423274 -0.699876,1.597593 -0.828183,0.251554 -1.955403,0.485451 -2.909386,0.603697 l -0.448429,0.05558 0.03039,0.441189 c 0.03262,0.473633 -0.02739,1.085627 -0.150027,1.530061 -0.120102,0.435238 -0.227448,0.491137 -1.618095,0.842603 -1.060976,0.268147 -2.180866,0.452887 -3.413517,0.563105 -0.526306,0.04706 -2.626841,0.0866 -3.298969,0.0621 z m 3.003442,-1.207466 c 1.270238,-0.09815 2.443538,-0.286873 3.555777,-0.571936 0.347892,-0.08916 0.653563,-0.183243 0.679268,-0.209065 0.02779,-0.02792 0.04674,-0.338481 0.04674,-0.766096 0,-0.599135 -0.01327,-0.742083 -0.07949,-0.856602 -0.04372,-0.0756 -0.132281,-0.281567 -0.196805,-0.457701 -0.449444,-1.226862 -1.523996,-2.259573 -3.198327,-3.073789 -0.544772,-0.264919 -0.735822,-0.414918 -0.80834,-0.634652 -0.0706,-0.213911 0.0022,-0.388798 0.318666,-0.76564 0.501087,-0.596669 0.732699,-1.22474 0.732699,-1.986889 0,-0.706731 -0.170356,-1.221675 -0.61091,-1.846633 -0.366969,-0.520572 -0.788085,-0.820973 -1.420501,-1.013306 -1.569537,-0.477336 -3.208991,0.380531 -3.720372,1.946736 -0.11356,0.3478 -0.13347,0.481376 -0.132702,0.890294 0.0014,0.747275 0.210638,1.353582 0.655384,1.899116 0.375832,0.461004 0.419459,0.535115 0.419459,0.712567 0,0.315092 -0.140514,0.444944 -0.918813,0.849095 -0.914824,0.475044 -1.47497,0.860689 -1.994456,1.373128 -0.765356,0.754972 -1.2206,1.617146 -1.350193,2.557092 -0.04975,0.360873 -0.02577,1.057862 0.04005,1.163885 0.04386,0.07064 1.368773,0.394519 2.184467,0.53399 0.642116,0.109793 1.673455,0.237499 2.199313,0.272332 0.572185,0.0379 3.044032,0.02696 3.599089,-0.01593 z m 6.504004,-3.552544 c 0.365407,-0.06116 0.924974,-0.175568 1.243482,-0.254246 l 0.579107,-0.143051 0.02749,-0.166219 C 27.972236,23.129911 27.658906,22.1528 27.083912,21.458233 26.660436,20.946693 25.975438,20.442047 25.191795,20.064287 24.682392,19.818726 24.5069,19.6781 24.449236,19.469257 c -0.06149,-0.222702 -0.0044,-0.374604 0.267123,-0.711304 0.636868,-0.789611 0.756604,-1.688742 0.340182,-2.554519 -0.501247,-1.042137 -1.728902,-1.527075 -2.857682,-1.128818 -0.398684,0.140664 -0.867266,0.516918 -1.103256,0.885875 l -0.127124,0.19875 0.163668,0.255853 c 0.861059,1.346053 0.862916,3.029196 0.0049,4.473838 -0.05838,0.09831 -0.08549,0.185949 -0.06024,0.194762 0.146692,0.0512 1.12099,0.662056 1.451039,0.909761 0.803412,0.60297 1.547756,1.473978 1.906126,2.230486 l 0.170806,0.360568 0.366552,-0.02757 c 0.201604,-0.01517 0.665521,-0.07761 1.030928,-0.13877 z M 10.879175,24.120299 c 0.512183,-1.030272 1.541477,-2.04584 2.774891,-2.737888 0.62985,-0.353399 0.599065,-0.308277 0.411037,-0.60246 -0.21024,-0.328934 -0.407889,-0.848395 -0.50482,-1.326769 -0.104641,-0.516427 -0.07209,-1.434693 0.06832,-1.927409 0.139077,-0.488031 0.464061,-1.12194 0.757663,-1.477887 0.157946,-0.191485 0.241519,-0.331237 0.224541,-0.37548 -0.04578,-0.11929 -0.55347,-0.471586 -0.83106,-0.576685 -0.985748,-0.373214 -2.057009,-0.07592 -2.676885,0.742885 -0.308269,0.407196 -0.410691,0.700511 -0.438275,1.255123 -0.03454,0.694515 0.131769,1.179764 0.579833,1.691792 0.255496,0.291969 0.31052,0.453403 0.233788,0.685902 -0.07025,0.212863 -0.244725,0.350714 -0.786867,0.621696 -1.0455005,0.522578 -1.7394485,1.109948 -2.1862883,1.850513 -0.3159287,0.523601 -0.490696,1.259853 -0.4326223,1.822533 l 0.026403,0.255818 0.585367,0.142732 c 0.4945479,0.120587 0.8388293,0.186195 1.7854426,0.340247 0.063,0.01025 0.135166,0.01993 0.160366,0.02151 0.0252,0.0016 0.137325,-0.1812 0.249164,-0.406169 z"
id="path51" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 27.527906,18.992721 c -0.266698,-0.05685 -0.370655,-0.120447 -0.474058,-0.290032 -0.201486,-0.330443 -0.07575,-0.667754 0.314818,-0.844585 0.38794,-0.175641 0.628317,-0.355173 0.71219,-0.531921 0.127285,-0.268234 0.09854,-0.395207 -0.157522,-0.695864 -0.662348,-0.777691 -0.997525,-1.743181 -0.945017,-2.722148 0.03114,-0.580505 0.12179,-0.953388 0.353328,-1.45334 0.212627,-0.459116 0.383506,-0.711346 0.740366,-1.09283 0.672636,-0.71905 1.682489,-1.241647 2.708976,-1.4018909 0.490149,-0.076517 1.526545,-0.02589 1.979609,0.096701 1.505262,0.407299 2.682696,1.468657 3.139596,2.830084 0.130153,0.387815 0.152618,0.524655 0.171084,1.042086 0.01784,0.500017 0.0055,0.661852 -0.07665,1.008018 -0.18178,0.765605 -0.696216,1.655075 -1.239997,2.143981 -0.529993,0.476509 -1.39904,0.89063 -2.246034,1.070287 -0.451196,0.0957 -1.424683,0.109171 -1.84512,0.02552 l -0.264364,-0.0526 -0.232292,0.175815 c -0.287398,0.217524 -0.824625,0.489676 -1.200559,0.60819 -0.322779,0.101755 -1.133879,0.149417 -1.43835,0.08452 z m 1.912071,-1.590093 c 0.06231,-0.04253 0.201752,-0.154112 0.309875,-0.247961 0.256635,-0.222755 0.510827,-0.261992 0.996819,-0.153869 0.271369,0.06038 0.490477,0.07337 0.954006,0.0566 0.518079,-0.01875 0.660472,-0.04167 1.024295,-0.164866 0.622734,-0.210873 0.936834,-0.386294 1.29259,-0.721896 0.524125,-0.494433 0.920622,-1.384119 0.918641,-2.061307 -0.0024,-0.83469 -0.430823,-1.715227 -1.090114,-2.240728 -1.113512,-0.887545 -2.674651,-1.048538 -3.985232,-0.410977 -0.378454,0.184106 -0.501993,0.27528 -0.857746,0.633026 -0.629706,0.633233 -0.870954,1.197212 -0.864765,2.021607 0.0053,0.710259 0.245878,1.299272 0.771959,1.890249 0.196399,0.220627 0.313378,0.39731 0.347876,0.525424 0.05502,0.204312 0.06918,0.826897 0.02061,0.905496 -0.04366,0.07064 0.03444,0.05572 0.161188,-0.0308 z"
id="path52" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,15.508159 c -0.49193,-0.14729 -0.560004,-0.852438 -0.103219,-1.069197 0.137886,-0.06543 0.400194,-0.0747 2.113789,-0.0747 2.235432,0 2.210772,-0.0037 2.367773,0.351267 0.150765,0.340831 -0.01604,0.691362 -0.378461,0.795303 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path53" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,13.996132 c -0.493719,-0.147826 -0.558571,-0.88531 -0.09489,-1.079049 0.232858,-0.09729 3.983021,-0.09522 4.216497,0.0023 0.224063,0.09362 0.364744,0.404907 0.296883,0.656921 -0.05662,0.210256 -0.206658,0.36168 -0.41861,0.422467 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path92" />
</svg>

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
id="svg23"
sodipodi:docname="new_chat_group_pressed.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"
id="namedview25"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,88 +20,77 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="22.130584"
inkscape:cy="40"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="19.954181"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="svg23" />
<defs
id="defs5">
<filter
id="g4j9xsegqa"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<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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
QKNV/w7jf9TLq/s/EHOtAAAAAElFTkSuQmCC
"
id="image10" />
fill="none"
fill-rule="evenodd"
id="g21">
<g
id="g19">
<g
fill="#DC4100"
id="g9">
<path
d="M0 5.005C0 2.241 2.236 0 5.005 0h29.99C37.759 0 40 2.236 40 5.005v29.99C40 37.759 37.764 40 34.995 40H5.005C2.241 40 0 37.764 0 34.995V5.005z"
transform="translate(20.000000, 20.000000) scale(1, -1) translate(-20.000000, -20.000000)"
id="path7" />
</g>
<g
filter="url(#g4j9xsegqa)"
id="g17">
<g
fill="#444"
fill-rule="nonzero"
id="g15">
<path
d="M24.656 7.186c.547 0 1.074-.115 1.548-.331.026-.012.052-.022.08-.03.032-.01.112-.04.224-.095.194-.097.39-.225.572-.389.158-.141.298-.303.416-.486.232-.36.381-.7.464-1.01.028-.102.046-.192.056-.267l.006-.056.003-.05c.01-.091.014-.183.014-.275 0-1.636-1.501-2.989-3.383-2.989-1.882 0-3.383 1.353-3.383 2.99 0 .779.34 1.513.944 2.07.097.089.162.207.185.337l.008.04c.084.342.084.656.014.942.156-.098.285-.195.397-.291.038-.033.07-.063.099-.09l.023-.022.015-.015.017-.016c.01-.01.01-.01.057-.045l.054-.034.455-.054c.365.11.735.166 1.115.166zm0 1.208c-.38 0-.754-.042-1.116-.125-.138.115-.292.227-.461.333-.774.486-1.635.711-2.542.509-.61-.136-.637-.995-.038-1.17.015-.004.057-.019.116-.045.104-.045.207-.101.3-.169.27-.192.388-.405.338-.71-.757-.764-1.189-1.76-1.189-2.82 0-2.333 2.07-4.197 4.592-4.197 2.523 0 4.592 1.864 4.592 4.197 0 .126-.006.251-.018.376-.006.136-.035.336-.103.588-.115.426-.314.881-.615 1.348-.179.277-.39.52-.625.732-.268.24-.555.428-.842.571-.152.076-.28.127-.374.158-.623.278-1.308.424-2.015.424zM22.8 2.957h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zm0 1.514h3.703c.806 0 .806 1.208 0 1.208H22.8c-.805 0-.805-1.208 0-1.208zM4.657 17.308c1.211.363 2.457.594 3.69.718.898.09 1.662.11 2.231.095l.11-.005h.112l.142.005c.57.016 1.333-.006 2.232-.095 1.232-.124 2.478-.355 3.69-.718.182-.987.005-2.103-.81-3.17-.618-.811-1.57-1.529-2.915-2.12-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.356-.692-.06-.953.046-.055.056-.067.099-.113.507-.547.794-1.265.794-2.03 0-1.642-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.968 0 .766.287 1.484.794 2.032.043.046.05.054.088.103.307.269.278.74-.05.962l-.148.1c-.03.02-.062.039-.096.053-1.344.591-2.296 1.309-2.915 2.12-.814 1.067-.992 2.183-.81 3.17zm6.079 2.016l-.123.004c-.618.018-1.434-.005-2.387-.1-1.42-.142-2.86-.42-4.259-.869-.18-.058-.324-.197-.386-.377-.029-.082-.066-.216-.101-.396-.258-1.31-.035-2.79 1.026-4.181.653-.858 1.59-1.609 2.833-2.232-.486-.695-.754-1.53-.754-2.405 0-2.305 1.852-4.176 4.141-4.176h.068c2.29 0 4.142 1.87 4.142 4.176 0 .876-.269 1.71-.755 2.405 1.244.623 2.18 1.374 2.834 2.232 1.061 1.39 1.284 2.87 1.026 4.181-.036.18-.073.314-.101.396-.063.18-.206.32-.387.377-1.399.448-2.838.727-4.259.869-.953.095-1.768.118-2.387.1l-.122-.004h-.05z"
transform="translate(6.873063, 9.879167)"
id="path11" />
<path
d="M14.878 8.768c0 .876-.268 1.71-.755 2.405 1.863.932 3.02 2.14 3.574 3.523 1.058-.081 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.635-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.953.027-.033.038-.046.072-.082.387-.418.606-.966.606-1.552 0-1.253-1.004-2.266-2.239-2.266h-.054c-.866 0-1.637.502-2.008 1.262.498.701.773 1.546.773 2.431zm2.835.227zm-4.146 1.917l-.243.553.34-.5-.045-.03-.052-.023zm-.69-.113c.506-.547.793-1.265.793-2.03 0-.725-.256-1.406-.714-1.942-.138-.16-.181-.381-.115-.582.464-1.408 1.775-2.378 3.272-2.378h.054c1.905 0 3.447 1.557 3.447 3.474 0 .682-.195 1.333-.552 1.888.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.333-.062.18-.205.32-.386.378-1.452.465-2.931.7-4.327.769-.278.013-.529-.164-.609-.431-.405-1.36-1.524-2.561-3.618-3.482-.034-.015-.066-.033-.097-.053l-.147-.1c-.326-.223-.355-.692-.06-.953.046-.055.056-.067.1-.113zM7.34 11.173c-.487-.695-.755-1.53-.755-2.405 0-1.11.432-2.147 1.177-2.917-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.013-2.238 2.266 0 .586.219 1.134.607 1.552.034.037.043.047.07.081.296.26.267.732-.06.954l-.12.08c-.03.021-.062.04-.095.054-1.063.467-1.812 1.031-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.246 1.695.414 2.546.516.565-1.355 1.715-2.538 3.545-3.454zM4.474 8.996v-.001zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.899l-.148.1c-.03.02-.062.039-.096.053-2.07.91-3.187 2.097-3.604 3.438-.085.273-.349.449-.633.423-1.193-.11-2.409-.339-3.591-.717-.181-.058-.324-.198-.387-.378-.024-.07-.056-.184-.085-.334-.214-1.083-.03-2.307.846-3.455.516-.676 1.243-1.27 2.199-1.766-.357-.555-.552-1.206-.552-1.888 0-1.917 1.541-3.474 3.446-3.474h.055c1.265 0 2.409.693 3.013 1.785.143.26.077.585-.156.768-.714.56-1.14 1.417-1.14 2.348 0 .766.288 1.484.795 2.032.043.046.05.054.088.103.307.269.278.74-.05.962z"
transform="translate(6.873063, 9.879167)"
id="path13" />
</g>
</g>
</g>
</g>
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 16.494845,29.178175 c -1.768895,-0.06448 -3.540258,-0.35045 -5.260067,-0.849187 -0.617674,-0.179123 -0.718313,-0.274855 -0.841605,-0.800583 -0.06362,-0.271286 -0.0839,-0.541986 -0.0839,-1.120246 V 25.645643 L 10.057274,25.61642 C 9.2497315,25.522777 7.4166963,25.063708 7.2458642,24.912324 6.889066,24.596146 6.791109,23.319917 7.0541971,22.415197 c 0.3542798,-1.218314 1.2195108,-2.260043 2.5233927,-3.038139 0.2386257,-0.1424 0.4338652,-0.268162 0.4338652,-0.27947 0,-0.01131 -0.051764,-0.108888 -0.1150309,-0.216845 C 9.8331572,18.772786 9.7316224,18.538126 9.6707912,18.359274 9.219476,17.032352 9.5623261,15.647722 10.577298,14.698265 c 1.316242,-1.231279 3.363424,-1.234352 4.677638,-0.007 l 0.337119,0.314832 0.312717,-0.140306 c 0.503414,-0.225867 0.909194,-0.321118 1.492803,-0.350416 0.960698,-0.04823 1.81064,0.178533 2.53808,0.67715 l 0.187661,0.128629 0.224711,-0.281924 c 0.421979,-0.529418 1.124912,-0.986213 1.782557,-1.158378 0.680573,-0.178168 1.541067,-0.121952 2.193924,0.143327 0.795352,0.323181 1.531624,1.060815 1.876332,1.879807 0.377346,0.896534 0.329572,2.013165 -0.123296,2.881831 -0.07883,0.151203 -0.149288,0.287211 -0.156579,0.302239 -0.0073,0.01503 0.1472,0.120659 0.343314,0.234734 1.062933,0.618287 1.873211,1.43704 2.3253,2.349625 0.329742,0.665615 0.41238,1.027594 0.413179,1.809851 0.0012,1.13309 -0.125967,1.423274 -0.699876,1.597593 -0.828183,0.251554 -1.955403,0.485451 -2.909386,0.603697 l -0.448429,0.05558 0.03039,0.441189 c 0.03262,0.473633 -0.02739,1.085627 -0.150027,1.530061 -0.120102,0.435238 -0.227448,0.491137 -1.618095,0.842603 -1.060976,0.268147 -2.180866,0.452887 -3.413517,0.563105 -0.526306,0.04706 -2.626841,0.0866 -3.298969,0.0621 z m 3.003442,-1.207466 c 1.270238,-0.09815 2.443538,-0.286873 3.555777,-0.571936 0.347892,-0.08916 0.653563,-0.183243 0.679268,-0.209065 0.02779,-0.02792 0.04674,-0.338481 0.04674,-0.766096 0,-0.599135 -0.01327,-0.742083 -0.07949,-0.856602 -0.04372,-0.0756 -0.132281,-0.281567 -0.196805,-0.457701 -0.449444,-1.226862 -1.523996,-2.259573 -3.198327,-3.073789 -0.544772,-0.264919 -0.735822,-0.414918 -0.80834,-0.634652 -0.0706,-0.213911 0.0022,-0.388798 0.318666,-0.76564 0.501087,-0.596669 0.732699,-1.22474 0.732699,-1.986889 0,-0.706731 -0.170356,-1.221675 -0.61091,-1.846633 -0.366969,-0.520572 -0.788085,-0.820973 -1.420501,-1.013306 -1.569537,-0.477336 -3.208991,0.380531 -3.720372,1.946736 -0.11356,0.3478 -0.13347,0.481376 -0.132702,0.890294 0.0014,0.747275 0.210638,1.353582 0.655384,1.899116 0.375832,0.461004 0.419459,0.535115 0.419459,0.712567 0,0.315092 -0.140514,0.444944 -0.918813,0.849095 -0.914824,0.475044 -1.47497,0.860689 -1.994456,1.373128 -0.765356,0.754972 -1.2206,1.617146 -1.350193,2.557092 -0.04975,0.360873 -0.02577,1.057862 0.04005,1.163885 0.04386,0.07064 1.368773,0.394519 2.184467,0.53399 0.642116,0.109793 1.673455,0.237499 2.199313,0.272332 0.572185,0.0379 3.044032,0.02696 3.599089,-0.01593 z m 6.504004,-3.552544 c 0.365407,-0.06116 0.924974,-0.175568 1.243482,-0.254246 l 0.579107,-0.143051 0.02749,-0.166219 C 27.972236,23.129911 27.658906,22.1528 27.083912,21.458233 26.660436,20.946693 25.975438,20.442047 25.191795,20.064287 24.682392,19.818726 24.5069,19.6781 24.449236,19.469257 c -0.06149,-0.222702 -0.0044,-0.374604 0.267123,-0.711304 0.636868,-0.789611 0.756604,-1.688742 0.340182,-2.554519 -0.501247,-1.042137 -1.728902,-1.527075 -2.857682,-1.128818 -0.398684,0.140664 -0.867266,0.516918 -1.103256,0.885875 l -0.127124,0.19875 0.163668,0.255853 c 0.861059,1.346053 0.862916,3.029196 0.0049,4.473838 -0.05838,0.09831 -0.08549,0.185949 -0.06024,0.194762 0.146692,0.0512 1.12099,0.662056 1.451039,0.909761 0.803412,0.60297 1.547756,1.473978 1.906126,2.230486 l 0.170806,0.360568 0.366552,-0.02757 c 0.201604,-0.01517 0.665521,-0.07761 1.030928,-0.13877 z M 10.879175,24.120299 c 0.512183,-1.030272 1.541477,-2.04584 2.774891,-2.737888 0.62985,-0.353399 0.599065,-0.308277 0.411037,-0.60246 -0.21024,-0.328934 -0.407889,-0.848395 -0.50482,-1.326769 -0.104641,-0.516427 -0.07209,-1.434693 0.06832,-1.927409 0.139077,-0.488031 0.464061,-1.12194 0.757663,-1.477887 0.157946,-0.191485 0.241519,-0.331237 0.224541,-0.37548 -0.04578,-0.11929 -0.55347,-0.471586 -0.83106,-0.576685 -0.985748,-0.373214 -2.057009,-0.07592 -2.676885,0.742885 -0.308269,0.407196 -0.410691,0.700511 -0.438275,1.255123 -0.03454,0.694515 0.131769,1.179764 0.579833,1.691792 0.255496,0.291969 0.31052,0.453403 0.233788,0.685902 -0.07025,0.212863 -0.244725,0.350714 -0.786867,0.621696 -1.0455005,0.522578 -1.7394485,1.109948 -2.1862883,1.850513 -0.3159287,0.523601 -0.490696,1.259853 -0.4326223,1.822533 l 0.026403,0.255818 0.585367,0.142732 c 0.4945479,0.120587 0.8388293,0.186195 1.7854426,0.340247 0.063,0.01025 0.135166,0.01993 0.160366,0.02151 0.0252,0.0016 0.137325,-0.1812 0.249164,-0.406169 z"
id="path52" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 27.527906,18.992721 c -0.266698,-0.05685 -0.370655,-0.120447 -0.474058,-0.290032 -0.201486,-0.330443 -0.07575,-0.667754 0.314818,-0.844585 0.38794,-0.175641 0.628317,-0.355173 0.71219,-0.531921 0.127285,-0.268234 0.09854,-0.395207 -0.157522,-0.695864 -0.662348,-0.777691 -0.997525,-1.743181 -0.945017,-2.722148 0.03114,-0.580505 0.12179,-0.953388 0.353328,-1.45334 0.212627,-0.459116 0.383506,-0.711346 0.740366,-1.09283 0.672636,-0.71905 1.682489,-1.241647 2.708976,-1.4018909 0.490149,-0.076517 1.526545,-0.02589 1.979609,0.096701 1.505262,0.407299 2.682696,1.468657 3.139596,2.830084 0.130153,0.387815 0.152618,0.524655 0.171084,1.042086 0.01784,0.500017 0.0055,0.661852 -0.07665,1.008018 -0.18178,0.765605 -0.696216,1.655075 -1.239997,2.143981 -0.529993,0.476509 -1.39904,0.89063 -2.246034,1.070287 -0.451196,0.0957 -1.424683,0.109171 -1.84512,0.02552 l -0.264364,-0.0526 -0.232292,0.175815 c -0.287398,0.217524 -0.824625,0.489676 -1.200559,0.60819 -0.322779,0.101755 -1.133879,0.149417 -1.43835,0.08452 z m 1.912071,-1.590093 c 0.06231,-0.04253 0.201752,-0.154112 0.309875,-0.247961 0.256635,-0.222755 0.510827,-0.261992 0.996819,-0.153869 0.271369,0.06038 0.490477,0.07337 0.954006,0.0566 0.518079,-0.01875 0.660472,-0.04167 1.024295,-0.164866 0.622734,-0.210873 0.936834,-0.386294 1.29259,-0.721896 0.524125,-0.494433 0.920622,-1.384119 0.918641,-2.061307 -0.0024,-0.83469 -0.430823,-1.715227 -1.090114,-2.240728 -1.113512,-0.887545 -2.674651,-1.048538 -3.985232,-0.410977 -0.378454,0.184106 -0.501993,0.27528 -0.857746,0.633026 -0.629706,0.633233 -0.870954,1.197212 -0.864765,2.021607 0.0053,0.710259 0.245878,1.299272 0.771959,1.890249 0.196399,0.220627 0.313378,0.39731 0.347876,0.525424 0.05502,0.204312 0.06918,0.826897 0.02061,0.905496 -0.04366,0.07064 0.03444,0.05572 0.161188,-0.0308 z"
id="path91" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,15.508159 c -0.49193,-0.14729 -0.560004,-0.852438 -0.103219,-1.069197 0.137886,-0.06543 0.400194,-0.0747 2.113789,-0.0747 2.235432,0 2.210772,-0.0037 2.367773,0.351267 0.150765,0.340831 -0.01604,0.691362 -0.378461,0.795303 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path130" />
<path
style="fill:#ffffff;stroke-width:0.045819"
d="m 29.512912,13.996132 c -0.493719,-0.147826 -0.558571,-0.88531 -0.09489,-1.079049 0.232858,-0.09729 3.983021,-0.09522 4.216497,0.0023 0.224063,0.09362 0.364744,0.404907 0.296883,0.656921 -0.05662,0.210256 -0.206658,0.36168 -0.41861,0.422467 -0.192992,0.05535 -3.814178,0.05293 -3.999882,-0.0027 z"
id="path169" />
</svg>

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
id="svg29"
sodipodi:docname="new_conference_disabled.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"
id="namedview31"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,68 +20,76 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="22.130584"
inkscape:cy="40"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="20"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="svg29" />
<defs
id="defs5">
<filter
id="rspqpram5a"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<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" />
fill="none"
fill-rule="evenodd"
id="g27">
<g
id="g25">
<g
fill="#FF5E00"
opacity=".3"
id="g9">
<path
d="M0 5.005C0 2.241 2.236 0 5.005 0h29.99C37.759 0 40 2.236 40 5.005v29.99C40 37.759 37.764 40 34.995 40H5.005C2.241 40 0 37.764 0 34.995V5.005z"
transform="translate(20.000000, 20.000000) scale(1, -1) translate(-20.000000, -20.000000)"
id="path7" />
</g>
<g
id="g23">
<g
filter="url(#rspqpram5a)"
transform="translate(5.873063, 10.000000)"
id="g19">
<g
id="g17">
<g
fill="#444"
fill-rule="nonzero"
id="g15">
<path
d="M4.657 13.441c1.211.363 2.457.595 3.69.718.898.09 1.662.111 2.231.095l.11-.004.112-.001.142.005c.57.016 1.333-.005 2.232-.095 1.232-.123 2.478-.355 3.69-.718.182-.987.005-2.102-.81-3.17-.618-.81-1.57-1.528-2.915-2.12-.034-.014-.066-.032-.097-.053l-.147-.1c-.326-.222-.356-.692-.06-.953.046-.055.056-.067.099-.112.507-.547.794-1.266.794-2.031 0-1.641-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.969 0 .765.287 1.484.794 2.031.043.046.05.055.088.104.307.268.278.74-.05.961l-.148.1c-.03.021-.062.039-.096.054-1.344.59-2.296 1.308-2.915 2.119-.814 1.068-.992 2.183-.81 3.17zm6.079 2.016l-.123.005c-.618.018-1.434-.005-2.387-.1-1.42-.143-2.86-.421-4.259-.87-.18-.057-.324-.197-.386-.377-.029-.082-.066-.216-.101-.395-.258-1.31-.035-2.791 1.026-4.182.653-.857 1.59-1.609 2.833-2.232-.486-.695-.754-1.529-.754-2.404 0-2.306 1.852-4.177 4.141-4.177h.068c2.29 0 4.142 1.871 4.142 4.177 0 .875-.269 1.71-.755 2.404 1.244.624 2.18 1.375 2.834 2.232 1.061 1.39 1.284 2.871 1.026 4.182-.036.179-.073.313-.101.395-.063.18-.206.32-.387.378-1.399.448-2.838.726-4.259.868-.953.096-1.768.119-2.387.1-.053 0-.095-.002-.122-.004h-.05z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path11" />
<path
d="M14.878 4.902c0 .875-.268 1.709-.755 2.404 1.863.933 3.02 2.14 3.574 3.523 1.058-.08 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.634-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.952.027-.034.038-.046.072-.083.387-.418.606-.966.606-1.551 0-1.253-1.004-2.267-2.239-2.267h-.054c-.866 0-1.637.502-2.008 1.263.498.7.773 1.545.773 2.43zm2.835.227v-.001zm-4.146 1.916l-.243.554.34-.5-.045-.03-.052-.024zm-.69-.112c.506-.547.793-1.266.793-2.031 0-.724-.256-1.406-.714-1.942-.138-.16-.181-.38-.115-.581C13.305.97 14.616 0 16.113 0h.054c1.905 0 3.447 1.557 3.447 3.475 0 .681-.195 1.332-.552 1.887.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.334-.062.18-.205.32-.386.377-1.452.465-2.931.7-4.327.769-.278.014-.529-.164-.609-.43-.405-1.36-1.524-2.562-3.618-3.482-.034-.015-.066-.033-.097-.054l-.147-.1c-.326-.222-.355-.692-.06-.953.046-.055.056-.067.1-.112zM7.34 7.306c-.487-.695-.755-1.529-.755-2.404 0-1.11.432-2.148 1.177-2.918-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.014-2.238 2.267 0 .585.219 1.133.607 1.552.034.037.043.047.07.08.296.261.267.732-.06.954l-.12.081c-.03.02-.062.038-.095.053-1.063.467-1.812 1.032-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.247 1.695.415 2.546.516.565-1.355 1.715-2.537 3.545-3.454zM4.474 5.13zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.9l-.148.1c-.03.02-.062.038-.096.053-2.07.91-3.187 2.096-3.604 3.438-.085.272-.349.448-.633.422-1.193-.11-2.409-.338-3.591-.717-.181-.058-.324-.198-.387-.377-.024-.072-.056-.184-.085-.334C-.133 9.5.051 8.276.927 7.128c.516-.675 1.243-1.27 2.199-1.766-.357-.554-.552-1.206-.552-1.887C2.574 1.557 4.115 0 6.02 0h.055C7.34 0 8.484.693 9.088 1.786c.143.26.077.584-.156.767-.714.56-1.14 1.418-1.14 2.349 0 .765.288 1.484.795 2.031.043.046.05.055.088.104.307.268.278.74-.05.961z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path13" />
</g>
</g>
</g>
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
d="M30.278 6.994c-.907-2.01-3.608-3.397-5.857-3.397h-.047c-2.249 0-4.95 1.388-5.857 3.398l.331 2.602h2.898l.205-2.59h4.893l.205 2.59h2.898l.33-2.603h0z"
transform="translate(5.873063, 10.000000) translate(24.397663, 6.597392) rotate(-119.000000) translate(-24.397663, -6.597392)"
id="path21" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -1,23 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="40"
height="40"
viewBox="0 0 40 40"
version="1.1"
id="svg2"
width="80"
height="80"
viewBox="0 0 80 80"
id="svg29"
sodipodi:docname="new_conference_hovered.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs6" />
<sodipodi:namedview
id="namedview4"
id="namedview31"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,67 +20,79 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="10.9125"
inkscape:cx="22.130584"
inkscape:cy="40"
inkscape:zoom="21.825"
inkscape:cx="20"
inkscape:cy="19.954181"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="g8" />
inkscape:current-layer="svg29" />
<defs
id="defs5">
<filter
id="gerxywefia"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 0 1.000000 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<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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
AABJRU5ErkJggg==
"
id="image10" />
fill="none"
fill-rule="evenodd"
id="g27">
<g
id="g25">
<g
fill="#4B5964"
id="g9">
<path
d="M0 5.005C0 2.241 2.236 0 5.005 0h29.99C37.759 0 40 2.236 40 5.005v29.99C40 37.759 37.764 40 34.995 40H5.005C2.241 40 0 37.764 0 34.995V5.005z"
transform="translate(20.000000, 20.000000) scale(1, -1) translate(-20.000000, -20.000000)"
id="path7" />
</g>
<g
id="g23">
<g
filter="url(#gerxywefia)"
transform="translate(5.873063, 10.000000)"
id="g19">
<g
id="g17">
<g
fill="#444"
fill-rule="nonzero"
id="g15">
<path
d="M4.657 13.441c1.211.363 2.457.595 3.69.718.898.09 1.662.111 2.231.095l.11-.004.112-.001.142.005c.57.016 1.333-.005 2.232-.095 1.232-.123 2.478-.355 3.69-.718.182-.987.005-2.102-.81-3.17-.618-.81-1.57-1.528-2.915-2.12-.034-.014-.066-.032-.097-.053l-.147-.1c-.326-.222-.356-.692-.06-.953.046-.055.056-.067.099-.112.507-.547.794-1.266.794-2.031 0-1.641-1.315-2.969-2.934-2.969h-.068c-1.618 0-2.933 1.328-2.933 2.969 0 .765.287 1.484.794 2.031.043.046.05.055.088.104.307.268.278.74-.05.961l-.148.1c-.03.021-.062.039-.096.054-1.344.59-2.296 1.308-2.915 2.119-.814 1.068-.992 2.183-.81 3.17zm6.079 2.016l-.123.005c-.618.018-1.434-.005-2.387-.1-1.42-.143-2.86-.421-4.259-.87-.18-.057-.324-.197-.386-.377-.029-.082-.066-.216-.101-.395-.258-1.31-.035-2.791 1.026-4.182.653-.857 1.59-1.609 2.833-2.232-.486-.695-.754-1.529-.754-2.404 0-2.306 1.852-4.177 4.141-4.177h.068c2.29 0 4.142 1.871 4.142 4.177 0 .875-.269 1.71-.755 2.404 1.244.624 2.18 1.375 2.834 2.232 1.061 1.39 1.284 2.871 1.026 4.182-.036.179-.073.313-.101.395-.063.18-.206.32-.387.378-1.399.448-2.838.726-4.259.868-.953.096-1.768.119-2.387.1-.053 0-.095-.002-.122-.004h-.05z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path11" />
<path
d="M14.878 4.902c0 .875-.268 1.709-.755 2.404 1.863.933 3.02 2.14 3.574 3.523 1.058-.08 2.16-.266 3.243-.585.12-.745-.028-1.58-.64-2.383-.484-.634-1.233-1.199-2.296-1.666-.034-.015-.067-.033-.097-.054l-.119-.08c-.326-.222-.355-.692-.06-.952.027-.034.038-.046.072-.083.387-.418.606-.966.606-1.551 0-1.253-1.004-2.267-2.239-2.267h-.054c-.866 0-1.637.502-2.008 1.263.498.7.773 1.545.773 2.43zm2.835.227v-.001zm-4.146 1.916l-.243.554.34-.5-.045-.03-.052-.024zm-.69-.112c.506-.547.793-1.266.793-2.031 0-.724-.256-1.406-.714-1.942-.138-.16-.181-.38-.115-.581C13.305.97 14.616 0 16.113 0h.054c1.905 0 3.447 1.557 3.447 3.475 0 .681-.195 1.332-.552 1.887.956.497 1.683 1.09 2.198 1.766.876 1.148 1.06 2.372.847 3.456-.03.15-.06.262-.086.334-.062.18-.205.32-.386.377-1.452.465-2.931.7-4.327.769-.278.014-.529-.164-.609-.43-.405-1.36-1.524-2.562-3.618-3.482-.034-.015-.066-.033-.097-.054l-.147-.1c-.326-.222-.355-.692-.06-.953.046-.055.056-.067.1-.112zM7.34 7.306c-.487-.695-.755-1.529-.755-2.404 0-1.11.432-2.148 1.177-2.918-.418-.485-1.027-.776-1.687-.776H6.02c-1.235 0-2.238 1.014-2.238 2.267 0 .585.219 1.133.607 1.552.034.037.043.047.07.08.296.261.267.732-.06.954l-.12.081c-.03.02-.062.038-.095.053-1.063.467-1.812 1.032-2.296 1.666-.612.803-.76 1.638-.64 2.383.838.247 1.695.415 2.546.516.565-1.355 1.715-2.537 3.545-3.454zM4.474 5.13zm3.324 1.97l.34.5-.244-.554-.051.023-.045.03zm.826.9l-.148.1c-.03.02-.062.038-.096.053-2.07.91-3.187 2.096-3.604 3.438-.085.272-.349.448-.633.422-1.193-.11-2.409-.338-3.591-.717-.181-.058-.324-.198-.387-.377-.024-.072-.056-.184-.085-.334C-.133 9.5.051 8.276.927 7.128c.516-.675 1.243-1.27 2.199-1.766-.357-.554-.552-1.206-.552-1.887C2.574 1.557 4.115 0 6.02 0h.055C7.34 0 8.484.693 9.088 1.786c.143.26.077.584-.156.767-.714.56-1.14 1.418-1.14 2.349 0 .765.288 1.484.795 2.031.043.046.05.055.088.104.307.268.278.74-.05.961z"
transform="translate(0.000000, 0.685585) translate(0.000000, 3.745833)"
id="path13" />
</g>
</g>
</g>
<path
stroke="#FFF"
stroke-linecap="round"
stroke-linejoin="round"
d="M30.278 6.994c-.907-2.01-3.608-3.397-5.857-3.397h-.047c-2.249 0-4.95 1.388-5.857 3.398l.331 2.602h2.898l.205-2.59h4.893l.205 2.59h2.898l.33-2.603h0z"
transform="translate(5.873063, 10.000000) translate(24.397663, 6.597392) rotate(-119.000000) translate(-24.397663, -6.597392)"
id="path21" />
</g>
</g>
</g>
<path
style="fill:#ffffff;stroke-width:0.045819"
d="M 15.166094,29.844075 C 13.87814,29.788111 12.328834,29.559882 11.065292,29.239984 9.786811,28.916304 9.5647637,28.814878 9.4658175,28.509382 9.3354584,28.1069 9.267805,27.482053 9.2935883,26.918671 l 0.026211,-0.572737 -0.640858,-0.104726 C 7.5236868,26.052422 6.3924205,25.735094 6.2044097,25.547083 5.9957122,25.338386 5.8579054,24.597276 5.9064941,23.944926 c 0.1180372,-1.584763 1.0812313,-2.949853 2.787664,-3.950825 0.1701031,-0.09978 0.3092783,-0.191334 0.3092783,-0.203451 0,-0.01212 -0.069846,-0.160727 -0.1552124,-0.330244 C 8.4084997,18.587231 8.3552576,17.61442 8.6973475,16.703674 9.5732363,14.371796 12.537478,13.69901 14.305167,15.430883 l 0.284548,0.278782 0.24237,-0.118598 c 0.640377,-0.313355 1.226703,-0.425396 2.029312,-0.387784 0.7707,0.03612 1.375593,0.221923 1.978932,0.607874 0.13877,0.08877 0.267991,0.155204 0.287159,0.14763 0.01917,-0.0076 0.138973,-0.139477 0.266234,-0.293119 0.419187,-0.506084 1.081053,-0.923376 1.751753,-1.104441 0.4109,-0.110928 1.332069,-0.110723 1.739673,3.88e-4 0.924216,0.251937 1.704888,0.874124 2.169781,1.72929 0.25306,0.465503 0.357779,0.864297 0.384419,1.463963 0.02874,0.646888 -0.07362,1.138768 -0.352301,1.693044 l -0.184481,0.366915 0.194765,0.09901 c 0.107121,0.05446 0.3618,0.209976 0.565953,0.345601 1.091444,0.725079 1.812228,1.623411 2.181451,2.718798 0.141062,0.418493 0.146797,0.464438 0.148702,1.191294 0.003,1.15988 -0.110817,1.419878 -0.699323,1.596941 -0.816586,0.245685 -1.844026,0.463566 -2.740785,0.581216 l -0.601311,0.07889 0.02331,0.491764 c 0.03978,0.839329 -0.116429,1.647701 -0.357624,1.850653 -0.408382,0.343631 -3.284961,0.935142 -5.15264,1.059539 -0.635215,0.04231 -2.482677,0.05101 -3.298969,0.01554 z m 3.894616,-1.226546 c 1.182292,-0.13755 2.179645,-0.317844 3.106027,-0.561485 0.414081,-0.108904 0.552206,-0.164567 0.59176,-0.238474 0.0654,-0.1222 0.06569,-1.087062 4.12e-4,-1.334179 -0.04933,-0.186719 -0.20815,-0.596843 -0.389863,-1.006754 -0.453704,-1.023467 -1.476,-1.950482 -3.008469,-2.728069 -0.731764,-0.3713 -0.872604,-0.5001 -0.872604,-0.797999 0,-0.206913 0.02647,-0.253918 0.425813,-0.756169 0.429245,-0.539859 0.630456,-1.13309 0.630456,-1.858776 0,-0.732703 -0.186883,-1.281402 -0.648472,-1.903947 -0.489183,-0.65976 -1.172593,-1.018856 -2.057282,-1.080993 -1.427808,-0.100283 -2.720604,0.830417 -3.096108,2.228927 -0.116905,0.435396 -0.104389,1.163534 0.02717,1.580756 0.142948,0.453334 0.292169,0.731315 0.588759,1.09679 0.340473,0.419552 0.368969,0.473188 0.370878,0.69809 0.0025,0.294688 -0.14356,0.427438 -0.883291,0.802784 -1.55186,0.787426 -2.471898,1.624229 -2.994977,2.724023 -0.294297,0.618772 -0.39009,1.029328 -0.393997,1.688622 -0.002,0.32926 0.01761,0.588635 0.04876,0.646566 0.120392,0.223887 2.466606,0.69735 4.156399,0.838756 0.637915,0.05338 3.850636,0.02529 4.398625,-0.03847 z m 5.933563,-3.5125 c 0.365406,-0.06093 0.926431,-0.175509 1.246721,-0.254629 l 0.582345,-0.143853 0.03093,-0.206266 c 0.04637,-0.309196 -0.01154,-0.827652 -0.13633,-1.220621 -0.318625,-1.003357 -1.118245,-1.80936 -2.504779,-2.524775 -0.667467,-0.344395 -0.776268,-0.454453 -0.776565,-0.785539 -1.37e-4,-0.163538 0.03299,-0.229461 0.230296,-0.45819 0.849545,-0.98484 0.837153,-2.322598 -0.02973,-3.209414 -0.535662,-0.547978 -1.315078,-0.790076 -2.056693,-0.638839 -0.198187,0.04042 -0.475075,0.12923 -0.615308,0.197364 -0.266049,0.129264 -0.800271,0.626614 -0.916625,0.85336 -0.0593,0.115552 -0.05599,0.142706 0.03623,0.297824 0.242037,0.407117 0.427012,0.813252 0.541256,1.188397 0.110144,0.361679 0.122704,0.474972 0.123386,1.112867 6.32e-4,0.591164 -0.01611,0.77163 -0.09987,1.076747 -0.09363,0.341053 -0.351076,0.924229 -0.5438,1.231857 -0.05324,0.08498 -0.06498,0.138662 -0.03287,0.150289 0.02747,0.0099 0.241366,0.127665 0.475315,0.26159 1.30543,0.7473 2.293657,1.721541 2.861514,2.821017 l 0.219429,0.424855 0.350388,-0.03163 c 0.192713,-0.0174 0.649357,-0.08148 1.014764,-0.142408 z M 9.8082992,24.937255 c 0.3315758,-0.705722 0.9784488,-1.50669 1.6621428,-2.058088 0.427198,-0.344534 1.079263,-0.778296 1.45052,-0.964904 0.151203,-0.076 0.280232,-0.142774 0.286731,-0.148387 0.0065,-0.0056 -0.0891,-0.204199 -0.212439,-0.441305 -0.370401,-0.712047 -0.508564,-1.259916 -0.509227,-2.01928 -7.88e-4,-0.905788 0.303007,-1.798472 0.847445,-2.490157 0.138659,-0.176159 0.265995,-0.349782 0.28297,-0.38583 0.04423,-0.09393 -0.30686,-0.385421 -0.69548,-0.577412 -0.890674,-0.440023 -1.955091,-0.249908 -2.643886,0.472222 -0.4224999,0.442947 -0.6321734,0.970675 -0.6321734,1.591121 0,0.597302 0.1895231,1.089283 0.6005674,1.559006 0.327412,0.374152 0.350269,0.663438 0.07315,0.92575 -0.08074,0.07642 -0.3942174,0.264383 -0.6966229,0.417692 -0.6509622,0.330015 -1.0770464,0.62736 -1.5039382,1.049533 -0.7377375,0.729581 -1.0624044,1.491124 -1.0303751,2.416862 l 0.014267,0.412371 0.3894616,0.103785 c 0.5147595,0.137174 1.6919852,0.367587 2.1336143,0.417602 0.026867,0.003 0.1093412,-0.123219 0.183276,-0.280581 z"
id="path55" />
</svg>

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="12"
height="12"
viewBox="0 0 12 12"
version="1.1"
id="svg10"
sodipodi:docname="panel_arrow.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"
width="12px"
inkscape:zoom="72.75"
inkscape:cx="4.7079038"
inkscape:cy="6"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg10" />
<g
fill="none"
fill-rule="evenodd"
stroke-linecap="round"
stroke-linejoin="round"
id="g8"
transform="translate(2.5)">
<g
stroke="#ffffff"
stroke-width="2"
id="g6">
<g
id="g4">
<path
d="m 221,30 5,-5 m -4.996,-5 4.996,5"
transform="translate(-220,-19)"
id="path2" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg2"
width="14"
height="14"
viewBox="0 0 14 14"
sodipodi:docname="timeline_close.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="29.1"
inkscape:cx="8.3333333"
inkscape:cy="15"
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="14"
height="14"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAERlWElmTU0A KgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAHqADAAQAAAAB AAAAHgAAAADKQTcFAAAFMUlEQVRIDbVXfUxbVRS/5z5axteCzjkdRJMlUnUZmXxFw2YWJzBti4CC aysVtC2MuUT9x8SvNC4x+oeZn4w95sKEQlgj+2hxMtBtaGIic1PnMLIsi4loYjIZAweWvnc9t+w9 7gNKCGH3j95zfufjd8959913K9mcngP3bCy4dPHnM3+TmzisTl+lZUPOq1nZuauGzp89C1aHhxEg /xICZd3tzX03g9vm9O5mjL2u5wZaRWMKIynAWLfN5XlKNy6D4Pf7qd3paTSQYl4gZP00MSqMEDNh 0Gl3+DzLwEl8Pp/pzNBwQGVkh5gPgIxRKnVwYuScHrgyqhK12er0vqJhS5ntPl/yn+PsKObbLsYj 6RUA2Hqsbe9vVKKSG4uPig6EsXdsDu+7BmyRSlnNi+nqGOtF0scMIQB/mCTz5lCgeYDj2G5C7C6v TWUsiLWv4Lo+AD5NLiuqC1ZVKTq2gFBZ03DHxH+RHmxhttENhhLBXNzV/snvGh4j5kqps+5hhagh rHalZuQztubzpKwMZ9Dvj4j4bNnq3LGOkKleXDzOMwMJzpkSErYdbm0yvK46MXctddc/oEaVL7FN t8+EogTQl5xuKg82No4b8BvKEy7fhihjPbjoOw12IP3pkGQPBD66ZsBR0Xc1Nxz7rOkcQpvwAegt iQUw9ujE1chX5e6dq2K68GNz1D2EpKdnk+JGCq02Z5bMR8rDDcQcCLfvu5gIZBOKv3JdG4yRgkg0 0m9z12doGO7+EgJqH5LeomF8xsfTmpeVWdHS4p8UcVE2tFo08OqmopHj2PZ8EefdACIV4ZzDmNqK pCbRjqQfhALySzjrr6lo1+S4xNyhsqEhFVt8BKvdqgXEZoBrGJiKizJ2DOib3e3yboNvHEWKg8fg wYGBSMmWws6Riej9CNwn+CairC8aq1MpgRfCHc3vCT4LinrwQl6Vhw5JE4d7ZUbYc3P9IEol5g61 7e+Ya4uPGFsV3w/LY3G6w4CpsOg8GkWcZJqZkJoa/4rRCz8Gcac8PYMaJE5absnOuzJ0/ofvDZYF lAWJXa5dK0ei/4QxfpuYAxcxSgHMiGmPCmf2uCU7h+BH/rToG0+O26LK2l2rR9nkSSTZIgbjRrps NtNcvD1sRzbDMYq73291eD/E3a4tSAw1yPM62N2+u1hUPYGJLKI3Ov9ilmhxV5v8F8ftLl+xytQu PJ9TRD+U2/ItmbV4ETB+9QSnOcR4EbhXBYaHPcsU/PA0It8xYrJ2t+8dEXG7y/OgqpJuxG4VcexM OGlNalVwz54JEddkA3FpdV2eqqj8tLpNc+AzJumBVKgIyfJ1Eddk+7Pe9SzCTuBjWathfAYC3ySl gT0oy6MizmX9GdurPY+oivL1XFLSuTYV7PFIeZLQweYLkMDPd7jEdW3ge7/5+jg7VV5db/zaoUOM 2ObylqtR+AKfaZoWxGestAkPe6csy1MiPp8cat1/WUpJLsQqfzLYGds4pSjfVjh33i3igJ+1WkKU ZmyT4dWiQN8Otcuvic6LkfnVZyoyHsYNVyj644KGJUqLjwb2DXKcMqIcmEXKkPTlpZDyhEda3r+a vCatCLt1nOvawLZnKEzptznrCzg2faG/YcWdpjBKn+8OyAe1gKXO/Ho7PMYwD3OIObDycSol5Omb C7fgJL4yTy4HKSfi+yLfkvEModAoEmPlqaqqOGIVI+EYoQml4bamU6LTcsn4b+ItvNi/oefDvzCS JTt3nQRSbSiwL3bf1Y3LKOD5fTIrO28QC4wAhY/xP1rr/65z4vA1bJBHAAAAAElFTkSuQmCC "
id="image10"
x="0"
y="0" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="13"
width="15"
height="15"
viewBox="0 0 13 15"
viewBox="0 0 15 15"
version="1.1"
id="svg16"
sodipodi:docname="secure_level_1.svg"
@ -30,11 +30,13 @@
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg16" />
inkscape:current-layer="svg16"
width="15px" />
<g
fill="none"
fill-rule="evenodd"
id="g14">
id="g14"
transform="matrix(1.0283369,0,0,1.0153836,0.84203685,-0.00127697)">
<g
id="g12">
<g
@ -42,20 +44,20 @@
<g
id="g8">
<path
fill="#96C11F"
d="M6.478 14.72c-.008.006-.016.012-.025.016-.042.025-.09.038-.136.038-.045 0-.089-.012-.129-.035-.068-.038-1.68-.973-3.257-2.894C1.474 10.07-.214 7.087.022 2.96c.007-.12.095-.22.213-.245C3.521 2.057 6.055.178 6.161.098L6.173.09l.065-.043c.095-.064.22-.061.311.01.025.02 2.554 1.953 5.856 2.615.118.023.206.124.213.245.447 7.827-5.615 11.502-6.14 11.804"
transform="translate(-637.000000, -296.000000) translate(609.000000, 196.000000) translate(0.000000, 90.000000) translate(28.153846, 10.000000)"
fill="#96c11f"
d="M 6.478,14.72 C 6.47,14.726 6.462,14.732 6.453,14.736 6.411,14.761 6.363,14.774 6.317,14.774 6.272,14.774 6.228,14.762 6.188,14.739 6.12,14.701 4.508,13.766 2.931,11.845 1.474,10.07 -0.214,7.087 0.022,2.96 0.029,2.84 0.117,2.74 0.235,2.715 3.521,2.057 6.055,0.178 6.161,0.098 L 6.173,0.09 6.238,0.047 c 0.095,-0.064 0.22,-0.061 0.311,0.01 0.025,0.02 2.554,1.953 5.856,2.615 0.118,0.023 0.206,0.124 0.213,0.245 0.447,7.827 -5.615,11.502 -6.14,11.804"
transform="translate(0.153846)"
id="path2" />
<path
fill="#FEFEFE"
d="M3.652 3.681L3.033 4.934 1.65 5.135 2.651 6.111 2.415 7.488 3.652 6.838 4.889 7.488 4.653 6.111 5.654 5.135 4.27 4.934z"
transform="translate(-637.000000, -296.000000) translate(609.000000, 196.000000) translate(0.000000, 90.000000) translate(28.153846, 10.000000)"
fill="#fefefe"
d="M 3.652,3.681 3.033,4.934 1.65,5.135 2.651,6.111 2.415,7.488 3.652,6.838 4.889,7.488 4.653,6.111 5.654,5.135 4.27,4.934 Z"
transform="translate(0.153846)"
id="path4" />
<path
fill="#FEFEFE"
d="M8.856 3.681L8.237 4.934 6.854 5.135 7.855 6.111 7.619 7.488 8.856 6.838 10.093 7.488 9.857 6.111 10.858 5.135 9.474 4.934z"
opacity=".35"
transform="translate(-637.000000, -296.000000) translate(609.000000, 196.000000) translate(0.000000, 90.000000) translate(28.153846, 10.000000)"
fill="#fefefe"
d="M 8.856,3.681 8.237,4.934 6.854,5.135 7.855,6.111 7.619,7.488 8.856,6.838 10.093,7.488 9.857,6.111 10.858,5.135 9.474,4.934 Z"
opacity="0.35"
transform="translate(0.153846)"
id="path6" />
</g>
</g>

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="21"
viewBox="0 0 19 21"
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg18"
sodipodi:docname="secure_off.svg"
@ -23,18 +23,20 @@
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="41.571429"
inkscape:cx="9.4896907"
inkscape:cx="9.4896906"
inkscape:cy="10.5"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg18" />
inkscape:current-layer="svg18"
width="18px" />
<g
fill="none"
fill-rule="evenodd"
id="g16">
id="g16"
transform="matrix(0.72345975,0,0,0.71432646,0.99978048,-8.5563664e-4)">
<g
id="g14">
<g
@ -44,22 +46,21 @@
<g
id="g8">
<path
fill="#444"
fill-opacity=".2"
d="M9.208 20.924c-.011.008-.023.017-.035.023-.06.034-.127.053-.194.053-.064 0-.126-.016-.183-.05-.096-.054-2.388-1.383-4.63-4.113-2.07-2.524-4.47-6.763-4.134-12.63.01-.17.134-.313.302-.348C5.004 2.924 8.606.254 8.757.14l.018-.012.092-.062c.135-.091.313-.086.442.014.036.028 3.63 2.777 8.324 3.717.169.033.293.178.303.348.636 11.127-7.982 16.35-8.728 16.78"
transform="translate(-103.000000, -189.000000) translate(73.000000, 89.000000) translate(30.000000, 67.000000) translate(0.000000, 33.000000)"
fill="#444444"
fill-opacity="0.2"
d="M 9.208,20.924 C 9.197,20.932 9.185,20.941 9.173,20.947 9.113,20.981 9.046,21 8.979,21 8.915,21 8.853,20.984 8.796,20.95 8.7,20.896 6.408,19.567 4.166,16.837 2.096,14.313 -0.304,10.074 0.032,4.207 0.042,4.037 0.166,3.894 0.334,3.859 5.004,2.924 8.606,0.254 8.757,0.14 L 8.775,0.128 8.867,0.066 C 9.002,-0.025 9.18,-0.02 9.309,0.08 c 0.036,0.028 3.63,2.777 8.324,3.717 0.169,0.033 0.293,0.178 0.303,0.348 0.636,11.127 -7.982,16.35 -8.728,16.78"
id="path2" />
<path
fill="#FFF"
fill="#ffffff"
fill-rule="nonzero"
d="M9.77 15.115c0 .397-.323.719-.72.719-.397 0-.719-.322-.719-.72V4.713c0-.398.322-.72.72-.72.396 0 .718.322.718.72v10.403z"
transform="translate(-103.000000, -189.000000) translate(73.000000, 89.000000) translate(30.000000, 67.000000) translate(0.000000, 33.000000) translate(9.050235, 9.913249) rotate(-45.000000) translate(-9.050235, -9.913249)"
d="m 9.77,15.115 c 0,0.397 -0.323,0.719 -0.72,0.719 -0.397,0 -0.719,-0.322 -0.719,-0.72 V 4.713 c 0,-0.398 0.322,-0.72 0.72,-0.72 0.396,0 0.718,0.322 0.718,0.72 v 10.403 z"
transform="rotate(-45,9.050235,9.913249)"
id="path4" />
<path
fill="#FFF"
fill="#ffffff"
fill-rule="nonzero"
d="M3.871 10.632c-.397 0-.719-.322-.719-.719 0-.397.322-.719.72-.719h10.403c.397 0 .719.322.719.72 0 .396-.322.718-.72.718H3.872z"
transform="translate(-103.000000, -189.000000) translate(73.000000, 89.000000) translate(30.000000, 67.000000) translate(0.000000, 33.000000) translate(9.073053, 9.913249) rotate(-45.000000) translate(-9.073053, -9.913249)"
d="m 3.871,10.632 c -0.397,0 -0.719,-0.322 -0.719,-0.719 0,-0.397 0.322,-0.719 0.72,-0.719 h 10.403 c 0.397,0 0.719,0.322 0.719,0.72 0,0.396 -0.322,0.718 -0.72,0.718 H 3.872 Z"
transform="rotate(-45,9.073053,9.913249)"
id="path6" />
</g>
</g>

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="19"
height="21"
viewBox="0 0 19 21"
width="15"
height="15"
viewBox="0 0 15 15"
version="1.1"
id="svg14"
sodipodi:docname="secure_on.svg"
@ -23,20 +23,22 @@
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="41.571429"
inkscape:cx="9.4896907"
inkscape:cx="9.4896906"
inkscape:cy="10.5"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg14" />
inkscape:current-layer="svg14"
width="13px" />
<g
fill="none"
fill-rule="evenodd"
id="g12">
id="g12"
transform="matrix(0.72345975,0,0,0.71432646,0.99978048,-8.5563367e-4)">
<g
fill="#96C11F"
fill="#96c11f"
id="g10">
<g
id="g8">
@ -45,8 +47,7 @@
<g
id="g4">
<path
d="M9.208 20.924c-.011.008-.023.017-.035.023-.06.034-.127.053-.194.053-.064 0-.126-.016-.183-.05-.096-.054-2.388-1.383-4.63-4.113-2.07-2.524-4.47-6.763-4.134-12.63.01-.17.134-.313.302-.348C5.004 2.924 8.606.254 8.757.14l.018-.012.092-.062c.135-.091.313-.086.442.014.036.028 3.63 2.777 8.324 3.717.169.033.293.178.303.348.636 11.127-7.982 16.35-8.728 16.78"
transform="translate(-185.000000, -189.000000) translate(73.000000, 89.000000) translate(30.000000, 67.000000) translate(0.000000, 33.000000) translate(82.000000, 0.000000)"
d="M 9.208,20.924 C 9.197,20.932 9.185,20.941 9.173,20.947 9.113,20.981 9.046,21 8.979,21 8.915,21 8.853,20.984 8.796,20.95 8.7,20.896 6.408,19.567 4.166,16.837 2.096,14.313 -0.304,10.074 0.032,4.207 0.042,4.037 0.166,3.894 0.334,3.859 5.004,2.924 8.606,0.254 8.757,0.14 L 8.775,0.128 8.867,0.066 C 9.002,-0.025 9.18,-0.02 9.309,0.08 c 0.036,0.028 3.63,2.777 8.324,3.717 0.169,0.033 0.293,0.178 0.303,0.348 0.636,11.127 -7.982,16.35 -8.728,16.78"
id="path2" />
</g>
</g>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
version="1.1"
id="svg15"
sodipodi:docname="timeline_search.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">
<sodipodi:namedview
id="namedview17"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="54.5625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg15" />
<defs
id="defs5">
<filter
id="15qdh5dl2a"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 0.294118 0 0 0 0 0.349020 0 0 0 0 0.392157 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
<g
fill="none"
fill-rule="evenodd"
id="g13">
<g
id="g11">
<g
filter="url(#15qdh5dl2a)"
transform="translate(-259.000000, -203.000000) translate(49.000000, 196.000000)"
id="g9">
<path
fill="#CBCBCB"
d="M.605 4.13c.352-.828.828-1.542 1.428-2.142.6-.6 1.315-1.077 2.143-1.429C5.005.207 5.873.03 6.781.03c.908 0 1.776.177 2.605.529.828.352 1.543.829 2.143 1.429.6.6 1.076 1.314 1.428 2.142.353.83.529 1.697.529 2.605 0 1.397-.394 2.664-1.181 3.8l3.266 3.267c.235.235.353.52.353.857 0 .33-.12.616-.362.857-.241.241-.527.362-.857.362-.343 0-.629-.12-.857-.362L10.58 12.26c-1.137.787-2.403 1.181-3.8 1.181-.908 0-1.776-.176-2.605-.529-.828-.352-1.543-.828-2.143-1.428-.6-.6-1.076-1.314-1.428-2.143C.252 8.511.076 7.643.076 6.735c0-.908.176-1.776.529-2.605zm1.91 2.605c0 1.175.417 2.18 1.252 3.015.835.834 1.84 1.252 3.014 1.252 1.175 0 2.18-.418 3.014-1.252.835-.835 1.253-1.84 1.253-3.015 0-1.174-.418-2.18-1.253-3.014-.835-.835-1.84-1.252-3.014-1.252-1.175 0-2.18.417-3.014 1.252-.835.835-1.253 1.84-1.253 3.014z"
transform="translate(210.000000, 7.000000)"
id="path7" />
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -1,18 +1,23 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="14"
height="14"
viewBox="0 0 14 14"
version="1.1"
id="svg15"
id="svg2"
width="32"
height="32"
viewBox="0 0 32 32"
sodipodi:docname="timeline_search.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="namedview17"
id="namedview4"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -20,47 +25,33 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="54.5625"
inkscape:cx="8"
inkscape:cy="8"
inkscape:zoom="27.28125"
inkscape:cx="16"
inkscape:cy="16"
inkscape:window-width="1920"
inkscape:window-height="1092"
inkscape:window-x="1920"
inkscape:window-y="33"
inkscape:window-maximized="1"
inkscape:current-layer="svg15" />
<defs
id="defs5">
<filter
id="15qdh5dl2a"
color-interpolation-filters="auto"
x="0"
y="0"
width="1"
height="1">
<feColorMatrix
in="SourceGraphic"
values="0 0 0 0 0.294118 0 0 0 0 0.349020 0 0 0 0 0.392157 0 0 0 1.000000 0"
id="feColorMatrix2" />
</filter>
</defs>
inkscape:current-layer="g8" />
<g
fill="none"
fill-rule="evenodd"
id="g13"
transform="matrix(0.88339223,0,0,0.88339223,-0.06713781,-0.02650177)">
<g
id="g11">
<g
filter="url(#15qdh5dl2a)"
transform="translate(-210,-7)"
id="g9">
<path
fill="#cbcbcb"
d="M 0.605,4.13 C 0.957,3.302 1.433,2.588 2.033,1.988 2.633,1.388 3.348,0.911 4.176,0.559 5.005,0.207 5.873,0.03 6.781,0.03 c 0.908,0 1.776,0.177 2.605,0.529 0.828,0.352 1.543,0.829 2.143,1.429 0.6,0.6 1.076,1.314 1.428,2.142 0.353,0.83 0.529,1.697 0.529,2.605 0,1.397 -0.394,2.664 -1.181,3.8 l 3.266,3.267 c 0.235,0.235 0.353,0.52 0.353,0.857 0,0.33 -0.12,0.616 -0.362,0.857 -0.241,0.241 -0.527,0.362 -0.857,0.362 -0.343,0 -0.629,-0.12 -0.857,-0.362 L 10.58,12.26 c -1.137,0.787 -2.403,1.181 -3.8,1.181 -0.908,0 -1.776,-0.176 -2.605,-0.529 C 3.347,12.56 2.632,12.084 2.032,11.484 1.432,10.884 0.956,10.17 0.604,9.341 0.252,8.511 0.076,7.643 0.076,6.735 0.076,5.827 0.252,4.959 0.605,4.13 Z m 1.91,2.605 c 0,1.175 0.417,2.18 1.252,3.015 0.835,0.834 1.84,1.252 3.014,1.252 1.175,0 2.18,-0.418 3.014,-1.252 C 10.63,8.915 11.048,7.91 11.048,6.735 11.048,5.561 10.63,4.555 9.795,3.721 8.96,2.886 7.955,2.469 6.781,2.469 5.606,2.469 4.601,2.886 3.767,3.721 2.932,4.556 2.514,5.561 2.514,6.735 Z"
transform="translate(210,7)"
id="path7" />
</g>
</g>
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="32"
height="32"
preserveAspectRatio="none"
style="image-rendering:optimizeQuality"
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAAAFzUkdC
AK7OHOkAAAA8UExURUdwTExaZEtaZE1cZ0xaZUtaZU1bZ0xZZVNia1pqckxbZkxaZExaZU1bZUtZ
ZEtZZUtZZExaZExZZUtZZHcCA00AAAATdFJOUwDI9S6BlCLlEQhC23RS7dK5p2DG16tEAAAA5klE
QVQ4y42S67bEEAyFU6JELxjv/66zGjVDOKezfxHfkp0LQJU3MdgtGk8w025z1Ykj4rfcyh7i/aWy
EPbvn7iaElrdqTUB6WqmyRI4kNx9JVN41yfAIeUnwgWkzhSyn7tYzRfXAWQbF0wb2bYmmK6zF8B6
BZdyjtd5la3lfjZFOgmcl7Eff5h64NLCaHhaRenD+ncfisvYATyNs67NkWWSXUynTDPWUl2ZpiW5
D8p4R87jea9dY+vIM3WEeiJ06J62MBDw+i6+RXLLSIDGtGwhIrd9SnT6mUjwQCzwQOz/AEAYd3gD
nfob8h+L4UQAAAAASUVORK5CYII=
"
id="image10" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -1,23 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="30"
height="30"
viewBox="0 0 30 30"
version="1.1"
id="svg2"
width="84"
height="100"
viewBox="0 0 84 100"
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: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" />
id="defs16" />
<sodipodi:namedview
id="namedview4"
id="namedview14"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
@ -25,100 +22,37 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="8.73"
inkscape:cx="41.981672"
inkscape:cy="50"
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="g8" />
inkscape:current-layer="svg12" />
<g
inkscape:groupmode="layer"
inkscape:label="Image"
id="g8">
<image
width="84"
height="100"
preserveAspectRatio="none"
xlink:href="data:image/png;base64,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
"
id="image10" />
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>

Before

Width:  |  Height:  |  Size: 7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -68,6 +68,7 @@
<file>assets/images/chat_is_composing_1.svg</file>
<file>assets/images/chat_is_composing_2.svg</file>
<file>assets/images/chat_is_composing_3.svg</file>
<file>assets/images/chat_micro.svg</file>
<file>assets/images/chat_normal.svg</file>
<file>assets/images/chat_pressed.svg</file>
<file>assets/images/chat_read.svg</file>
@ -88,9 +89,13 @@
<file>assets/images/contact_edit_hovered.svg</file>
<file>assets/images/contact_edit_normal.svg</file>
<file>assets/images/contact_edit_pressed.svg</file>
<file>assets/images/contact_disabled.svg</file>
<file>assets/images/contact_normal.svg</file>
<file>assets/images/contact_selected.svg</file>
<file>assets/images/current_account_status_available.svg</file>
<file>assets/images/current_account_status_online.svg</file>
<file>assets/images/current_account_status_offline.svg</file>
<file>assets/images/current_account_status_dnd.svg</file>
<file>assets/images/current_account_status_busy.svg</file>
<file>assets/images/declined_incoming_call.svg</file>
<file>assets/images/declined_outgoing_call.svg</file>
<file>assets/images/delete_hovered.svg</file>
@ -118,6 +123,9 @@
<file>assets/images/generic_error_normal.svg</file>
<file>assets/images/generic_error_pressed.svg</file>
<file>assets/images/generic_error.svg</file>
<file>assets/images/group_chat_hovered.svg</file>
<file>assets/images/group_chat_normal.svg</file>
<file>assets/images/group_chat_pressed.svg</file>
<file>assets/images/hangup_hovered.svg</file>
<file>assets/images/hangup_normal.svg</file>
<file>assets/images/hangup_pressed.svg</file>
@ -169,6 +177,7 @@
<file>assets/images/options_normal.svg</file>
<file>assets/images/options_pressed.svg</file>
<file>assets/images/outgoing_call.svg</file>
<file>assets/images/panel_arrow.svg</file>
<file>assets/images/panel_hidden_normal.svg</file>
<file>assets/images/panel_hidden_hovered.svg</file>
<file>assets/images/panel_hidden_pressed.svg</file>
@ -482,6 +491,7 @@
<file>ui/views/App/Main/Dialogs/AuthenticationRequest.qml</file>
<file>ui/views/App/Main/Dialogs/EphemeralChatRoom.qml</file>
<file>ui/views/App/Main/Dialogs/InfoChatRoom.qml</file>
<file>ui/views/App/Main/Dialogs/InfoEncryption.qml</file>
<file>ui/views/App/Main/Dialogs/ManageAccount.js</file>
<file>ui/views/App/Main/Dialogs/ManageAccounts.qml</file>
<file>ui/views/App/Main/Dialogs/ManageChatRoom.qml</file>
@ -531,6 +541,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/InfoEncryptionStyle.qml</file>
<file>ui/views/App/Styles/Main/Dialogs/ManageAccountsStyle.qml</file>
<file>ui/views/App/Styles/Main/HomeStyle.qml</file>
<file>ui/views/App/Styles/Main/InviteFriendsStyle.qml</file>

View file

@ -215,6 +215,8 @@ bool App::setFetchConfig (QCommandLineParser *parser) {
}
// -----------------------------------------------------------------------------
App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
connect(this, SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(stateChanged(Qt::ApplicationState)));
@ -592,8 +594,12 @@ void App::registerTypes () {
qRegisterMetaType<std::shared_ptr<ChatRoomModel>>();
qRegisterMetaType<std::shared_ptr<ParticipantListModel>>();
qRegisterMetaType<std::shared_ptr<ParticipantDeviceModel>>();
qRegisterMetaType<std::shared_ptr<ChatMessageModel>>();
qRegisterMetaType<std::shared_ptr<ChatNoticeModel>>();
qRegisterMetaType<std::shared_ptr<ChatCallModel>>();
//qRegisterMetaType<std::shared_ptr<ChatEvent>>();
LinphoneEnums::registerMetaTypes();
registerType<AssistantModel>("AssistantModel");
registerType<AuthenticationNotifier>("AuthenticationNotifier");
registerType<CallsListProxyModel>("CallsListProxyModel");
@ -626,13 +632,17 @@ void App::registerTypes () {
registerSingletonType<VideoCodecsModel>("VideoCodecsModel");
registerUncreatableType<CallModel>("CallModel");
registerUncreatableType<ChatCallModel>("ChatCallModel");
registerUncreatableType<ChatMessageModel>("ChatMessageModel");
registerUncreatableType<ChatNoticeModel>("ChatNoticeModel");
registerUncreatableType<ChatRoomModel>("ChatRoomModel");
registerUncreatableType<ConferenceHelperModel::ConferenceAddModel>("ConferenceAddModel");
registerUncreatableType<ContactModel>("ContactModel");
registerUncreatableType<ContactsImporterModel>("ContactsImporterModel");
registerUncreatableType<ContentModel>("ContentModel");
registerUncreatableType<HistoryModel>("HistoryModel");
registerUncreatableType<LdapModel>("LdapModel");
registerUncreatableType<SearchResultModel>("SearchResultModel");
registerUncreatableType<SipAddressObserver>("SipAddressObserver");
registerUncreatableType<VcardModel>("VcardModel");
registerUncreatableType<TimelineModel>("TimelineModel");
@ -641,6 +651,11 @@ void App::registerTypes () {
registerUncreatableType<ParticipantDeviceModel>("ParticipantDeviceModel");
registerUncreatableType<ParticipantDeviceListModel>("ParticipantDeviceListModel");
registerUncreatableType<ParticipantDeviceProxyModel>("ParticipantDeviceProxyModel");
registerUncreatableType<ParticipantImdnStateModel>("ParticipantImdnStateModel");
registerUncreatableType<ParticipantImdnStateListModel>("ParticipantImdnStateListModel");
registerUncreatableType<ParticipantImdnStateProxyModel>("ParticipantImdnStateProxyModel");
qmlRegisterUncreatableMetaObject(LinphoneEnums::staticMetaObject, "LinphoneEnums", 1, 0, "LinphoneEnums", "Only enums");
}
@ -668,7 +683,7 @@ void App::registerToolTypes () {
registerToolType<TextToSpeech>("TextToSpeech");
registerToolType<Units>("Units");
registerToolType<ContactsImporterPluginsManager>("ContactsImporterPluginsManager");
registerToolType<Utils>("Utils");
registerToolType<Utils>("UtilsCpp");
}
void App::registerSharedToolTypes () {

View file

@ -28,7 +28,9 @@
#include "calls/CallsListProxyModel.hpp"
#include "camera/Camera.hpp"
#include "camera/CameraPreview.hpp"
#include "components/chat-message/ChatMessageModel.hpp"
#include "components/chat-events/ChatCallModel.hpp"
#include "components/chat-events/ChatMessageModel.hpp"
#include "components/chat-events/ChatNoticeModel.hpp"
#include "chat-room/ChatRoomProxyModel.hpp"
#include "codecs/AudioCodecsModel.hpp"
#include "codecs/VideoCodecsModel.hpp"
@ -57,13 +59,17 @@
#include "participant/ParticipantDeviceListModel.hpp"
#include "participant/ParticipantDeviceModel.hpp"
#include "participant/ParticipantDeviceProxyModel.hpp"
#include "participant-imdn/ParticipantImdnStateModel.hpp"
#include "participant-imdn/ParticipantImdnStateListModel.hpp"
#include "participant-imdn/ParticipantImdnStateProxyModel.hpp"
#include "presence/OwnPresenceModel.hpp"
#include "settings/AccountSettingsModel.hpp"
#include "settings/SettingsModel.hpp"
#include "search/SearchResultModel.hpp"
#include "sip-addresses/SipAddressesModel.hpp"
#include "sip-addresses/SipAddressesProxyModel.hpp"
#include "sip-addresses/SearchSipAddressesModel.hpp"
#include "sip-addresses/SearchSipAddressesProxyModel.hpp"
#include "search/SearchSipAddressesModel.hpp"
#include "search/SearchSipAddressesProxyModel.hpp"
#include "sound-player/SoundPlayer.hpp"
#include "telephone-numbers/TelephoneNumbersModel.hpp"
#include "timeline/TimelineModel.hpp"

View file

@ -26,6 +26,7 @@
#include "app/App.hpp"
#include "components/calls/CallsListModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreHandlers.hpp"
@ -33,6 +34,7 @@
#include "components/notifier/Notifier.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/timeline/TimelineListModel.hpp"
#include "utils/MediastreamerUtils.hpp"
#include "utils/Utils.hpp"
@ -88,6 +90,7 @@ CallModel::CallModel (shared_ptr<linphone::Call> call){
mRemoteAddress = mCall->getRemoteAddress()->clone();
mMagicSearch->getContactListFromFilterAsync(mRemoteAddress->getUsername(),mRemoteAddress->getDomain());
qWarning() << getFullPeerAddress();
}
CallModel::~CallModel () {
@ -118,6 +121,12 @@ ContactModel *CallModel::getContactModel() const{
return contact;
}
ChatRoomModel * CallModel::getChatRoomModel() const{
if(mCall->getCallLog()->getCallId() != "")
return CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(mCall->getChatRoom(), true).get();
else
return nullptr;
}
// -----------------------------------------------------------------------------
void CallModel::setRecordFile (const shared_ptr<linphone::CallParams> &callParams) {

View file

@ -27,6 +27,7 @@
// =============================================================================
class ContactModel;
class ChatRoomModel;
class CallModel : public QObject {
Q_OBJECT;
@ -36,7 +37,10 @@ class CallModel : public QObject {
Q_PROPERTY(QString fullPeerAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged);
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress CONSTANT);
Q_PROPERTY(ContactModel *contact READ getContactModel CONSTANT )/*
Q_PROPERTY(ContactModel *contactModel READ getContactModel CONSTANT )
Q_PROPERTY(ChatRoomModel * chatRoomModel READ getChatRoomModel CONSTANT)
/*
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
@ -74,6 +78,8 @@ class CallModel : public QObject {
Q_PROPERTY(float speakerVolumeGain READ getSpeakerVolumeGain WRITE setSpeakerVolumeGain NOTIFY speakerVolumeGainChanged);
Q_PROPERTY(float microVolumeGain READ getMicroVolumeGain WRITE setMicroVolumeGain NOTIFY microVolumeGainChanged);
public:
enum CallStatus {
@ -107,6 +113,8 @@ public:
QString getFullLocalAddress () const;
ContactModel *getContactModel() const;
ChatRoomModel * getChatRoomModel() const;
bool isInConference () const {
return mIsInConference;

View file

@ -36,209 +36,205 @@
#include "CallsListModel.hpp"
#include "utils/hacks/ChatRoomInitializer.hpp"
// =============================================================================
using namespace std;
namespace {
// Delay before removing call in ms.
constexpr int DelayBeforeRemoveCall = 3000;
// Delay before removing call in ms.
constexpr int DelayBeforeRemoveCall = 3000;
}
static inline int findCallIndex (QList<CallModel *> &list, const shared_ptr<linphone::Call> &call) {
auto it = find_if(list.begin(), list.end(), [call](CallModel *callModel) {
return call == callModel->getCall();
});
Q_ASSERT(it != list.end());
return int(distance(list.begin(), it));
auto it = find_if(list.begin(), list.end(), [call](CallModel *callModel) {
return call == callModel->getCall();
});
Q_ASSERT(it != list.end());
return int(distance(list.begin(), it));
}
static inline int findCallIndex (QList<CallModel *> &list, const CallModel &callModel) {
return ::findCallIndex(list, callModel.getCall());
return ::findCallIndex(list, callModel.getCall());
}
// -----------------------------------------------------------------------------
CallsListModel::CallsListModel (QObject *parent) : QAbstractListModel(parent) {
mCoreHandlers = CoreManager::getInstance()->getHandlers();
QObject::connect(
mCoreHandlers.get(), &CoreHandlers::callStateChanged,
this, &CallsListModel::handleCallStateChanged
);
mCoreHandlers = CoreManager::getInstance()->getHandlers();
QObject::connect(
mCoreHandlers.get(), &CoreHandlers::callStateChanged,
this, &CallsListModel::handleCallStateChanged
);
}
int CallsListModel::rowCount (const QModelIndex &) const {
return mList.count();
return mList.count();
}
QHash<int, QByteArray> CallsListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$call";
return roles;
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$call";
return roles;
}
QVariant CallsListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row]);
return QVariant();
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row]);
return QVariant();
}
// -----------------------------------------------------------------------------
void CallsListModel::askForTransfer (CallModel *callModel) {
emit callTransferAsked(callModel);
emit callTransferAsked(callModel);
}
// -----------------------------------------------------------------------------
void CallsListModel::launchAudioCall (const QString &sipAddress, const QHash<QString, QString> &headers) const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()), Utils::appStringToCoreString(iterator.value()));
}
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
shared_ptr<linphone::ProxyConfig> currentProxyConfig = core->getDefaultProxyConfig();
if(currentProxyConfig){
if(currentProxyConfig->getState() == linphone::RegistrationState::Ok)
core->inviteAddressWithParams(address, params);
else{
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::registrationStateChanged,context,
[address,core,params,currentProxyConfig, context](const std::shared_ptr<linphone::ProxyConfig> &proxyConfig, linphone::RegistrationState state) mutable {
if(context && proxyConfig==currentProxyConfig && state==linphone::RegistrationState::Ok){
delete context;
context = nullptr;
core->inviteAddressWithParams(address, params);
}
});
}
}else
core->inviteAddressWithParams(address, params);
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()), Utils::appStringToCoreString(iterator.value()));
}
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
shared_ptr<linphone::ProxyConfig> currentProxyConfig = core->getDefaultProxyConfig();
if(currentProxyConfig){
if(currentProxyConfig->getState() == linphone::RegistrationState::Ok)
core->inviteAddressWithParams(address, params);
else{
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::registrationStateChanged,context,
[address,core,params,currentProxyConfig, context](const std::shared_ptr<linphone::ProxyConfig> &proxyConfig, linphone::RegistrationState state) mutable {
if(context && proxyConfig==currentProxyConfig && state==linphone::RegistrationState::Ok){
delete context;
context = nullptr;
core->inviteAddressWithParams(address, params);
}
});
}
}else
core->inviteAddressWithParams(address, params);
}
void CallsListModel::launchSecureAudioCall (const QString &sipAddress, LinphoneEnums::MediaEncryption encryption, const QHash<QString, QString> &headers) const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()), Utils::appStringToCoreString(iterator.value()));
}
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
shared_ptr<linphone::ProxyConfig> currentProxyConfig = core->getDefaultProxyConfig();
params->setMediaEncryption(LinphoneEnums::toLinphone(encryption));
if(currentProxyConfig){
if(currentProxyConfig->getState() == linphone::RegistrationState::Ok)
core->inviteAddressWithParams(address, params);
else{
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::registrationStateChanged,context,
[address,core,params,currentProxyConfig, context](const std::shared_ptr<linphone::ProxyConfig> &proxyConfig, linphone::RegistrationState state) mutable {
if(context && proxyConfig==currentProxyConfig && state==linphone::RegistrationState::Ok){
delete context;
context = nullptr;
core->inviteAddressWithParams(address, params);
}
});
}
}else
core->inviteAddressWithParams(address, params);
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(false);
QHashIterator<QString, QString> iterator(headers);
while (iterator.hasNext()) {
iterator.next();
params->addCustomHeader(Utils::appStringToCoreString(iterator.key()), Utils::appStringToCoreString(iterator.value()));
}
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
shared_ptr<linphone::ProxyConfig> currentProxyConfig = core->getDefaultProxyConfig();
params->setMediaEncryption(LinphoneEnums::toLinphone(encryption));
if(currentProxyConfig){
if(currentProxyConfig->getState() == linphone::RegistrationState::Ok)
core->inviteAddressWithParams(address, params);
else{
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::registrationStateChanged,context,
[address,core,params,currentProxyConfig, context](const std::shared_ptr<linphone::ProxyConfig> &proxyConfig, linphone::RegistrationState state) mutable {
if(context && proxyConfig==currentProxyConfig && state==linphone::RegistrationState::Ok){
delete context;
context = nullptr;
core->inviteAddressWithParams(address, params);
}
});
}
}else
core->inviteAddressWithParams(address, params);
}
void CallsListModel::launchVideoCall (const QString &sipAddress) const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->videoSupported()) {
qWarning() << QStringLiteral("Unable to launch video call. (Video not supported.) Launching audio call...");
launchAudioCall(sipAddress);
return;
}
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(true);
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
core->inviteAddressWithParams(address, params);
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->videoSupported()) {
qWarning() << QStringLiteral("Unable to launch video call. (Video not supported.) Launching audio call...");
launchAudioCall(sipAddress);
return;
}
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return;
shared_ptr<linphone::CallParams> params = core->createCallParams(nullptr);
params->enableVideo(true);
params->setProxyConfig(core->getDefaultProxyConfig());
CallModel::setRecordFile(params, QString::fromStdString(address->getUsername()));
core->inviteAddressWithParams(address, params);
}
ChatRoomModel* CallsListModel::launchSecureChat (const QString &sipAddress) const {
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return nullptr;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
std::shared_ptr<const linphone::Address> localAddress;
participants.push_back(address);
auto proxy = core->getDefaultProxyConfig();
params->enableEncryption(true);
params->setSubject("Dummy Subject");
params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(sipAddress));
if (!address)
return nullptr;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
std::shared_ptr<const linphone::Address> localAddress;
participants.push_back(address);
auto proxy = core->getDefaultProxyConfig();
params->enableEncryption(true);
params->setSubject("Dummy Subject");
params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
if( chatRoom != nullptr){
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
timelineList->update();
auto timeline = timelineList->getTimeline(chatRoom, false);
if(!timeline){
timeline = timelineList->getTimeline(chatRoom, true);
timelineList->add(timeline);
}
return timeline->getChatRoomModel();
}
return nullptr;
}
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
/*
if( chatRoom!=nullptr){
auto search = core->searchChatRoom(params, localAddress
, address
, participants);
if(search != chatRoom)
qWarning("toto");
}
return chatRoom!=nullptr;
*/
if( chatRoom != nullptr){
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
timelineList->update();
auto timeline = timelineList->getTimeline(chatRoom, false);
if(!timeline){
timeline = timelineList->getTimeline(chatRoom, true);
timelineList->add(timeline);
}
return timeline->getChatRoomModel();
}
return nullptr;
QVariantMap CallsListModel::launchChat(const QString &sipAddress, const int& securityLevel) const{
QVariantList participants;
participants << sipAddress;
return createChatRoom("", securityLevel, participants);
}
ChatRoomModel* CallsListModel::createChat (const QString &participantAddress) const{
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(participantAddress));
if (!address)
return nullptr;
return nullptr;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
@ -247,7 +243,7 @@ ChatRoomModel* CallsListModel::createChat (const QString &participantAddress) co
auto proxy = core->getDefaultProxyConfig();
params->setBackend(linphone::ChatRoomBackend::Basic);
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
/*
if( chatRoom!=nullptr){
@ -269,11 +265,19 @@ ChatRoomModel* CallsListModel::createChat (const QString &participantAddress) co
return nullptr;
}
ChatRoomModel* CallsListModel::createChat (const CallModel * model) const{
if(model){
return model->getChatRoomModel();
}
return nullptr;
}
bool CallsListModel::createSecureChat (const QString& subject, const QString &participantAddress) const{
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
shared_ptr<linphone::Address> address = core->interpretUrl(Utils::appStringToCoreString(participantAddress));
if (!address)
return false;
return false;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > participants;
@ -286,30 +290,35 @@ bool CallsListModel::createSecureChat (const QString& subject, const QString &pa
params->setBackend(linphone::ChatRoomBackend::FlexisipChat);
params->setEncryptionBackend(linphone::ChatRoomEncryptionBackend::Lime);
params->enableGroup(true);
std::shared_ptr<linphone::ChatRoom> chatRoom = core->createChatRoom(params, localAddress, participants);
return chatRoom != nullptr;
}
bool CallsListModel::createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants) const{
// Created, timeline that can be used
QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants) const{
QVariantMap result;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
std::shared_ptr<linphone::ChatRoom> chatRoom;
qWarning() << "Creation of " << subject << " " << securityLevel << " " << participants;
for(auto p : participants){
ParticipantModel* pp = p.value<ParticipantModel*>();
qWarning() << pp->getSipAddress() << "=>" << pp->getAdminStatus();
}
QList< std::shared_ptr<linphone::Address>> admins;
qWarning() << "ChatRoom creation of " << subject << " at " << securityLevel << " security and with " << participants;
std::shared_ptr<linphone::ChatRoomParams> params = core->createDefaultChatRoomParams();
std::list <shared_ptr<linphone::Address> > chatRoomParticipants;
std::shared_ptr<const linphone::Address> localAddress;
for(auto p : participants){
ParticipantModel* participant = p.value<ParticipantModel*>();
auto address = Utils::interpretUrl(participant->getSipAddress());
std::shared_ptr<linphone::Address> address;
if(participant) {
address = Utils::interpretUrl(participant->getSipAddress());
if(participant->getAdminStatus())
admins << address;
}else{
QString participant = p.toString();
if( participant != "")
address = Utils::interpretUrl(participant);
}
if( address)
chatRoomParticipants.push_back( address );
chatRoomParticipants.push_back( address );
}
auto proxy = core->getDefaultProxyConfig();
params->enableEncryption(securityLevel>0);
@ -320,34 +329,48 @@ bool CallsListModel::createChatRoom(const QString& subject, const int& securityL
}else
params->setBackend(linphone::ChatRoomBackend::Basic);
params->enableGroup(subject != "");
if(chatRoomParticipants.size() > 0) {
if(!params->groupEnabled()) {// Chat room is one-one : check if it is already exist with empty or dummy subject
chatRoom = core->searchChatRoom(params, localAddress
, localAddress
, chatRoomParticipants);
, localAddress
, chatRoomParticipants);
params->setSubject(subject != ""?subject.toStdString():"Dummy Subject");
if(!chatRoom)
chatRoom = core->searchChatRoom(params, localAddress
, localAddress
, chatRoomParticipants);
, localAddress
, chatRoomParticipants);
}else
params->setSubject(subject != ""?subject.toStdString():"Dummy Subject");
if( !chatRoom)
if( !chatRoom) {
chatRoom = core->createChatRoom(params, localAddress, chatRoomParticipants);
if(chatRoom != nullptr && admins.size() > 0)
ChatRoomInitializer::setAdminsAsync(params->getSubject(), params->getBackend(), params->groupEnabled(), admins );
}else{
if(admins.size() > 0){
ChatRoomInitializer::setAdminsSync(chatRoom, admins);
}
auto timelineList = CoreManager::getInstance()->getTimelineListModel();
auto timeline = timelineList->getTimeline(chatRoom, true);
QTimer::singleShot(200, [timeline](){// Delay process in order to let GUI time for Timeline building/linking before doing actions
timeline->setSelected(true);
});
result["chatRoomModel"] = QVariant::fromValue(timeline->getChatRoomModel());
}
}
return chatRoom != nullptr;
result["created"] = (chatRoom != nullptr);
return result;
}
// -----------------------------------------------------------------------------
int CallsListModel::getRunningCallsNumber () const {
return CoreManager::getInstance()->getCore()->getCallsNb();
return CoreManager::getInstance()->getCore()->getCallsNb();
}
void CallsListModel::terminateAllCalls () const {
CoreManager::getInstance()->getCore()->terminateAllCalls();
CoreManager::getInstance()->getCore()->terminateAllCalls();
}
void CallsListModel::terminateCall (const QString& sipAddress) const{
auto coreManager = CoreManager::getInstance();
@ -368,134 +391,134 @@ void CallsListModel::terminateCall (const QString& sipAddress) const{
// -----------------------------------------------------------------------------
static void joinConference (const shared_ptr<linphone::Call> &call) {
if (call->getToHeader("method") != "join-conference")
return;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->getConference()) {
qWarning() << QStringLiteral("Not in a conference. => Responding to `join-conference` as a simple call...");
return;
}
shared_ptr<linphone::Conference> conference = core->getConference();
const QString conferenceId = Utils::coreStringToAppString(call->getToHeader("conference-id"));
if (conference->getId() != Utils::appStringToCoreString(conferenceId)) {
qWarning() << QStringLiteral("Trying to join conference with an invalid conference id: `%1`. Responding as a simple call...")
.arg(conferenceId);
return;
}
qInfo() << QStringLiteral("Join conference: `%1`.").arg(conferenceId);
ConferenceHelperModel helperModel;
ConferenceHelperModel::ConferenceAddModel *addModel = helperModel.getConferenceAddModel();
CallModel *callModel = &call->getData<CallModel>("call-model");
callModel->accept();
addModel->addToConference(call->getRemoteAddress());
addModel->update();
if (call->getToHeader("method") != "join-conference")
return;
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
if (!core->getConference()) {
qWarning() << QStringLiteral("Not in a conference. => Responding to `join-conference` as a simple call...");
return;
}
shared_ptr<linphone::Conference> conference = core->getConference();
const QString conferenceId = Utils::coreStringToAppString(call->getToHeader("conference-id"));
if (conference->getId() != Utils::appStringToCoreString(conferenceId)) {
qWarning() << QStringLiteral("Trying to join conference with an invalid conference id: `%1`. Responding as a simple call...")
.arg(conferenceId);
return;
}
qInfo() << QStringLiteral("Join conference: `%1`.").arg(conferenceId);
ConferenceHelperModel helperModel;
ConferenceHelperModel::ConferenceAddModel *addModel = helperModel.getConferenceAddModel();
CallModel *callModel = &call->getData<CallModel>("call-model");
callModel->accept();
addModel->addToConference(call->getRemoteAddress());
addModel->update();
}
void CallsListModel::handleCallStateChanged (const shared_ptr<linphone::Call> &call, linphone::Call::State state) {
switch (state) {
case linphone::Call::State::IncomingReceived:
addCall(call);
joinConference(call);
break;
case linphone::Call::State::OutgoingInit:
addCall(call);
break;
case linphone::Call::State::End:
case linphone::Call::State::Error:
if (call->getCallLog()->getStatus() == linphone::Call::Status::Missed)
emit callMissed(&call->getData<CallModel>("call-model"));
removeCall(call);
break;
case linphone::Call::State::StreamsRunning: {
int index = findCallIndex(mList, call);
emit callRunning(index, &call->getData<CallModel>("call-model"));
} break;
default:
break;
}
switch (state) {
case linphone::Call::State::IncomingReceived:
addCall(call);
joinConference(call);
break;
case linphone::Call::State::OutgoingInit:
addCall(call);
break;
case linphone::Call::State::End:
case linphone::Call::State::Error:
if (call->getCallLog()->getStatus() == linphone::Call::Status::Missed)
emit callMissed(&call->getData<CallModel>("call-model"));
removeCall(call);
break;
case linphone::Call::State::StreamsRunning: {
int index = findCallIndex(mList, call);
emit callRunning(index, &call->getData<CallModel>("call-model"));
} break;
default:
break;
}
}
bool CallsListModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
return removeRows(row, 1, parent);
}
bool CallsListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row)->deleteLater();
endRemoveRows();
return true;
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row)->deleteLater();
endRemoveRows();
return true;
}
// -----------------------------------------------------------------------------
void CallsListModel::addCall (const shared_ptr<linphone::Call> &call) {
if (call->getDir() == linphone::Call::Dir::Outgoing) {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
if (CoreManager::getInstance()->getSettingsModel()->getKeepCallsWindowInBackground()) {
if (!callsWindow->isVisible())
callsWindow->showMinimized();
} else
App::smartShowWindow(callsWindow);
}
}
CallModel *callModel = new CallModel(call);
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
App::getInstance()->getEngine()->setObjectOwnership(callModel, QQmlEngine::CppOwnership);
// This connection is (only) useful for `CallsListProxyModel`.
QObject::connect(callModel, &CallModel::isInConferenceChanged, this, [this, callModel](bool) {
int id = findCallIndex(mList, *callModel);
emit dataChanged(index(id, 0), index(id, 0));
});
int row = mList.count();
beginInsertRows(QModelIndex(), row, row);
mList << callModel;
endInsertRows();
if (call->getDir() == linphone::Call::Dir::Outgoing) {
QQuickWindow *callsWindow = App::getInstance()->getCallsWindow();
if (callsWindow) {
if (CoreManager::getInstance()->getSettingsModel()->getKeepCallsWindowInBackground()) {
if (!callsWindow->isVisible())
callsWindow->showMinimized();
} else
App::smartShowWindow(callsWindow);
}
}
CallModel *callModel = new CallModel(call);
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
App::getInstance()->getEngine()->setObjectOwnership(callModel, QQmlEngine::CppOwnership);
// This connection is (only) useful for `CallsListProxyModel`.
QObject::connect(callModel, &CallModel::isInConferenceChanged, this, [this, callModel](bool) {
int id = findCallIndex(mList, *callModel);
emit dataChanged(index(id, 0), index(id, 0));
});
int row = mList.count();
beginInsertRows(QModelIndex(), row, row);
mList << callModel;
endInsertRows();
}
void CallsListModel::removeCall (const shared_ptr<linphone::Call> &call) {
CallModel *callModel;
try {
callModel = &call->getData<CallModel>("call-model");
} catch (const out_of_range &) {
// The call model not exists because the linphone call state
// `CallStateIncomingReceived`/`CallStateOutgoingInit` was not notified.
qWarning() << QStringLiteral("Unable to find call:") << call.get();
return;
}
QTimer::singleShot(DelayBeforeRemoveCall, this, [this, callModel] {
removeCallCb(callModel);
});
CallModel *callModel;
try {
callModel = &call->getData<CallModel>("call-model");
} catch (const out_of_range &) {
// The call model not exists because the linphone call state
// `CallStateIncomingReceived`/`CallStateOutgoingInit` was not notified.
qWarning() << QStringLiteral("Unable to find call:") << call.get();
return;
}
QTimer::singleShot(DelayBeforeRemoveCall, this, [this, callModel] {
removeCallCb(callModel);
});
}
void CallsListModel::removeCallCb (CallModel *callModel) {
qInfo() << QStringLiteral("Removing call:") << callModel;
int index = mList.indexOf(callModel);
if (index == -1 || !removeRow(index))
qWarning() << QStringLiteral("Unable to remove call:") << callModel;
qInfo() << QStringLiteral("Removing call:") << callModel;
int index = mList.indexOf(callModel);
if (index == -1 || !removeRow(index))
qWarning() << QStringLiteral("Unable to remove call:") << callModel;
}

View file

@ -49,10 +49,12 @@ public:
Q_INVOKABLE void launchSecureAudioCall (const QString &sipAddress, LinphoneEnums::MediaEncryption encryption, const QHash<QString, QString> &headers = {}) const;
Q_INVOKABLE void launchVideoCall (const QString &sipAddress) const;
Q_INVOKABLE ChatRoomModel* launchSecureChat (const QString &sipAddress) const;
Q_INVOKABLE QVariantMap launchChat(const QString &sipAddress, const int& securityLevel) const;
Q_INVOKABLE ChatRoomModel* createChat (const QString &participantAddress) const;
Q_INVOKABLE ChatRoomModel* createChat (const CallModel * ) const;
Q_INVOKABLE bool createSecureChat (const QString& subject, const QString &participantAddress) const;
Q_INVOKABLE bool createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants) const;
Q_INVOKABLE QVariantMap createChatRoom(const QString& subject, const int& securityLevel, const QVariantList& participants) const;
Q_INVOKABLE int getRunningCallsNumber () const;

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "ChatCallModel.hpp"
// =============================================================================
ChatCallModel::ChatCallModel ( std::shared_ptr<linphone::CallLog> callLog, const bool& isStart, QObject * parent) : QObject(parent), ChatEvent(ChatRoomModel::EntryType::CallEntry) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mCallLog = callLog;
if(isStart){
mTimestamp = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
setIsStart(true);
}else{
mTimestamp = QDateTime::fromMSecsSinceEpoch((callLog->getStartDate() + callLog->getDuration()) * 1000);
setIsStart(false);
}
}
ChatCallModel::~ChatCallModel(){
}
std::shared_ptr<ChatCallModel> ChatCallModel::create(std::shared_ptr<linphone::CallLog> callLog, const bool& isStart, QObject * parent){
auto model = std::make_shared<ChatCallModel>(callLog, isStart, parent);
if(model && model->update()){
model->mSelf = model;
return model;
}else
return nullptr;
}
std::shared_ptr<linphone::CallLog> ChatCallModel::getCallLog(){
return mCallLog;
}
//--------------------------------------------------------------------------------------------------------------------------
void ChatCallModel::setIsStart(const bool& data){
if(data != mIsStart) {
mIsStart = data;
emit isStartChanged();
}
}
void ChatCallModel::setStatus(const LinphoneEnums::CallStatus& data){
if(data != mStatus) {
mStatus = data;
emit statusChanged();
}
}
void ChatCallModel::setIsOutgoing(const bool& data){
if(data != mIsOutgoing) {
mIsOutgoing = data;
emit isOutgoingChanged();
}
}
bool ChatCallModel::update(){
setIsOutgoing(mCallLog->getDir() == linphone::Call::Dir::Outgoing);
setStatus(LinphoneEnums::fromLinphone(mCallLog->getStatus()));
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_CALL_MODEL_H
#define CHAT_CALL_MODEL_H
#include "utils/LinphoneEnums.hpp"
#include "ChatEvent.hpp"
// =============================================================================
class ChatCallModel : public QObject, public ChatEvent {
Q_OBJECT
public:
static std::shared_ptr<ChatCallModel> create(std::shared_ptr<linphone::CallLog> chatLog, const bool& isStart, QObject * parent = nullptr);// Call it instead constructor
ChatCallModel (std::shared_ptr<linphone::CallLog> eventLog, const bool& isStart, QObject * parent = nullptr);
virtual ~ChatCallModel();
Q_PROPERTY(ChatRoomModel::EntryType type MEMBER mType CONSTANT)
Q_PROPERTY(QDateTime timestamp MEMBER mTimestamp CONSTANT)
Q_PROPERTY(bool isStart MEMBER mIsStart WRITE setIsStart NOTIFY isStartChanged)
Q_PROPERTY(LinphoneEnums::CallStatus status MEMBER mStatus WRITE setStatus NOTIFY statusChanged)
Q_PROPERTY(bool isOutgoing MEMBER mIsOutgoing WRITE setIsOutgoing NOTIFY isOutgoingChanged)
std::shared_ptr<linphone::CallLog> getCallLog();
void setIsStart(const bool& isStart);
void setStatus(const LinphoneEnums::CallStatus& status);
void setIsOutgoing(const bool& isOutgoing);
bool update();
bool mIsStart;
LinphoneEnums::CallStatus mStatus;
bool mIsOutgoing;
signals:
void isStartChanged();
void statusChanged();
void isOutgoingChanged();
private:
std::shared_ptr<linphone::CallLog> mCallLog;
std::weak_ptr<ChatCallModel> mSelf; // Used to pass to functions that need a shared_ptr
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatCallModel>)
Q_DECLARE_METATYPE(ChatCallModel*)
#endif

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "ChatEvent.hpp"
// =============================================================================
ChatEvent::ChatEvent (ChatRoomModel::EntryType type){
mType = type;
}
ChatEvent::~ChatEvent(){
}
void ChatEvent::deleteEvent(){
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_EVENT_H
#define CHAT_EVENT_H
#include "components/chat-room/ChatRoomModel.hpp"
// =============================================================================
class ChatEvent{
public:
ChatEvent (ChatRoomModel::EntryType type);
virtual ~ChatEvent();
ChatRoomModel::EntryType mType;
QDateTime mTimestamp;
virtual void deleteEvent();
};
Q_DECLARE_METATYPE(ChatEvent*)
#endif

View file

@ -0,0 +1,534 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ChatMessageModel.hpp"
#include <QQmlApplicationEngine>
#include <algorithm>
#include <QDateTime>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QFileInfo>
#include <QMimeDatabase>
#include <QTimer>
#include <QUuid>
#include <QMessageBox>
#include <QUrlQuery>
#include <QImageReader>
#include "app/App.hpp"
#include "app/paths/Paths.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
#include "components/core/CoreManager.hpp"
#include "app/providers/ThumbnailProvider.hpp"
#include "components/notifier/Notifier.hpp"
#include "components/participant-imdn/ParticipantImdnStateListModel.hpp"
#include "components/participant-imdn/ParticipantImdnStateProxyModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "utils/QExifImageHeader.hpp"
#include "utils/Utils.hpp"
// =============================================================================
namespace {
constexpr int ThumbnailImageFileWidth = 100;
constexpr int ThumbnailImageFileHeight = 100;
// In Bytes.
constexpr qint64 FileSizeLimit = 524288000;
}
/*
std::shared_ptr<ChatMessageModel::ChatMessageListener::ChatMessageListener> ChatMessageModel::ChatMessageListener::create(ChatMessageModel * model, std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent){// Call it instead constructor
auto listener = std::shared_ptr<ChatMessageModel::ChatMessageListener::ChatMessageListener>(new ChatMessageModel::ChatMessageListener::ChatMessageListener(model,chatMessage, parent), [model](ChatMessageModel::ChatMessageListener::ChatMessageListener * listener){
chatMessage->removeListener(model->getHandler());
});
chatMessage->addListener(listener);
return model;
}
ChatMessageModel::ChatMessageListener::ChatMessageListener(ChatMessageModel * model, std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent){
connect(this, &ChatMessageModel::ChatMessageListener::onFileTransferSend, model, ChatMessageModel::onFileTransferSend);
connect(this, &ChatMessageModel::ChatMessageListener::onFileTransferProgressIndication, model, ChatMessageModel::onFileTransferProgressIndication);
connect(this, &ChatMessageModel::ChatMessageListener::onMsgStateChanged, model, ChatMessageModel::onMsgStateChanged);
}
ChatMessageModel::ChatMessageListener::~ChatMessageListener(){
}
*/
// Warning : isFileTransfer/isFile/getpath cannot be used for Content that comes from linphone::ChatMessage::getContents(). That lead to a crash.
// in SDK there is this note : return c->isFile(); // TODO FIXME this doesn't work when Content is from linphone_chat_message_get_contents() list
ContentModel::ContentModel(ChatMessageModel* chatModel){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mChatMessageModel = chatModel;
mWasDownloaded = false;
mFileOffset = 0;
}
ContentModel::ContentModel(std::shared_ptr<linphone::Content> content, ChatMessageModel* chatModel){
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mChatMessageModel = chatModel;
mWasDownloaded = false;
mFileOffset = 0;
setContent(content);
}
std::shared_ptr<linphone::Content> ContentModel::getContent()const{
return mContent;
}
quint64 ContentModel::getFileSize() const{
auto s = mContent->getFileSize();
return (quint64)s;
}
QString ContentModel::getName() const{
return QString::fromStdString(mContent->getName());
}
QString ContentModel::getThumbnail() const{
return mThumbnail;
}
void ContentModel::setFileOffset(quint64 fileOffset){
if( mFileOffset != fileOffset) {
mFileOffset = fileOffset;
emit fileOffsetChanged();
}
}
void ContentModel::setThumbnail(const QString& data){
if( mThumbnail != data) {
mThumbnail = data;
emit thumbnailChanged();
}
}
void ContentModel::setWasDownloaded(bool wasDownloaded){
if( mWasDownloaded != wasDownloaded) {
mWasDownloaded = wasDownloaded;
emit wasDownloadedChanged();
}
}
void ContentModel::setContent(std::shared_ptr<linphone::Content> content){
mContent = content;
auto chatMessageFileContentModel = mChatMessageModel->getFileContentModel();
if(chatMessageFileContentModel && chatMessageFileContentModel->getContent() == content){
QString path = Utils::coreStringToAppString(mContent->getFilePath());
if (!path.isEmpty() && (mChatMessageModel->isOutgoing() ||
mChatMessageModel->getState() == LinphoneEnums::ChatMessageStateDisplayed))
createThumbnail();
}
}
// Create a thumbnail from the first content that have a file and store it in Appdata
void ContentModel::createThumbnail () {
//if (!getChatMessageModel()->getChatMessage()->getAppdata().empty())
// return;// Already exist : no need to create one
//std::list<std::shared_ptr<linphone::Content> > contents = message->getContents();
//if( contents.size() > 0)
//{
auto chatMessageFileContentModel = mChatMessageModel->getFileContentModel();
if( chatMessageFileContentModel && chatMessageFileContentModel->getContent() == mContent){
QString id;
auto a = chatMessageFileContentModel->getContent();
auto b = mChatMessageModel->getChatMessage()->getFileTransferInformation();
if( a == b)
qWarning() << "OK";
else
qWarning() << "NOOOOOOOOOO";
QString path = Utils::coreStringToAppString(b->getFilePath());
auto appdata = ChatMessageModel::AppDataManager(Utils::coreStringToAppString(mChatMessageModel->getChatMessage()->getAppdata()));
if(!appdata.mData.contains(path)
|| !QFileInfo(Utils::coreStringToAppString(Paths::getThumbnailsDirPath())+appdata.mData[path]).isFile()){
// File don't exist. Create the thumbnail
QImage image(path);
if( image.isNull()){// Try to determine format from headers
QImageReader reader(path);
reader.setDecideFormatFromContent(true);
QByteArray format = reader.format();
if(!format.isEmpty())
image = QImage(path, format);
}
if (!image.isNull()){
int rotation = 0;
QExifImageHeader exifImageHeader;
if (exifImageHeader.loadFromJpeg(path))
rotation = int(exifImageHeader.value(QExifImageHeader::ImageTag::Orientation).toShort());
QImage thumbnail = image.scaled(
ThumbnailImageFileWidth, ThumbnailImageFileHeight,
Qt::KeepAspectRatio, Qt::SmoothTransformation
);
if (rotation != 0) {
QTransform transform;
if (rotation == 3 || rotation == 4)
transform.rotate(180);
else if (rotation == 5 || rotation == 6)
transform.rotate(90);
else if (rotation == 7 || rotation == 8)
transform.rotate(-90);
thumbnail = thumbnail.transformed(transform);
if (rotation == 2 || rotation == 4 || rotation == 5 || rotation == 7)
thumbnail = thumbnail.mirrored(true, false);
}
QString uuid = QUuid::createUuid().toString();
id = QStringLiteral("%1.jpg").arg(uuid.mid(1, uuid.length() - 2));
if (!thumbnail.save(Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + id , "jpg", 100)) {
qWarning() << QStringLiteral("Unable to create thumbnail of: `%1`.").arg(path);
}else{
appdata.mData[path] = id;
mChatMessageModel->getChatMessage()->setAppdata(Utils::appStringToCoreString(appdata.toString()));
}
}
}
if( path != ""){
setWasDownloaded( !path.isEmpty() && QFileInfo(path).isFile());
if(appdata.mData.contains(path))
setThumbnail(QStringLiteral("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(appdata.mData[path]));
}
}
//message->setAppdata(Utils::appStringToCoreString(id+':'+path));
//}
}
void ContentModel::downloadFile(){
switch (mChatMessageModel->getState()) {
case LinphoneEnums::ChatMessageStateDelivered:
case LinphoneEnums::ChatMessageStateDeliveredToUser:
case LinphoneEnums::ChatMessageStateDisplayed:
case LinphoneEnums::ChatMessageStateFileTransferDone:
break;
default:
qWarning() << QStringLiteral("Unable to download file of entry %1. It was not uploaded.").arg(mChatMessageModel->getState());
return;
}
bool soFarSoGood;
QString filename = getName();//mFileTransfertContent->getName();
const QString safeFilePath = Utils::getSafeFilePath(
QStringLiteral("%1%2")
.arg(CoreManager::getInstance()->getSettingsModel()->getDownloadFolder())
.arg(filename),
&soFarSoGood
);
if (!soFarSoGood) {
qWarning() << QStringLiteral("Unable to create safe file path for: %1.").arg(filename);
return;
}
mContent->setFilePath(Utils::appStringToCoreString(safeFilePath));
//mChatMessage->getContents().front()->setFilePath(Utils::appStringToCoreString(safeFilePath));
if( !mContent->isFileTransfer()){
QMessageBox::warning(nullptr, "Download File", "This file was already downloaded and is no more on the server. Your peer have to resend it if you want to get it");
}else
{
if (!mChatMessageModel->getChatMessage()->downloadContent(mContent))
qWarning() << QStringLiteral("Unable to download file of entry %1.").arg(filename);
}
}
void ContentModel::openFile (bool showDirectory) {
if (!mWasDownloaded && !mChatMessageModel->isOutgoing()) {
downloadFile();
}else{
QFileInfo info( Utils::coreStringToAppString(mContent->getFilePath()));
QDesktopServices::openUrl(
QUrl(QStringLiteral("file:///%1").arg(showDirectory ? info.absolutePath() : info.absoluteFilePath()))
);
}
}
// =============================================================================
ChatMessageListener::ChatMessageListener(ChatMessageModel * model, QObject* parent) : QObject(parent){
connect(this, &ChatMessageListener::fileTransferRecv, model, &ChatMessageModel::onFileTransferRecv);
connect(this, &ChatMessageListener::fileTransferSendChunk, model, &ChatMessageModel::onFileTransferSendChunk);
connect(this, &ChatMessageListener::fileTransferSend, model, &ChatMessageModel::onFileTransferSend);
connect(this, &ChatMessageListener::fileTransferProgressIndication, model, &ChatMessageModel::onFileTransferProgressIndication);
connect(this, &ChatMessageListener::msgStateChanged, model, &ChatMessageModel::onMsgStateChanged);
connect(this, &ChatMessageListener::participantImdnStateChanged, model, &ChatMessageModel::onParticipantImdnStateChanged);
connect(this, &ChatMessageListener::ephemeralMessageTimerStarted, model, &ChatMessageModel::onEphemeralMessageTimerStarted);
connect(this, &ChatMessageListener::ephemeralMessageDeleted, model, &ChatMessageModel::onEphemeralMessageDeleted);
connect(this, &ChatMessageListener::participantImdnStateChanged, model->getParticipantImdnStates().get(), &ParticipantImdnStateListModel::onParticipantImdnStateChanged);
}
void ChatMessageListener::onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer){
emit fileTransferRecv(message, content, buffer);
}
void ChatMessageListener::onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer){
emit fileTransferSendChunk(message, content, offset, size, buffer);
}
std::shared_ptr<linphone::Buffer> ChatMessageListener::onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size) {
emit fileTransferSend(message, content, offset, size);
return nullptr;
}
void ChatMessageListener::onFileTransferProgressIndication (const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t i){
emit fileTransferProgressIndication(message, content, offset, i);
}
void ChatMessageListener::onMsgStateChanged (const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state){
emit msgStateChanged(message, state);
}
void ChatMessageListener::onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state){
emit participantImdnStateChanged(message, state);
}
void ChatMessageListener::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> & message){
emit ephemeralMessageTimerStarted(message);
}
void ChatMessageListener::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> & message){
emit ephemeralMessageDeleted(message);
}
// =============================================================================
ChatMessageModel::AppDataManager::AppDataManager(const QString& appdata){
if(!appdata.isEmpty()){
for(QString pair : appdata.split(';')){
QStringList fields = pair.split(':');
mData[fields[1]] = fields[0];
}
}
}
QString ChatMessageModel::AppDataManager::toString(){
QStringList pairs;
for(QMap<QString,QString>::iterator it = mData.begin() ; it != mData.end() ; ++it){
pairs << it.value() + ":" + it.key();
}
return pairs.join(';');
}
ChatMessageModel::ChatMessageModel ( std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent) : QObject(parent), ChatEvent(ChatRoomModel::EntryType::MessageEntry) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it
mParticipantImdnStateListModel = std::make_shared<ParticipantImdnStateListModel>(chatMessage);
mChatMessageListener = std::make_shared<ChatMessageListener>(this, parent);
mChatMessage = chatMessage;
mWasDownloaded = false;
mChatMessage->addListener(mChatMessageListener);
mTimestamp = QDateTime::fromMSecsSinceEpoch(chatMessage->getTime() * 1000);
connect(this, &ChatMessageModel::remove, dynamic_cast<ChatRoomModel*>(parent), &ChatRoomModel::removeEntry);
std::list<std::shared_ptr<linphone::Content>> contents = chatMessage->getContents();
QString txt;
for(auto content : contents){
if(content->isText())
txt += QString::fromStdString(content->getUtf8Text());
}
mContent = txt;
//mIsOutgoing = chatMessage->isOutgoing() || chatMessage->getState() == linphone::ChatMessage::State::Idle;
// Old workaround.
// It can exist messages with a not delivered status. It's a linphone core bug.
/*
linphone::ChatMessage::State state = chatMessage->getState();
if (state == linphone::ChatMessage::State::InProgress)
dest["status"] = ChatRoomModel::MessageStatusNotDelivered;
else
dest["status"] = static_cast<ChatRoomModel::MessageStatus>(chatMessage->getState());
*/
auto content = chatMessage->getFileTransferInformation();
if (content) {
mFileTransfertContent = std::make_shared<ContentModel>(this);
mFileTransfertContent->setContent(content);
}
for(auto content : chatMessage->getContents()){
mContents << std::make_shared<ContentModel>(content, this);
}
}
ChatMessageModel::~ChatMessageModel(){
mChatMessage->removeListener(mChatMessageListener);
}
std::shared_ptr<ChatMessageModel> ChatMessageModel::create(std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent){
auto model = std::make_shared<ChatMessageModel>(chatMessage, parent);
return model;
}
std::shared_ptr<linphone::ChatMessage> ChatMessageModel::getChatMessage(){
return mChatMessage;
}
std::shared_ptr<ContentModel> ChatMessageModel::getContentModel(std::shared_ptr<linphone::Content> content){
if(content == mFileTransfertContent->getContent())
return mFileTransfertContent;
for(auto c : mContents)
if(c->getContent() == content)
return c;
return nullptr;
}
ContentModel * ChatMessageModel::getContent(int i){
return mContents[i].get();
}
//-----------------------------------------------------------------------------------------------------------------------
QString ChatMessageModel::getFromDisplayName() const{
return Utils::getDisplayName(mChatMessage->getFromAddress());
}
QString ChatMessageModel::getToDisplayName() const{
return Utils::getDisplayName(mChatMessage->getToAddress());
}
ContactModel * ChatMessageModel::getContactModel() const{
return CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(Utils::coreStringToAppString(mChatMessage->getFromAddress()->asString()));
}
bool ChatMessageModel::isEphemeral() const{
return mChatMessage->isEphemeral();
}
qint64 ChatMessageModel::getEphemeralExpireTime() const{
time_t t = mChatMessage->getEphemeralExpireTime();
return t >0 ? t - QDateTime::currentSecsSinceEpoch() : 0;
//return QDateTime::fromMSecsSinceEpoch(mChatMessage->getEphemeralExpireTime() * 1000)
}
LinphoneEnums::ChatMessageState ChatMessageModel::getState() const{
return LinphoneEnums::fromLinphone(mChatMessage->getState());
}
bool ChatMessageModel::isOutgoing() const{
return mChatMessage->isOutgoing();
}
ContentModel * ChatMessageModel::getFileContentModel() const{
return mFileTransfertContent.get();
}
QList<ContentModel*> ChatMessageModel::getContents() const{
QList<ContentModel*> models;
for(auto content : mContents)
models << content.get();
return models;
}
ParticipantImdnStateProxyModel * ChatMessageModel::getProxyImdnStates(){
ParticipantImdnStateProxyModel * proxy = new ParticipantImdnStateProxyModel();
proxy->setChatMessageModel(this);
return proxy;
}
std::shared_ptr<ParticipantImdnStateListModel> ChatMessageModel::getParticipantImdnStates() const{
return mParticipantImdnStateListModel;
}
//-----------------------------------------------------------------------------------------------------------------------
void ChatMessageModel::setWasDownloaded(bool wasDownloaded){
if( mWasDownloaded != wasDownloaded) {
mWasDownloaded = wasDownloaded;
emit wasDownloadedChanged();
}
}
//-----------------------------------------------------------------------------------------------------------------------
void ChatMessageModel::resendMessage (){
switch (getState()) {
case LinphoneEnums::ChatMessageStateFileTransferError:
case LinphoneEnums::ChatMessageStateNotDelivered: {
mChatMessage->send();
break;
}
default:
qWarning() << QStringLiteral("Unable to resend message: %1. Bad state.").arg(getState());
}
}
void ChatMessageModel::deleteEvent(){
if (mChatMessage && mChatMessage->getFileTransferInformation()) {// Remove thumbnail
mChatMessage->cancelFileTransfer();
QString appdata = Utils::coreStringToAppString(mChatMessage->getAppdata());
QStringList fields = appdata.split(':');
if(fields[0].size() > 0) {
QString thumbnailPath = Utils::coreStringToAppString(Paths::getThumbnailsDirPath()) + fields[0];
if (!QFile::remove(thumbnailPath))
qWarning() << QStringLiteral("Unable to remove `%1`.").arg(thumbnailPath);
}
mChatMessage->setAppdata("");// Remove completely Thumbnail from the message
}
mChatMessage->getChatRoom()->deleteMessage(mChatMessage);
}
void ChatMessageModel::updateFileTransferInformation(){
if( mFileTransfertContent && mFileTransfertContent->getContent() != getChatMessage()->getFileTransferInformation()){
mFileTransfertContent->setContent(getChatMessage()->getFileTransferInformation());
}
}
void ChatMessageModel::onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer){
}
void ChatMessageModel::onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer) {
}
std::shared_ptr<linphone::Buffer> ChatMessageModel::onFileTransferSend (const std::shared_ptr<linphone::ChatMessage> &,const std::shared_ptr<linphone::Content> &content,size_t,size_t) {
return nullptr;
}
void ChatMessageModel::onFileTransferProgressIndication (const std::shared_ptr<linphone::ChatMessage> &message,const std::shared_ptr<linphone::Content> &content,size_t offset,size_t) {
// content parameter is not in getContents() and getFileTransferInformation(). Question? What is it? Workaround : use the current file transfert.
// Note here : mFileTransfertContent->getContent() == getChatMessage()->getFileTransferInformation()
// Idea :
// auto model = getContentModel(content);
// if(model)
// model->setFileOffset(offset);
mFileTransfertContent->setFileOffset(offset);
}
void ChatMessageModel::onMsgStateChanged (const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state) {
updateFileTransferInformation();// On message state, file transfert information Content can be changed
// File message downloaded.
if (state == linphone::ChatMessage::State::FileTransferDone && !mChatMessage->isOutgoing()) {
if(mFileTransfertContent)
mFileTransfertContent->createThumbnail();
setWasDownloaded(true);
App::getInstance()->getNotifier()->notifyReceivedFileMessage(message);
}
emit stateChanged();
}
void ChatMessageModel::onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state){
}
void ChatMessageModel::onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> & message) {
emit ephemeralExpireTimeChanged();
}
void ChatMessageModel::onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> & message) {
//emit remove(mSelf.lock());
emit remove(this);
}
//-------------------------------------------------------------------------------------------------------

View file

@ -0,0 +1,220 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_MESSAGE_MODEL_H
#define CHAT_MESSAGE_MODEL_H
#include "utils/LinphoneEnums.hpp"
#include <QDateTime>
// =============================================================================
/*
class Thumbnail{
public:
Thumbnail();
QString mId;
QString mPath;
QString toString()const;
void fromString(const QString& );
static QString toString(const QVector<Thumbnail>& );
static QVector<Thumbnail> fromListString(const QString& );
};
*/
#include "components/chat-room/ChatRoomModel.hpp"
#include "ChatEvent.hpp"
#include "components/participant-imdn/ParticipantImdnStateListModel.hpp"
class ChatMessageModel;
class ParticipantImdnStateProxyModel;
class ParticipantImdnStateListModel;
class ContentModel : public QObject{
Q_OBJECT
public:
ContentModel(ChatMessageModel* chatModel);
ContentModel(std::shared_ptr<linphone::Content> content, ChatMessageModel* chatModel);
Q_PROPERTY(quint64 fileSize READ getFileSize NOTIFY fileSizeChanged)
Q_PROPERTY(QString name READ getName NOTIFY nameChanged)
Q_PROPERTY(quint64 fileOffset MEMBER mFileOffset WRITE setFileOffset NOTIFY fileOffsetChanged)
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;
QString getName() const;
QString getThumbnail() const;
void setFileOffset(quint64 fileOffset);
void setThumbnail(const QString& data);
void setWasDownloaded(bool wasDownloaded);
void setContent(std::shared_ptr<linphone::Content> content);
void createThumbnail ();
Q_INVOKABLE void downloadFile();
Q_INVOKABLE void openFile (bool showDirectory = false);
QString mThumbnail;
bool mWasDownloaded;
quint64 mFileOffset;
signals:
void fileSizeChanged();
void nameChanged();
void thumbnailChanged();
void fileOffsetChanged();
void wasDownloadedChanged();
private:
std::shared_ptr<linphone::Content> mContent;
ChatMessageModel* mChatMessageModel;
};
Q_DECLARE_METATYPE(std::shared_ptr<ContentModel>)
class ChatMessageListener : public QObject, public linphone::ChatMessageListener {
Q_OBJECT
public:
ChatMessageListener(ChatMessageModel * model, QObject * parent = nullptr);
virtual ~ChatMessageListener(){};
virtual void onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer) override;
virtual void onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer) override;
virtual std::shared_ptr<linphone::Buffer> onFileTransferSend(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size) override;
virtual void onFileTransferProgressIndication (const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &, size_t offset, size_t) override;
virtual void onMsgStateChanged (const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state) override;
virtual void onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state) override;
virtual void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> & message) override;
signals:
void fileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer);
void fileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer);
std::shared_ptr<linphone::Buffer> fileTransferSend (const std::shared_ptr<linphone::ChatMessage> &,const std::shared_ptr<linphone::Content> &,size_t,size_t);
void fileTransferProgressIndication (const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &, size_t offset, size_t);
void msgStateChanged (const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state);
void participantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state);
void ephemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> & message);
void ephemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> & message);
};
class ChatMessageModel : public QObject, public ChatEvent {
Q_OBJECT
public:
static std::shared_ptr<ChatMessageModel> create(std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent = nullptr);// Call it instead constructor
ChatMessageModel (std::shared_ptr<linphone::ChatMessage> chatMessage, QObject * parent = nullptr);
virtual ~ChatMessageModel();
class AppDataManager{// Used to manage appdata to store persistant data like created thumbnails
public:
AppDataManager(const QString&);
QMap<QString, QString> mData;// Path / ID
QString toString();
};
Q_PROPERTY(QString fromDisplayName READ getFromDisplayName CONSTANT)
Q_PROPERTY(QString toDisplayName READ getToDisplayName CONSTANT)
Q_PROPERTY(ContactModel * contactModel READ getContactModel CONSTANT)
Q_PROPERTY(bool isEphemeral READ isEphemeral NOTIFY isEphemeralChanged)
Q_PROPERTY(qint64 ephemeralExpireTime READ getEphemeralExpireTime NOTIFY ephemeralExpireTimeChanged)
Q_PROPERTY(LinphoneEnums::ChatMessageState state READ getState NOTIFY stateChanged)
Q_PROPERTY(bool isOutgoing READ isOutgoing NOTIFY isOutgoingChanged)
Q_PROPERTY(bool wasDownloaded MEMBER mWasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged)
Q_PROPERTY(ChatRoomModel::EntryType type MEMBER mType CONSTANT)
Q_PROPERTY(QDateTime timestamp MEMBER mTimestamp CONSTANT)
//Q_PROPERTY(QString thumbnail MEMBER mThumbnail NOTIFY thumbnailChanged)
Q_PROPERTY(QString content MEMBER mContent NOTIFY contentChanged)
Q_PROPERTY(ContentModel * fileContentModel READ getFileContentModel NOTIFY fileContentChanged)
//Q_PROPERTY(QList<ContentModel *> contents READ getContents CONSTANT)
std::shared_ptr<linphone::ChatMessage> getChatMessage();
std::shared_ptr<ContentModel> getContentModel(std::shared_ptr<linphone::Content> content);
Q_INVOKABLE ContentModel * getContent(int i);
//----------------------------------------------------------------------------
QString getFromDisplayName() const;
QString getToDisplayName() const;
ContactModel * getContactModel() const;
bool isEphemeral() const;
Q_INVOKABLE qint64 getEphemeralExpireTime() const;
LinphoneEnums::ChatMessageState getState() const;
bool isOutgoing() const;
ContentModel * getFileContentModel() const;
QList<ContentModel*> getContents() const;
Q_INVOKABLE ParticipantImdnStateProxyModel * getProxyImdnStates();
std::shared_ptr<ParticipantImdnStateListModel> getParticipantImdnStates() const;
//----------------------------------------------------------------------------
void setWasDownloaded(bool wasDownloaded);
//----------------------------------------------------------------------------
Q_INVOKABLE void resendMessage ();
virtual void deleteEvent();
void updateFileTransferInformation();
// Linphone callbacks
void onFileTransferRecv(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, const std::shared_ptr<const linphone::Buffer> & buffer) ;
void onFileTransferSendChunk(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<linphone::Content> & content, size_t offset, size_t size, const std::shared_ptr<linphone::Buffer> & buffer) ;
std::shared_ptr<linphone::Buffer> onFileTransferSend (const std::shared_ptr<linphone::ChatMessage> &,const std::shared_ptr<linphone::Content> &,size_t,size_t);
void onFileTransferProgressIndication (const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &, size_t offset, size_t);
void onMsgStateChanged (const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state);
void onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state);
void onEphemeralMessageTimerStarted(const std::shared_ptr<linphone::ChatMessage> & message);
void onEphemeralMessageDeleted(const std::shared_ptr<linphone::ChatMessage> & message);
//----------------------------------------------------------------------------
bool mWasDownloaded;
QString mContent;
QString mIsOutgoing;
//----------------------------------------------------------------------------
signals:
void isEphemeralChanged();
void ephemeralExpireTimeChanged();
void stateChanged();
void wasDownloadedChanged();
void contentChanged();
void isOutgoingChanged();
void fileContentChanged();
void remove(ChatMessageModel* model);
private:
QList<std::shared_ptr<ContentModel>> mContents;
std::shared_ptr<ContentModel> mFileTransfertContent;
std::shared_ptr<linphone::ChatMessage> mChatMessage;
std::shared_ptr<ParticipantImdnStateListModel> mParticipantImdnStateListModel;
std::shared_ptr<ChatMessageListener> mChatMessageListener;
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatMessageModel>)
Q_DECLARE_METATYPE(ChatMessageListener*)
#endif

View file

@ -0,0 +1,140 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "ChatNoticeModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "utils/Utils.hpp"
// =============================================================================
ChatNoticeModel::ChatNoticeModel ( std::shared_ptr<linphone::EventLog> eventLog, QObject * parent) : QObject(parent), ChatEvent(ChatRoomModel::EntryType::NoticeEntry) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mEventLog = eventLog;
mTimestamp = QDateTime::fromMSecsSinceEpoch(eventLog->getCreationTime() * 1000);
}
ChatNoticeModel::~ChatNoticeModel(){
}
std::shared_ptr<ChatNoticeModel> ChatNoticeModel::create(std::shared_ptr<linphone::EventLog> eventLog, QObject * parent){
auto model = std::make_shared<ChatNoticeModel>(eventLog, parent);
if(model && model->update()){
model->mSelf = model;
return model;
}else
return nullptr;
}
std::shared_ptr<linphone::EventLog> ChatNoticeModel::getEventLog(){
return mEventLog;
}
//---------------------------------------------------------------------------------------------
bool ChatNoticeModel::update(){
bool handledEvent = true;
auto participantAddress = mEventLog->getParticipantAddress();
switch(mEventLog->getType()){
case linphone::EventLog::Type::ConferenceCreated:
setName("");
setStatus(NoticeType::NoticeMessage);
//dest["message"] = "You have joined the group";
break;
case linphone::EventLog::Type::ConferenceTerminated:
setName("");
setStatus(NoticeType::NoticeMessage);
// dest["message"] = "You have left the group";
break;
case linphone::EventLog::Type::ConferenceParticipantAdded:
setName(Utils::getDisplayName(participantAddress));
setStatus(NoticeType::NoticeMessage);
//dest["message"] = "%1 has joined";
break;
case linphone::EventLog::Type::ConferenceParticipantRemoved:
setName(Utils::getDisplayName(participantAddress));
setStatus(NoticeType::NoticeMessage);
//dest["message"] = "%1 has left";
break;
case linphone::EventLog::Type::ConferenceSecurityEvent: {
if(mEventLog->getSecurityEventType() == linphone::EventLog::SecurityEventType::SecurityLevelDowngraded ){
auto faultyParticipant = mEventLog->getSecurityEventFaultyDeviceAddress();
if(faultyParticipant)
setName(Utils::getDisplayName(faultyParticipant));
else if(participantAddress)
setName(Utils::getDisplayName(participantAddress));
setStatus(NoticeType::NoticeError);
//dest["message"] = "Security level degraded by %1";
}else// No callback from SDK on upgraded security event yet
handledEvent = false;
break;
}
case linphone::EventLog::Type::ConferenceEphemeralMessageEnabled :{
int selectedTime = mEventLog->getEphemeralMessageLifetime();
if(selectedTime == 60)
setName( "1 minute" );
else if(selectedTime == 3600)
setName( "1 heure" );
else if(selectedTime == 86400)
setName( "1 jour" );
else if(selectedTime == 259200)
setName( "3 jours" );
else if(selectedTime == 604800)
setName( "1 semaine" );
setStatus(NoticeType::NoticeMessage);
break;
}
case linphone::EventLog::Type::ConferenceEphemeralMessageDisabled :{
setName("");
setStatus(NoticeType::NoticeMessage);
break;
}
default:{
handledEvent = false;
}
}
setEventLogType(LinphoneEnums::fromLinphone(mEventLog->getType()));
return handledEvent;
}
void ChatNoticeModel::setName(const QString& data){
if(data != mName) {
mName = data;
emit nameChanged();
}
}
void ChatNoticeModel::setStatus(NoticeType data){
if(data != mStatus) {
mStatus = data;
emit statusChanged();
}
}
void ChatNoticeModel::setEventLogType(const LinphoneEnums::EventLogType& data){
if(data != mEventLogType) {
mEventLogType = data;
emit eventLogTypeChanged();
}
}

View file

@ -0,0 +1,76 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_NOTICE_MODEL_H
#define CHAT_NOTICE_MODEL_H
#include "utils/LinphoneEnums.hpp"
#include "ChatEvent.hpp"
// =============================================================================
class ChatNoticeModel : public QObject, public ChatEvent {
Q_OBJECT
public:
enum NoticeType {
NoticeMessage,
NoticeError
};
Q_ENUM(NoticeType);
static std::shared_ptr<ChatNoticeModel> create(std::shared_ptr<linphone::EventLog> eventLog, QObject * parent = nullptr);// Call it instead constructor
ChatNoticeModel (std::shared_ptr<linphone::EventLog> eventLog, QObject * parent = nullptr);
virtual ~ChatNoticeModel();
Q_PROPERTY(ChatRoomModel::EntryType type MEMBER mType CONSTANT)
Q_PROPERTY(QDateTime timestamp MEMBER mTimestamp CONSTANT)
Q_PROPERTY(QString name MEMBER mName WRITE setName NOTIFY nameChanged)
Q_PROPERTY(NoticeType status MEMBER mStatus WRITE setStatus NOTIFY statusChanged)
Q_PROPERTY(LinphoneEnums::EventLogType eventLogType MEMBER mEventLogType WRITE setEventLogType NOTIFY eventLogTypeChanged)
std::shared_ptr<linphone::EventLog> getEventLog();
void setName(const QString& data);
void setStatus(NoticeType data);
void setEventLogType(const LinphoneEnums::EventLogType& data);
bool update(); // Update data from eventLog
QString mName;
NoticeType mStatus;
LinphoneEnums::EventLogType mEventLogType;
signals:
void nameChanged();
void statusChanged();
void eventLogTypeChanged();
private:
std::shared_ptr<linphone::EventLog> mEventLog;
std::weak_ptr<ChatNoticeModel> mSelf; // Used to pass to functions that need a shared_ptr
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatNoticeModel>)
Q_DECLARE_METATYPE(ChatNoticeModel*)
#endif

File diff suppressed because it is too large Load diff

View file

@ -32,6 +32,8 @@
class CoreHandlers;
class ParticipantModel;
class ParticipantListModel;
class ChatEvent;
class ContactModel;
class ChatRoomModel : public QAbstractListModel, public linphone::ChatRoomListener {
class MessageHandlers;
@ -52,37 +54,6 @@ public:
};
Q_ENUM(EntryType);
enum NoticeType {
NoticeMessage,
NoticeError
};
Q_ENUM(NoticeType);
enum CallStatus {
CallStatusDeclined = int(linphone::Call::Status::Declined),
CallStatusMissed = int(linphone::Call::Status::Missed),
CallStatusSuccess = int(linphone::Call::Status::Success),
CallStatusAborted = int(linphone::Call::Status::Aborted),
CallStatusEarlyAborted = int(linphone::Call::Status::EarlyAborted),
CallStatusAcceptedElsewhere = int(linphone::Call::Status::AcceptedElsewhere),
CallStatusDeclinedElsewhere = int(linphone::Call::Status::DeclinedElsewhere)
};
Q_ENUM(CallStatus);
enum MessageStatus {
MessageStatusDelivered = int(linphone::ChatMessage::State::Delivered),
MessageStatusDeliveredToUser = int(linphone::ChatMessage::State::DeliveredToUser),
MessageStatusDisplayed = int(linphone::ChatMessage::State::Displayed),
MessageStatusFileTransferDone = int(linphone::ChatMessage::State::FileTransferDone),
MessageStatusFileTransferError = int(linphone::ChatMessage::State::FileTransferError),
MessageStatusFileTransferInProgress = int(linphone::ChatMessage::State::FileTransferInProgress),
MessageStatusIdle = int(linphone::ChatMessage::State::Idle),
MessageStatusInProgress = int(linphone::ChatMessage::State::InProgress),
MessageStatusNotDelivered = int(linphone::ChatMessage::State::NotDelivered)
};
Q_ENUM(MessageStatus);
//Q_PROPERTY(QString participants READ getParticipants NOTIFY participantsChanged);
//Q_PROPERTY(ParticipantProxyModel participants READ getParticipants NOTIFY participantsChanged);
@ -95,11 +66,10 @@ public:
Q_PROPERTY(bool groupEnabled READ isGroupEnabled NOTIFY groupEnabledChanged)
Q_PROPERTY(bool haveEncryption READ haveEncryption CONSTANT)
Q_PROPERTY(bool isComposing MEMBER mIsRemoteComposing NOTIFY isRemoteComposingChanged)
//Q_PROPERTY(bool isComposing MEMBER mIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
Q_PROPERTY(bool hasBeenLeft READ hasBeenLeft NOTIFY hasBeenLeftChanged)
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString sipAddressUriOnly READ getPeerAddress NOTIFY fullPeerAddressChanged)
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
@ -108,11 +78,15 @@ public:
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
Q_PROPERTY(long ephemeralLifetime READ getEphemeralLifetime WRITE setEphemeralLifetime NOTIFY ephemeralLifetimeChanged)
Q_PROPERTY(bool ephemeralEnabled READ getEphemeralEnabled WRITE setEphemeralEnabled NOTIFY ephemeralEnabledChanged)
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE setEphemeralEnabled NOTIFY ephemeralEnabledChanged)
Q_PROPERTY(bool canBeEphemeral READ canBeEphemeral NOTIFY canBeEphemeralChanged)
Q_PROPERTY(ParticipantListModel* participants READ getParticipants CONSTANT)
//ChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
static std::shared_ptr<ChatRoomModel> create(std::shared_ptr<linphone::ChatRoom> chatRoom);
ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom);
~ChatRoomModel ();
@ -123,6 +97,9 @@ public:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
void removeAllEntries ();
//---- Getters
Q_INVOKABLE QString getPeerAddress () const;
Q_INVOKABLE QString getLocalAddress () const;
@ -136,62 +113,43 @@ public:
int getPresenceStatus() const;
int getState() const;
bool hasBeenLeft() const;
bool getEphemeralEnabled() const;
bool isEphemeralEnabled() const;
long getEphemeralLifetime() const;
bool canBeEphemeral();
Q_INVOKABLE bool haveEncryption() const;
Q_INVOKABLE bool isSecure() const;
int getSecurityLevel() const;
bool isGroupEnabled() const;
bool getIsRemoteComposing () const;
ParticipantListModel* getParticipants() const;
std::shared_ptr<linphone::ChatRoom> getChatRoom();
QList<QString> getComposers();
//---- Setters
void setLastUpdateTime(const QDateTime& lastUpdateDate);
void setUnreadMessagesCount(const int& count);
void setMissedCallsCount(const int& count);
void setEphemeralEnabled(bool enabled);
void setEphemeralLifetime(long lifetime);
// Tools
void deleteChatRoom();
Q_INVOKABLE void leaveChatRoom ();
Q_INVOKABLE bool haveEncryption() const;
Q_INVOKABLE bool isSecure() const;
int getSecurityLevel() const;
bool isGroupEnabled() const;
bool getIsRemoteComposing () const;
//Q_INVOKABLE QList<ParticipantModel*> getParticipants()const
//Q_INVOKABLE QString getParticipants()const;
//QList<std::shared_ptr<ParticipantModel> > getParticipants();
//Q_INVOKABLE std::shared_ptr<ParticipantListModel> getParticipants();
Q_PROPERTY(ParticipantListModel* participants READ getParticipants CONSTANT)
ParticipantListModel* getParticipants() const;
void removeEntry (int id);
void removeAllEntries ();
void sendMessage (const QString &message);
void resendMessage (int id);
Q_INVOKABLE void updateParticipants(const QVariantList& participants);
void sendMessage (const QString &message);
void sendFileMessage (const QString &path);
void downloadFile (int id);
void openFile (int id, bool showDirectory = false);
void openFileDirectory (int id) {
openFile(id, true);
}
bool fileWasDownloaded (int id);
void compose ();
void resetMessageCount ();
Q_INVOKABLE void initEntries();
std::shared_ptr<linphone::ChatRoom> getChatRoom();
QDateTime mLastUpdateTime;
int mUnreadMessagesCount = 0;
int mMissedCallsCount = 0;
bool mIsInitialized = false;
bool mDeleteChatRoom = false; // Use as workaround because of core->deleteChatRoom() that call destructor without takking account of count ref : call it in ChatRoomModel destructor
//-------------------- CHAT ROOM HANDLER
@ -222,12 +180,14 @@ public:
virtual void onParticipantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress) override;
virtual void onChatMessageShouldBeStored(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message) override;
virtual void onChatMessageParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state) override;
public slots:
void removeEntry(ChatEvent* entry);
signals:
bool isRemoteComposingChanged (bool status);
bool isRemoteComposingChanged ();
void allEntriesRemoved ();
void allEntriesRemoved (std::shared_ptr<ChatRoomModel> model);
void lastEntryRemoved ();
void messageSent (const std::shared_ptr<linphone::ChatMessage> &message);
@ -240,7 +200,7 @@ signals:
void fullPeerAddressChanged();
void participantsChanged();
void subjectChanged(QString subject);
void usernameChanged(QString username);
void usernameChanged();
void avatarChanged(QString avatar);
void presenceStatusChanged();
void lastUpdateTimeChanged();
@ -253,7 +213,8 @@ signals:
void hasBeenLeftChanged();
void ephemeralEnabledChanged();
void ephemeralLifetimeChanged();
void canBeEphemeralChanged();
void chatRoomDeleted();// Must be connected with DirectConnection mode
// Chat Room listener callbacks
@ -265,17 +226,10 @@ signals:
void participantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void participantRegistrationSubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress);
void participantRegistrationUnsubscriptionRequested(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::Address> & participantAddress);
void conferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void conferenceLeft(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
private:
typedef QPair<QVariantMap, std::shared_ptr<void>> ChatEntryData;
//void setSipAddresses (const QString &peerAddress, const QString &localAddress, const bool& isSecure);
const ChatEntryData getFileMessageEntry (int id);
void removeEntry (ChatEntryData &entry);
void insertCall (const std::shared_ptr<linphone::CallLog> &callLog);
void insertMessageAtEnd (const std::shared_ptr<linphone::ChatMessage> &message);
void insertNotice (const std::shared_ptr<linphone::EventLog> &enventLog);
@ -286,18 +240,17 @@ private:
//void handleIsComposingChanged (const std::shared_ptr<linphone::ChatRoom> &chatRoom);
//void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
bool mIsRemoteComposing = false;
mutable QList<ChatEntryData> mEntries;
//QList<ParticipantModel*> mParticipants;
//bool mIsRemoteComposing = false;
QList<std::shared_ptr<ChatEvent> > mEntries;
std::shared_ptr<ParticipantListModel> mParticipantListModel;
std::shared_ptr<CoreHandlers> mCoreHandlers;
std::shared_ptr<MessageHandlers> mMessageHandlers;
QMap<std::shared_ptr<const linphone::Address>, QString> mComposers; // Store all addresses that are composing with its username
std::shared_ptr<linphone::ChatRoom> mChatRoom;
std::weak_ptr<ChatRoomModel> mSelf;
};
Q_DECLARE_METATYPE(std::shared_ptr<ChatRoomModel>);
Q_DECLARE_METATYPE(std::shared_ptr<ChatRoomModel>)
#endif // CHAT_ROOM_MODEL_H_

View file

@ -24,6 +24,11 @@
#include "components/core/CoreManager.hpp"
#include "ChatRoomProxyModel.hpp"
#include "components/chat-events/ChatEvent.hpp"
#include "components/chat-events/ChatMessageModel.hpp"
#include "components/chat-events/ChatNoticeModel.hpp"
#include "components/chat-events/ChatCallModel.hpp"
#include "components/timeline/TimelineListModel.hpp"
// =============================================================================
@ -36,11 +41,11 @@ class ChatRoomProxyModel::ChatRoomModelFilter : public QSortFilterProxyModel {
public:
ChatRoomModelFilter (QObject *parent) : QSortFilterProxyModel(parent) {}
ChatRoomModel::EntryType getEntryTypeFilter () {
int getEntryTypeFilter () {
return mEntryTypeFilter;
}
void setEntryTypeFilter (ChatRoomModel::EntryType type) {
void setEntryTypeFilter (int type) {
mEntryTypeFilter = type;
invalidate();
}
@ -53,11 +58,11 @@ protected:
QModelIndex index = sourceModel()->index(sourceRow, 0, QModelIndex());
const QVariantMap data = index.data().toMap();
return data["type"].toInt() == mEntryTypeFilter;
return (data["type"].toInt() & mEntryTypeFilter) > 0;
}
private:
ChatRoomModel::EntryType mEntryTypeFilter = ChatRoomModel::EntryType::GenericEntry;
int mEntryTypeFilter = ChatRoomModel::EntryType::GenericEntry;
};
// =============================================================================
@ -104,16 +109,13 @@ ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel
); \
}
CREATE_PARENT_MODEL_FUNCTION(removeAllEntries);
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(sendFileMessage, const QString &)
CREATE_PARENT_MODEL_FUNCTION_WITH_PARAM(sendMessage, const QString &)
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeRow)
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(downloadFile);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(openFile);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(openFileDirectory);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(removeEntry);
CREATE_PARENT_MODEL_FUNCTION_WITH_ID(resendMessage);
#undef GET_CHAT_MODEL
#undef CREATE_PARENT_MODEL_FUNCTION
@ -147,7 +149,7 @@ void ChatRoomProxyModel::loadMoreEntries () {
}
}
void ChatRoomProxyModel::setEntryTypeFilter (ChatRoomModel::EntryType type) {
void ChatRoomProxyModel::setEntryTypeFilter (int type) {
ChatRoomModelFilter *ChatRoomModelFilter = static_cast<ChatRoomProxyModel::ChatRoomModelFilter *>(sourceModel());
if (ChatRoomModelFilter->getEntryTypeFilter() != type) {
@ -162,10 +164,21 @@ bool ChatRoomProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &) c
return sourceModel()->rowCount() - sourceRow <= mMaxDisplayedEntries;
}
bool ChatRoomProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const QVariantMap l = sourceModel()->data(left).value<QVariantMap>();
const QVariantMap r = sourceModel()->data(right).value<QVariantMap>();
auto l = sourceModel()->data(left);
auto r = sourceModel()->data(right);
return l["timestamp"].toDateTime() < r["timestamp"].toDateTime();
ChatEvent * a = l.value<ChatMessageModel*>();// l.value<ChatEvent*>() cannot be used
if(!a)
a = l.value<ChatNoticeModel*>();
if(!a)
a = l.value<ChatCallModel*>();
ChatEvent * b = r.value<ChatMessageModel*>();
if(!b)
b = r.value<ChatNoticeModel*>();
if(!b)
b = r.value<ChatCallModel*>();
return a->mTimestamp < b->mTimestamp;
}
// -----------------------------------------------------------------------------
@ -218,8 +231,18 @@ void ChatRoomProxyModel::setIsSecure (const int &secure) {
emit isSecureChanged(mIsSecure);
}
*/
/*
bool ChatRoomProxyModel::getIsRemoteComposing () const {
return mChatRoomModel ? mChatRoomModel->getIsRemoteComposing() : false;
}*/
QList<QString> ChatRoomProxyModel::getComposers() const{
return (mChatRoomModel?mChatRoomModel->getComposers():QList<QString>());
}
QString ChatRoomProxyModel::getDisplayNameComposers()const{
return getComposers().join(", ");
}
QString ChatRoomProxyModel::getCachedText() const{
@ -228,7 +251,7 @@ QString ChatRoomProxyModel::getCachedText() const{
// -----------------------------------------------------------------------------
void ChatRoomProxyModel::reload () {
void ChatRoomProxyModel::reload (ChatRoomModel *chatRoomModel) {
mMaxDisplayedEntries = EntriesChunkSize;
if (mChatRoomModel) {
@ -240,8 +263,10 @@ void ChatRoomProxyModel::reload () {
//mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mPeerAddress, mLocalAddress, mIsSecure);
//if(mChatRoom)
mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(mChatRoom);
mChatRoomModel = CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoomModel);
if(!mChatRoomModel)
qWarning() << "mChatRoomModel is null!";
if (mChatRoomModel) {
@ -252,6 +277,7 @@ void ChatRoomProxyModel::reload () {
}
static_cast<ChatRoomModelFilter *>(sourceModel())->setSourceModel(mChatRoomModel.get());
invalidate();
}
void ChatRoomProxyModel::resetMessageCount(){
if( mChatRoomModel){
@ -263,13 +289,11 @@ ChatRoomModel *ChatRoomProxyModel::getChatRoomModel () const{
return mChatRoomModel.get();
}
void ChatRoomProxyModel::setChatRoomModel (ChatRoomModel *chatRoomModel){
if(chatRoomModel)
mChatRoom = chatRoomModel->getChatRoom();
else
mChatRoom = nullptr;
reload();
reload(chatRoomModel);
emit chatRoomModelChanged();
emit isRemoteComposingChanged();
}
// -----------------------------------------------------------------------------
@ -290,8 +314,8 @@ void ChatRoomProxyModel::handleIsActiveChanged (QWindow *window) {
}
}
void ChatRoomProxyModel::handleIsRemoteComposingChanged (bool status) {
emit isRemoteComposingChanged(status);
void ChatRoomProxyModel::handleIsRemoteComposingChanged () {
emit isRemoteComposingChanged();
}
void ChatRoomProxyModel::handleMessageReceived (const shared_ptr<linphone::ChatMessage> &) {

View file

@ -41,28 +41,26 @@ class ChatRoomProxyModel : public QSortFilterProxyModel {
//Q_PROPERTY(int isSecure READ isSecure WRITE setIsSecure NOTIFY isSecureChanged)
Q_PROPERTY(ChatRoomModel *chatRoomModel READ getChatRoomModel WRITE setChatRoomModel NOTIFY chatRoomModelChanged)
//Q_PROPERTY(bool isSecure MEMBER mIsSecure NOTIFY isSecureChanged)
Q_PROPERTY(bool isRemoteComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged)
//Q_PROPERTY(bool isRemoteComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged)
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
//Q_PROPERTY(bool isSecure READ getIsSecure NOTIFY isSecureChanged)
Q_PROPERTY(QString cachedText READ getCachedText)
public:
ChatRoomProxyModel (QObject *parent = Q_NULLPTR);
Q_INVOKABLE QString getDisplayNameComposers()const;
Q_INVOKABLE void loadMoreEntries ();
Q_INVOKABLE void setEntryTypeFilter (ChatRoomModel::EntryType type);
Q_INVOKABLE void removeEntry (int id);
Q_INVOKABLE void setEntryTypeFilter (int type);
Q_INVOKABLE void removeAllEntries ();
Q_INVOKABLE void removeRow (int index);
Q_INVOKABLE void sendMessage (const QString &message);
Q_INVOKABLE void resendMessage (int id);
Q_INVOKABLE void sendFileMessage (const QString &path);
Q_INVOKABLE void downloadFile (int id);
Q_INVOKABLE void openFile (int id);
Q_INVOKABLE void openFileDirectory (int id);
Q_INVOKABLE void compose (const QString& text);
Q_INVOKABLE void resetMessageCount();
@ -72,14 +70,14 @@ signals:
void localAddressChanged (const QString &localAddress);
void fullPeerAddressChanged (const QString &fullPeerAddress);
void fullLocalAddressChanged (const QString &fullLocalAddress);
bool isRemoteComposingChanged (bool status);
bool isRemoteComposingChanged ();
//bool isSecureChanged(bool secure);
void chatRoomModelChanged();
void moreEntriesLoaded (int n);
void entryTypeFilterChanged (ChatRoomModel::EntryType type);
void entryTypeFilterChanged (int type);
protected:
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
@ -104,15 +102,15 @@ private:
ChatRoomModel *getChatRoomModel() const;
void setChatRoomModel (ChatRoomModel *chatRoomModel);
bool getIsRemoteComposing () const;
QList<QString> getComposers () const;
QString getCachedText() const;
void reload ();
void reload (ChatRoomModel *chatRoomModel);
void handleIsActiveChanged (QWindow *window);
void handleIsRemoteComposingChanged (bool status);
void handleIsRemoteComposingChanged ();
void handleMessageReceived (const std::shared_ptr<linphone::ChatMessage> &message);
void handleMessageSent (const std::shared_ptr<linphone::ChatMessage> &message);
@ -124,7 +122,7 @@ private:
QString mFullLocalAddress;
//int mIsSecure;
static QString gCachedText;
std::shared_ptr<linphone::ChatRoom> mChatRoom;
//std::shared_ptr<linphone::ChatRoom> mChatRoom;
std::shared_ptr<ChatRoomModel> mChatRoomModel;

View file

@ -1,4 +1,4 @@
/*
/*
* Copyright (c) 2010-2020 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
@ -21,6 +21,7 @@
#include <QtDebug>
#include "components/core/CoreManager.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
#include "utils/Utils.hpp"
@ -110,6 +111,15 @@ bool ConferenceHelperModel::ConferenceAddModel::addToConference (const QString &
return true;
}
void ConferenceHelperModel::ConferenceAddModel::addParticipants(ChatRoomModel * model){
auto participants = model->getChatRoom()->getParticipants();
for( auto participant : participants){
if(participant){
addToConference(Utils::coreStringToAppString(participant->getAddress()->asString()));
}
}
}
bool ConferenceHelperModel::ConferenceAddModel::removeFromConference (const QString &sipAddress) {
auto it = mSipAddresses.find(sipAddress);
if (it == mSipAddresses.end())

View file

@ -30,7 +30,7 @@
namespace linphone {
class Address;
}
class ChatRoomModel;
class ConferenceHelperModel::ConferenceAddModel : public QAbstractListModel {
Q_OBJECT;
@ -46,6 +46,7 @@ public:
Q_INVOKABLE bool addToConference (const QString &sipAddress);
Q_INVOKABLE bool removeFromConference (const QString &sipAddress);
Q_INVOKABLE void addParticipants(ChatRoomModel * model);
Q_INVOKABLE void update ();

View file

@ -28,6 +28,7 @@
#include "ConferenceAddModel.hpp"
#include "ConferenceHelperModel.hpp"
#include "components/contact/ContactModel.hpp"
// =============================================================================
@ -66,8 +67,9 @@ void ConferenceHelperModel::setFilter (const QString &pattern) {
bool ConferenceHelperModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const QVariantMap data = index.data().toMap();
const ContactModel * contactModel = data["contactModel"].value<ContactModel*>();
return !mConferenceAddModel->contains(data["sipAddress"].toString());
return contactModel != nullptr && !mConferenceAddModel->contains(data["sipAddress"].toString());
}
// -----------------------------------------------------------------------------

View file

@ -29,6 +29,7 @@
#include "components/notifier/Notifier.hpp"
#include "components/settings/AccountSettingsModel.hpp"
#include "components/settings/SettingsModel.hpp"
#include "components/timeline/TimelineListModel.hpp"
#include "utils/Utils.hpp"
#include "CoreHandlers.hpp"
@ -203,7 +204,7 @@ void CoreHandlers::onMessageReceived (
if (
!app->hasFocus() ||
!CoreManager::getInstance()->getChatRoomModel(chatRoom, false)
!CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoom, false)
/*
!CoreManager::getInstance()->chatRoomModelExists(
Utils::coreStringToAppString(chatRoom->getPeerAddress()->asStringUriOnly()),

View file

@ -159,18 +159,20 @@ shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (const QString &peerAddr
return chatRoomModel;
}
*/
/*
shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (ChatRoomModel * data) {
if(data){
for(auto it = mChatRoomModels.begin() ; it != mChatRoomModels.end() ; ++it){
auto a = it->second.lock();
if(a.get() == data)
return a;
}
return getChatRoomListModel()->getChatRoomModel(data);
//for(auto it = mChatRoomModels.begin() ; it != mChatRoomModels.end() ; ++it){
// auto a = it->second.lock();
// if(a.get() == data)
// return a;
//}
}
return nullptr;
}
}*/
/*
shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, const bool& create) {
if (!chatRoom)
return nullptr;
@ -184,6 +186,8 @@ shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (std::shared_ptr<linphon
&& pa->encryptionEnabled() == pc->encryptionEnabled()
){
// Returns an existing chat model.
if(a->mDeleteChatRoom)
return nullptr;
shared_ptr<ChatRoomModel> chatRoomModel = a;
Q_CHECK_PTR(chatRoomModel);
return chatRoomModel;
@ -192,43 +196,49 @@ shared_ptr<ChatRoomModel> CoreManager::getChatRoomModel (std::shared_ptr<linphon
if(!create){
return nullptr;
}else{
/*
bool isEncrypted = pc->encryptionEnabled();
auto peerAddress = chatRoom->getPeerAddress();
auto localAddress = chatRoom->getLocalAddress();
auto conferenceAddress = chatRoom->getConferenceAddress();
if(!peerAddress)
peerAddress = conferenceAddress;
QPair<bool, QPair<QString, QString>> chatRoomModelId{isEncrypted,
{ QString::fromStdString(peerAddress->asString())
, QString::fromStdString(localAddress->asString()) }};
*/
//auto deleter = [this, chatRoomModelId](ChatRoomModel *chatRoomModel) {
auto deleter = [this, chatRoom](ChatRoomModel *chatRoomModel) {
shared_ptr<ChatRoomModel> chatRoomModel = ChatRoomModel::create(chatRoom);
auto deleter = [this](QObject * obj) {
//bool removed = mChatRoomModels.remove(chatRoomModelId);
ChatRoomModel * chatRoomModel = (ChatRoomModel*)obj;
auto c = chatRoomModel->getChatRoom();
auto iterator = mChatRoomModels.begin();
qWarning() << c.use_count();
while(iterator != mChatRoomModels.end()) {
if(iterator->first != chatRoom)
if(iterator->first != chatRoomModel->getChatRoom())
++iterator;
else{
//iterator->first->removeListener(iterator->second.lock());
auto i = *iterator;
qWarning() << c.use_count();
mChatRoomModels.erase(iterator);
qWarning() << c.use_count();
iterator = mChatRoomModels.end();
}
}
chatRoomModel->deleteLater();
qWarning() << c.use_count();
if(chatRoomModel->mDeleteChatRoom){
CoreManager::getInstance()->getCore()->deleteChatRoom(c);
}
qWarning() << c.use_count();
};
shared_ptr<ChatRoomModel> chatRoomModel(new ChatRoomModel(chatRoom), deleter);
chatRoom->addListener(chatRoomModel);
mChatRoomModels.append({chatRoom, chatRoomModel});
// shared_ptr<ChatRoomModel> chatRoomModel = ChatRoomModel::create(chatRoom);
connect(chatRoomModel.get(), &QObject::destroyed, deleter);
mChatRoomModels.append({chatRoom, chatRoomModel});
qWarning() << chatRoom.use_count();
//shared_ptr<ChatRoomModel> chatRoomModel = ChatRoomModel::create(chatRoom);
//(new ChatRoomModel(chatRoom), deleter);
//chatRoom->addListener(chatRoomModel);
//mChatRoomModels.append({chatRoom, chatRoomModel});
emit chatRoomModelCreated(chatRoomModel);
return chatRoomModel;
}
}
*/
/*
//bool CoreManager::chatRoomModelExists (const QString &peerAddress, const QString &localAddress, const bool &isSecure) {
bool CoreManager::chatRoomModelExists (std::shared_ptr<linphone::ChatRoom> chatRoom) {

View file

@ -69,8 +69,8 @@ public:
}
//std::shared_ptr<ChatRoomModel> getChatRoomModel (const QString &peerAddress, const QString &localAddress, const bool &isSecure);
std::shared_ptr<ChatRoomModel> getChatRoomModel (ChatRoomModel * data);// Get the shared pointer. This can be done becuase of unicity of ChatRoomModel
std::shared_ptr<ChatRoomModel> getChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, const bool& create = true);
//std::shared_ptr<ChatRoomModel> getChatRoomModel (ChatRoomModel * data);// Get the shared pointer. This can be done becuase of unicity of ChatRoomModel
//std::shared_ptr<ChatRoomModel> getChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, const bool& create = true);
//bool chatRoomModelExists (const QString &sipAddress, const QString &localAddress, const bool &isSecure);
//bool chatRoomModelExists (std::shared_ptr<linphone::ChatRoom> chatRoom);
@ -96,11 +96,11 @@ public:
Q_CHECK_PTR(mCallsListModel);
return mCallsListModel;
}
/* Timelines
ChatRoomListModel *getChatRoomListModel () const {
Q_CHECK_PTR(mChatRoomListModel);
return mChatRoomListModel;
}
}*/
ContactsListModel *getContactsListModel () const {
@ -114,7 +114,6 @@ public:
}
TimelineListModel *getTimelineListModel () const {
Q_CHECK_PTR(mTimelineListModel);
return mTimelineListModel;
}
@ -219,7 +218,7 @@ private:
//QHash<QPair<bool, QPair<QString, QString> >, std::weak_ptr<ChatRoomModel>> mChatRoomModels;
//QHash<std::shared_ptr<linphone::ChatRoom>, std::weak_ptr<ChatRoomModel>> mChatRoomModels;
QList<QPair<std::shared_ptr<linphone::ChatRoom>, std::weak_ptr<ChatRoomModel>>> mChatRoomModels;
//QList<QPair<std::shared_ptr<linphone::ChatRoom>, std::weak_ptr<ChatRoomModel>>> mChatRoomModels;
HistoryModel * mHistoryModel = nullptr;
LdapListModel *mLdapListModel = nullptr;

View file

@ -91,6 +91,8 @@ class Colors : public QObject {
ADD_COLOR(q, "#FFFFFF")
ADD_COLOR(r, "#909fab")//Background button
ADD_COLOR(s, "#96be64")// Security
// Field error.
ADD_COLOR(error, "#FF0000")
@ -127,6 +129,7 @@ signals:
void colorTpChanged (const QColor &color);
void colorTqChanged (const QColor &color);
void colorTrChanged (const QColor &color);
void colorTsChanged (const QColor &color);
void colorTerrorChanged (const QColor &color);

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ParticipantImdnStateListModel.hpp"
#include "ParticipantImdnStateModel.hpp"
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "utils/Utils.hpp"
#include "components/Components.hpp"
// =============================================================================
ParticipantImdnStateListModel::ParticipantImdnStateListModel (std::shared_ptr<linphone::ChatMessage> message, QObject *parent) : QAbstractListModel(parent) {
QVector<linphone::ChatMessage::State> states;
states.push_back(linphone::ChatMessage::State::Delivered);
states.push_back(linphone::ChatMessage::State::DeliveredToUser);
states.push_back(linphone::ChatMessage::State::Displayed);
states.push_back(linphone::ChatMessage::State::NotDelivered);
for(int i = 0 ; i < states.size() ; ++i){
std::list<std::shared_ptr<linphone::ParticipantImdnState>> imdns = message->getParticipantsByImdnState(states[i]);
for(auto imdn : imdns){
auto deviceModel = std::make_shared<ParticipantImdnStateModel>(imdn);
//connect(this, &ParticipantDeviceListModel::securityLevelChanged, deviceModel.get(), &ParticipantDeviceModel::onSecurityLevelChanged);
mList << deviceModel;
}
}
}
int ParticipantImdnStateListModel::rowCount (const QModelIndex &index) const{
return mList.count();
}
QHash<int, QByteArray> ParticipantImdnStateListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$participantImdn";
return roles;
}
QVariant ParticipantImdnStateListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row].get());
return QVariant();
}
void ParticipantImdnStateListModel::add(std::shared_ptr<ParticipantImdnStateModel> imdn){
int row = mList.count();
beginInsertRows(QModelIndex(), row, row);
mList << imdn;
endInsertRows();
resetInternalData();
}
bool ParticipantImdnStateListModel::removeRow (int row, const QModelIndex &parent){
return removeRows(row, 1, parent);
}
bool ParticipantImdnStateListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row);
endRemoveRows();
return true;
}
//--------------------------------------------------------------------------------
std::shared_ptr<ParticipantImdnStateModel> ParticipantImdnStateListModel::getImdnState(const std::shared_ptr<const linphone::ParticipantImdnState> & state){
std::shared_ptr<ParticipantImdnStateModel> imdn;
auto imdnAddress = state->getParticipant()->getAddress();
auto it = mList.begin();
while(it != mList.end() && !(*it)->getAddress()->equal(imdnAddress))
++it;
if(it != mList.end())
imdn = *it;
else{// Create the new one
imdn = std::make_shared<ParticipantImdnStateModel>(state);
add(imdn);
}
return imdn;
}
//--------------------------------------------------------------------------------
void ParticipantImdnStateListModel::updateState(const std::shared_ptr<const linphone::ParticipantImdnState> & state){
getImdnState(state)->update(state);
}
//--------------------------------------------------------------------------------
void ParticipantImdnStateListModel::onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state){
updateState(state);
}

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_IMDN_STATE_LIST_MODEL_H_
#define PARTICIPANT_IMDN_STATE_LIST_MODEL_H_
#include <linphone++/linphone.hh>
// =============================================================================
#include <QObject>
#include <QDateTime>
#include <QString>
#include <QAbstractListModel>
class ParticipantImdnStateModel;
class ParticipantImdnStateListModel : public QAbstractListModel {
Q_OBJECT
public:
ParticipantImdnStateListModel (std::shared_ptr<linphone::ChatMessage> message, QObject *parent = nullptr);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
virtual QHash<int, QByteArray> roleNames () const override;
virtual QVariant data (const QModelIndex &index, int role = Qt::DisplayRole) const override;
std::shared_ptr<ParticipantImdnStateModel> getImdnState(const std::shared_ptr<const linphone::ParticipantImdnState> & state);
void updateState(const std::shared_ptr<const linphone::ParticipantImdnState> & state);
public slots:
void onParticipantImdnStateChanged(const std::shared_ptr<linphone::ChatMessage> & message, const std::shared_ptr<const linphone::ParticipantImdnState> & state);
signals:
void imdnStateChanged();
private:
void add(std::shared_ptr<ParticipantImdnStateModel> imdn);
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
virtual bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
QList<std::shared_ptr<ParticipantImdnStateModel>> mList;
};
Q_DECLARE_METATYPE(std::shared_ptr<ParticipantImdnStateListModel>)
#endif

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ParticipantImdnStateModel.hpp"
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "utils/Utils.hpp"
#include "components/Components.hpp"
#include "components/core/CoreManager.hpp"
// =============================================================================
ParticipantImdnStateModel::ParticipantImdnStateModel (const std::shared_ptr<const linphone::ParticipantImdnState> imdn, QObject * parent) : QObject(parent) {
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
setState(LinphoneEnums::fromLinphone(imdn->getState()));
setStateChangeTime(QDateTime::fromSecsSinceEpoch(imdn->getStateChangeTime())) ;
mAddress = imdn->getParticipant()->getAddress()->clone();
}
// -----------------------------------------------------------------------------
LinphoneEnums::ChatMessageState ParticipantImdnStateModel::getState() const{
return mState;
}
QDateTime ParticipantImdnStateModel::getStateChangeTime() const{
return mStateChangeTime;
}
QString ParticipantImdnStateModel::getDisplayName() const{
return Utils::getDisplayName(mAddress);
}
std::shared_ptr<const linphone::Address> ParticipantImdnStateModel::getAddress() const{
return mAddress;
}
void ParticipantImdnStateModel::update(const std::shared_ptr<const linphone::ParticipantImdnState> imdn){
setState(LinphoneEnums::fromLinphone(imdn->getState()));
setStateChangeTime(QDateTime::fromSecsSinceEpoch(imdn->getStateChangeTime())) ;
}
void ParticipantImdnStateModel::setState(LinphoneEnums::ChatMessageState state){
if(state != mState){
mState = state;
emit stateChanged();
}
}
void ParticipantImdnStateModel::setStateChangeTime(const QDateTime& changeTime){
if(changeTime != mStateChangeTime){
mStateChangeTime = changeTime;
emit stateChangeTimeChanged();
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_IMDN_STATE_MODEL_H_
#define PARTICIPANT_IMDN_STATE_MODEL_H_
#include <linphone++/linphone.hh>
// =============================================================================
#include <QObject>
#include <QDateTime>
#include <QString>
#include "utils/LinphoneEnums.hpp"
class ParticipantModel;
class ParticipantImdnStateModel : public QObject {
Q_OBJECT
public:
ParticipantImdnStateModel (const std::shared_ptr<const linphone::ParticipantImdnState> imdn, QObject * parent = nullptr);
Q_PROPERTY(LinphoneEnums::ChatMessageState state MEMBER mState WRITE setState NOTIFY stateChanged)
Q_PROPERTY(QDateTime stateChangeTime MEMBER mStateChangeTime WRITE setStateChangeTime NOTIFY stateChangeTimeChanged)
Q_PROPERTY(QString displayName READ getDisplayName NOTIFY displayNameChanged)
LinphoneEnums::ChatMessageState getState() const;
QDateTime getStateChangeTime() const;
QString getDisplayName() const;
std::shared_ptr<const linphone::Address> getAddress() const;
void update(const std::shared_ptr<const linphone::ParticipantImdnState> state);
void setState(LinphoneEnums::ChatMessageState state);
void setStateChangeTime(const QDateTime& changeTime);
signals:
void stateChanged();
void stateChangeTimeChanged();
void displayNameChanged();
private:
std::shared_ptr<linphone::Address> mAddress;
LinphoneEnums::ChatMessageState mState;
QDateTime mStateChangeTime;
};
Q_DECLARE_METATYPE(std::shared_ptr<ParticipantImdnStateModel>);
#endif

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ParticipantImdnStateProxyModel.hpp"
#include <QQmlApplicationEngine>
#include "app/App.hpp"
#include "utils/Utils.hpp"
#include "components/Components.hpp"
#include "ParticipantImdnStateListModel.hpp"
#include "ParticipantImdnStateModel.hpp"
// =============================================================================
ParticipantImdnStateProxyModel::ParticipantImdnStateProxyModel (QObject *parent) : QSortFilterProxyModel(parent){
}
bool ParticipantImdnStateProxyModel::filterAcceptsRow (
int sourceRow,
const QModelIndex &sourceParent
) const {
Q_UNUSED(sourceRow)
Q_UNUSED(sourceParent)
//const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
//const ParticipantDeviceModel *device = index.data().value<ParticipantDeviceModel *>();
return true;
}
bool ParticipantImdnStateProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const ParticipantImdnStateModel *imdnA = sourceModel()->data(left).value<ParticipantImdnStateModel *>();
const ParticipantImdnStateModel *imdnB = sourceModel()->data(right).value<ParticipantImdnStateModel *>();
return imdnA->getState() < imdnB->getState()
|| (imdnA->getState() == imdnB->getState() && imdnA->getStateChangeTime() < imdnB->getStateChangeTime());
}
//---------------------------------------------------------------------------------
void ParticipantImdnStateProxyModel::setChatMessageModel(ChatMessageModel * message){
setSourceModel(message->getParticipantImdnStates().get());
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PARTICIPANT_IMDN_STATE_PROXY_MODEL_H_
#define PARTICIPANT_IMDN_STATE_PROXY_MODEL_H_
#include <linphone++/linphone.hh>
// =============================================================================
#include <QObject>
#include <QDateTime>
#include <QString>
#include <QSortFilterProxyModel>
class ParticipantImdnStateListModel;
class ChatMessageModel;
class ParticipantImdnStateProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
ParticipantImdnStateProxyModel (QObject *parent = nullptr);
void setChatMessageModel(ChatMessageModel* message);
protected:
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
virtual bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
std::shared_ptr<ParticipantImdnStateListModel> mImdns;
};
#endif

View file

@ -50,13 +50,13 @@ QHash<int, QByteArray> ParticipantDeviceListModel::roleNames () const {
QVariant ParticipantDeviceListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count())
return QVariant();
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mList[row].get());
return QVariant::fromValue(mList[row].get());
return QVariant();
}
@ -66,17 +66,17 @@ bool ParticipantDeviceListModel::removeRow (int row, const QModelIndex &parent){
bool ParticipantDeviceListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mList.count())
return false;
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i)
mList.takeAt(row)->deleteLater();
mList.takeAt(row);
endRemoveRows();
return true;
}

View file

@ -37,6 +37,8 @@ ParticipantListModel::ParticipantListModel (ChatRoomModel * chatRoomModel, QObje
connect(mChatRoomModel, &ChatRoomModel::securityEvent, this, &ParticipantListModel::onSecurityEvent);
connect(mChatRoomModel, &ChatRoomModel::conferenceJoined, this, &ParticipantListModel::onConferenceJoined);
connect(mChatRoomModel, &ChatRoomModel::participantAdded, this, &ParticipantListModel::onParticipantAdded);
connect(mChatRoomModel, &ChatRoomModel::participantRemoved, this, &ParticipantListModel::onParticipantRemoved);
connect(mChatRoomModel, &ChatRoomModel::participantDeviceAdded, this, &ParticipantListModel::onParticipantDeviceAdded);
@ -67,7 +69,22 @@ ChatRoomModel *ParticipantListModel::getChatRoomModel() const{
QString ParticipantListModel::addressesToString()const{
QStringList txt;
for(auto participant : mParticipants){
txt << Utils::coreStringToAppString(participant->getParticipant()->getAddress()->asStringUriOnly());
if( participant->getParticipant())// is Participant. We test it because this participant is not accepted by chat room yet.
txt << Utils::coreStringToAppString(participant->getParticipant()->getAddress()->asStringUriOnly());
}
txt.removeFirst();// Remove me
return txt.join(", ");
}
QString ParticipantListModel::displayNamesToString()const{
QStringList txt;
for(auto participant : mParticipants){
auto p = participant->getParticipant();
if(p){
QString displayName = Utils::getDisplayName(p->getAddress());
if(displayName != "")
txt << displayName;
}
}
txt.removeFirst();// Remove me
return txt.join(", ");
@ -148,6 +165,7 @@ bool ParticipantListModel::removeRows (int row, int count, const QModelIndex &pa
void ParticipantListModel::updateParticipants () {
if( mChatRoomModel) {
bool changed = false;
CoreManager *coreManager = CoreManager::getInstance();
auto dbParticipants = mChatRoomModel->getChatRoom()->getParticipants();
auto me = mChatRoomModel->getChatRoom()->getMe();
@ -163,8 +181,8 @@ void ParticipantListModel::updateParticipants () {
++itDbParticipant;
}
if( itDbParticipant == dbParticipants.end()){
itParticipant = mParticipants.erase(itParticipant);
changed = true;
}else
++itParticipant;
}
@ -179,8 +197,11 @@ void ParticipantListModel::updateParticipants () {
connect(this, &ParticipantListModel::deviceSecurityLevelChanged, participant.get(), &ParticipantModel::onDeviceSecurityLevelChanged);
connect(this, &ParticipantListModel::securityLevelChanged, participant.get(), &ParticipantModel::onSecurityLevelChanged);
mParticipants << participant;
changed = true;
}
}
if( changed)
emit participantsChanged();
}
}
@ -190,6 +211,7 @@ void ParticipantListModel::add (std::shared_ptr<ParticipantModel> participant){
mParticipants << participant;
endInsertRows();
resetInternalData();
emit participantsChanged();
}
void ParticipantListModel::remove (ParticipantModel *model) {
@ -209,6 +231,7 @@ void ParticipantListModel::remove (ParticipantModel *model) {
beginRemoveRows(QModelIndex(), index, index);
mParticipants.erase(itParticipant);
endRemoveRows();
emit participantsChanged();
}
}
@ -241,6 +264,9 @@ void ParticipantListModel::onSecurityEvent(const std::shared_ptr<linphone::ChatR
}
}
void ParticipantListModel::onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
updateParticipants();
}
void ParticipantListModel::onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
updateParticipants();
}

View file

@ -52,7 +52,8 @@ public:
Q_INVOKABLE void remove (ParticipantModel *importer);
Q_INVOKABLE ChatRoomModel* getChatRoomModel() const;
Q_INVOKABLE QString addressesToString()const;
Q_INVOKABLE QString addressesToString()const;
Q_INVOKABLE QString displayNamesToString()const;
Q_INVOKABLE QString usernamesToString()const;
bool contains(const QString& address) const;
@ -61,6 +62,7 @@ public:
public slots:
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);
void onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
void onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog);
@ -72,6 +74,7 @@ public slots:
signals:
void securityLevelChanged();
void deviceSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
void participantsChanged();
private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());

View file

@ -32,6 +32,7 @@
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;
if(mParticipant){

View file

@ -59,7 +59,7 @@ public:
void setAdminStatus(const bool& status);
std::shared_ptr<linphone::Participant> getParticipant();
Q_INVOKABLE ParticipantDeviceProxyModel * getProxyDevices(); // Reminder : Q_INVOKABLE change the ownership of the proxy to QML
Q_INVOKABLE ParticipantDeviceProxyModel * getProxyDevices();
std::shared_ptr<ParticipantDeviceListModel> getParticipantDevices();
//linphone::ChatRoomSecurityLevel getSecurityLevel() const;
//std::shared_ptr<linphone::ParticipantDevice> findDevice(const std::shared_ptr<const linphone::Address> & address) const;

View file

@ -83,7 +83,7 @@ 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, this);
std::shared_ptr<ParticipantModel> participant = std::make_shared<ParticipantModel>(nullptr);
participant->setSipAddress(address);
participantsModel->add(participant);
}

View file

@ -61,13 +61,13 @@ QString Presence::getPresenceStatusAsString (const linphone::ConsolidatedPresenc
QString Presence::getBetterPresenceLevelIconName (const PresenceLevel &level) {
switch (level) {
case Green:
return QStringLiteral("current_account_status_available");
return QStringLiteral("current_account_status_online");
case Orange:
return QStringLiteral("led_orange");
return QStringLiteral("current_account_status_busy");
case Red:
return QStringLiteral("led_red");
return QStringLiteral("current_account_status_dnd");
case White:
return QStringLiteral("led_white");
return QStringLiteral("current_account_status_offline");
}
return QString("");

View file

@ -0,0 +1,53 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SearchResultModel.hpp"
#include "components/core/CoreManager.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contacts/ContactsListModel.hpp"
// =============================================================================
SearchResultModel::SearchResultModel(std::shared_ptr<const linphone::Friend> linphoneFriend, std::shared_ptr<const linphone::Address> address, QObject * parent) : QObject(parent){
mFriend = linphoneFriend;
if(linphoneFriend && linphoneFriend->getAddress())
mAddress = linphoneFriend->getAddress()->clone();
else
mAddress = address->clone();
}
QString SearchResultModel::getAddressString() const{
return QString::fromStdString(mAddress->asString());
}
QString SearchResultModel::getAddressStringUriOnly() const{
return QString::fromStdString(mAddress->asStringUriOnly());
}
std::shared_ptr<linphone::Address> SearchResultModel::getAddress() const{
return mAddress;
}
ContactModel * SearchResultModel::getContactModel() const{
return CoreManager::getInstance()->getContactsListModel()->findContactModelFromSipAddress(getAddressStringUriOnly());
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SEARCH_RESULT_MODEL_H_
#define SEARCH_RESULT_MODEL_H_
#include <QObject>
#include <linphone++/linphone.hh>
#include <list>
// =============================================================================
class ContactModel;
class SearchResultModel : public QObject{
Q_OBJECT
public:
SearchResultModel(std::shared_ptr<const linphone::Friend> linphoneFriend, std::shared_ptr<const linphone::Address> address, QObject * parent = nullptr);
Q_PROPERTY(ContactModel * contactModel READ getContactModel CONSTANT)
Q_PROPERTY(QString sipAddress READ getAddressString CONSTANT)
Q_INVOKABLE QString getAddressString() const;
Q_INVOKABLE QString getAddressStringUriOnly() const;
std::shared_ptr<linphone::Address> getAddress()const;
ContactModel * getContactModel() const;
std::shared_ptr<linphone::Address> mAddress;
std::shared_ptr<const linphone::Friend> mFriend;
};
Q_DECLARE_METATYPE(std::shared_ptr<SearchResultModel>)
#endif

View file

@ -18,6 +18,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SearchSipAddressesModel.hpp"
#include <QDateTime>
#include <QElapsedTimer>
#include <QUrl>
@ -34,7 +36,9 @@
#include "components/settings/AccountSettingsModel.hpp"
#include "utils/Utils.hpp"
#include "SearchSipAddressesModel.hpp"
#include "SearchResultModel.hpp"
// =============================================================================
@ -74,7 +78,7 @@ QVariant SearchSipAddressesModel::data (const QModelIndex &index, int role) cons
return QVariant();
if (role == Qt::DisplayRole)
return QVariantMap{{"sipAddress", mAddresses[row]}};
return QVariant::fromValue(mAddresses[row].get());
return QVariant();
}
@ -109,12 +113,7 @@ void SearchSipAddressesModel::setFilter(const QString& filter){
void SearchSipAddressesModel::searchReceived(std::list<std::shared_ptr<linphone::SearchResult>> results){
beginResetModel();
mAddresses.clear();
for(auto it = results.begin() ; it != results.end() ; ++it){
if((*it)->getFriend()){
mAddresses << QString::fromStdString((*it)->getFriend()->getAddress()->asString());
}else{
mAddresses << QString::fromStdString((*it)->getAddress()->asString());
}
}
for(auto it = results.begin() ; it != results.end() ; ++it)
mAddresses << std::make_shared<SearchResultModel>((*it)->getFriend(), (*it)->getAddress());
endResetModel();
}

View file

@ -27,10 +27,11 @@
#include <linphone++/linphone.hh>
#include "../search/SearchHandler.hpp"
#include "SearchHandler.hpp"
// =============================================================================
class SearchResultModel;
class SearchSipAddressesModel : public QAbstractListModel {
Q_OBJECT
@ -46,7 +47,7 @@ public:
Q_INVOKABLE void setFilter (const QString &pattern);
QStringList mAddresses;
QList<std::shared_ptr<SearchResultModel> > mAddresses;
// And instance of Magic search
std::shared_ptr<linphone::MagicSearch> mMagicSearch;
// Callback when searching

View file

@ -18,17 +18,17 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SearchSipAddressesProxyModel.hpp"
#include "components/contact/ContactModel.hpp"
#include "components/contact/VcardModel.hpp"
#include "components/core/CoreManager.hpp"
#include "components/sip-addresses/SipAddressesModel.hpp"
#include "components/sip-addresses/SipAddressesSorter.hpp"
#include "SipAddressesModel.hpp"
#include "SearchSipAddressesProxyModel.hpp"
#include "SearchSipAddressesModel.hpp"
#include "SipAddressesSorter.hpp"
#include "SearchResultModel.hpp"
#include "utils/Utils.hpp"
#include <QVariantMap>
@ -72,11 +72,9 @@ bool SearchSipAddressesProxyModel::isIgnored(const QString& address) const{
bool SearchSipAddressesProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
const QVariantMap data = sourceModel()->data(index).toMap();
std::shared_ptr<linphone::Address> a = Utils::interpretUrl(data["sipAddress"].toString());
return !mResultsToIgnore.contains(Utils::coreStringToAppString(a->asStringUriOnly()));
const SearchResultModel * model = sourceModel()->data(index).value<SearchResultModel*>();
return !mResultsToIgnore.contains(Utils::coreStringToAppString(model->getAddress()->asStringUriOnly()));
}
bool SearchSipAddressesProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {

View file

@ -171,7 +171,7 @@ class SettingsModel : public QObject {
Q_PROPERTY(bool exitOnClose READ getExitOnClose WRITE setExitOnClose NOTIFY exitOnCloseChanged)
Q_PROPERTY(bool showLocalSipAccount READ getShowLocalSipAccount CONSTANT)
Q_PROPERTY(bool showStartChat READ getShowStartChatButton CONSTANT)
Q_PROPERTY(bool showStartChatButton READ getShowStartChatButton CONSTANT)
Q_PROPERTY(bool showStartVideoCallButton READ getShowStartVideoCallButton CONSTANT)
// Advanced. -----------------------------------------------------------------

View file

@ -29,6 +29,7 @@
#include "TimelineModel.hpp"
#include "TimelineListModel.hpp"
#include <QDebug>
@ -36,7 +37,6 @@
// =============================================================================
TimelineListModel::TimelineListModel (QObject *parent) : QAbstractListModel(parent) {
//initTimeline();
mSelectedCount = 0;
CoreHandlers* coreHandlers= CoreManager::getInstance()->getHandlers().get();
connect(coreHandlers, &CoreHandlers::chatRoomStateChanged, this, &TimelineListModel::onChatRoomStateChanged);
@ -53,7 +53,6 @@ TimelineModel * TimelineListModel::getAt(const int& index){
}
void TimelineListModel::reset(){
//initTimeline();
updateTimelines ();
}
@ -66,25 +65,25 @@ void TimelineListModel::selectAll(const bool& selected){
(*it)->mSelected = selected;
}
int TimelineListModel::rowCount (const QModelIndex &) const {
return mTimelines.count();
return mTimelines.count();
}
QHash<int, QByteArray> TimelineListModel::roleNames () const {
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$timelines";
return roles;
QHash<int, QByteArray> roles;
roles[Qt::DisplayRole] = "$timelines";
return roles;
}
QVariant TimelineListModel::data (const QModelIndex &index, int role) const {
int row = index.row();
if (!index.isValid() || row < 0 || row >= mTimelines.count())
return QVariant();
if (role == Qt::DisplayRole)
return QVariant::fromValue(mTimelines[row].get());
return QVariant();
int row = index.row();
if (!index.isValid() || row < 0 || row >= mTimelines.count())
return QVariant();
if (role == Qt::DisplayRole)// && !mTimelines[row]->getChatRoomModel()->mDeleteChatRoom)
return QVariant::fromValue(mTimelines[row].get());
return QVariant();
}
// -----------------------------------------------------------------------------
@ -94,67 +93,37 @@ QVariant TimelineListModel::data (const QModelIndex &index, int role) const {
// -----------------------------------------------------------------------------
bool TimelineListModel::removeRow (int row, const QModelIndex &parent) {
return removeRows(row, 1, parent);
return removeRows(row, 1, parent);
}
bool TimelineListModel::removeRows (int row, int count, const QModelIndex &parent) {
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mTimelines.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i){
auto timeline = mTimelines.takeAt(row);
timeline->getChatRoomModel()->getChatRoom()->removeListener(timeline);
}
endRemoveRows();
return true;
QVector<std::shared_ptr<TimelineModel> > oldTimelines;
oldTimelines.reserve(count);
int limit = row + count - 1;
if (row < 0 || count < 0 || limit >= mTimelines.count())
return false;
beginRemoveRows(parent, row, limit);
for (int i = 0; i < count; ++i){
auto timeline = mTimelines.takeAt(row);
timeline->getChatRoomModel()->getChatRoom()->removeListener(timeline);
oldTimelines.push_back(timeline);
}
endRemoveRows();
for(auto timeline : oldTimelines)
if(timeline->mSelected)
timeline->setSelected(false);
return true;
}
// -----------------------------------------------------------------------------
void TimelineListModel::initTimeline () {
/*
CoreManager *coreManager = CoreManager::getInstance();
auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress();
std::list<std::shared_ptr<linphone::ChatRoom>> allChatRooms = coreManager->getCore()->getChatRooms();
QList<std::shared_ptr<TimelineModel>> models;
for(auto itAllChatRooms = allChatRooms.begin() ; itAllChatRooms != allChatRooms.end() ; ++itAllChatRooms){
if((*itAllChatRooms)->getMe()->getAddress()->weakEqual(currentAddress)){
models << new TimelineModel(*itAllChatRooms);
}
}
//beginInsertRows(QModelIndex(), 0, models.count()-1);
mTimelines = models;
//endInsertRows();
*/
/*
initSipAddressesFromChat();
initSipAddressesFromCalls();
initRefs();
initSipAddressesFromContacts();*/
/*
auto bcSections = lConfig->getSectionsNamesList();
// Loop on all sections and load configuration. If this is not a LDAP configuration, the model is discarded.
for(auto itSections = bcSections.begin(); itSections != bcSections.end(); ++itSections) {
TimelineModel * model = new TimelineModel();
if(model->load(*itSections)){
mTimelines.append(model);
}else
delete model;
}
*/
}
std::shared_ptr<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create){
if(chatRoom){
for(auto it = mTimelines.begin() ; it != mTimelines.end() ; ++it){
@ -163,9 +132,11 @@ std::shared_ptr<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<li
}
}
if(create){
std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom);
chatRoom->addListener(model);
std::shared_ptr<TimelineModel> model = TimelineModel::create(chatRoom);
//std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom);
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
add(model);
//connect(model.get(), SIGNAL(conferenceLeft()), this, SLOT(selectedHasChanged(bool)));
return model;
}
@ -179,14 +150,11 @@ QVariantList TimelineListModel::getLastChatRooms(const int& maxCount) const{
int count = 0;
QDateTime currentDateTime = QDateTime::currentDateTime();
auto contactList = CoreManager::getInstance()->getContactsListModel();
for(auto timeline : mTimelines){
auto chatRoom = timeline->getChatRoomModel();
if(chatRoom && !chatRoom->isGroupEnabled() && !chatRoom->haveEncryption()) {
//ContactModel * contact = contactList->findContactModelFromSipAddress(chatRoom->getPeerAddress());
//if(contact)
sortedData.insert(chatRoom->mLastUpdateTime.secsTo(currentDateTime),chatRoom);
sortedData.insert(chatRoom->mLastUpdateTime.secsTo(currentDateTime),chatRoom);
}
}
for(auto contact : sortedData){
@ -199,6 +167,36 @@ QVariantList TimelineListModel::getLastChatRooms(const int& maxCount) const{
return contacts;
}
std::shared_ptr<ChatRoomModel> TimelineListModel::getChatRoomModel(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool& create){
if(chatRoom ){
for(auto timeline : mTimelines){
if(timeline->mChatRoomModel->getChatRoom() == chatRoom)
return timeline->mChatRoomModel;
}
if(create){
std::shared_ptr<TimelineModel> model = TimelineModel::create(chatRoom);
if(model){
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
//connect(model.get(), SIGNAL(conferenceLeft()), this, SLOT(selectedHasChanged(bool)));
add(model);
return model->mChatRoomModel;
}
}
}
return nullptr;
}
std::shared_ptr<ChatRoomModel> TimelineListModel::getChatRoomModel(ChatRoomModel * chatRoom){
for(auto timeline : mTimelines){
if(timeline->mChatRoomModel.get() == chatRoom)
return timeline->mChatRoomModel;
}
return nullptr;
}
//-------------------------------------------------------------------------------------------------
void TimelineListModel::setSelectedCount(int selectedCount){
@ -223,63 +221,54 @@ void TimelineListModel::selectedHasChanged(bool selected){
}
void TimelineListModel::updateTimelines () {
//CoreManager *coreManager = CoreManager::getInstance();
//auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress();
/*
//std::list<std::shared_ptr<linphone::ChatRoom>> allChatRooms = coreManager->getCore()->getChatRooms();
QList<std::shared_ptr<TimelineModel> > models;
for(auto itAllChatRooms = allChatRooms.begin() ; itAllChatRooms != allChatRooms.end() ; ++itAllChatRooms){
if((*itAllChatRooms)->getMe()->getAddress()->weakEqual(currentAddress)){
models << getTimeline(*itAllChatRooms, true);
;
}
}
//beginInsertRows(QModelIndex(), 0, models.count()-1);
mTimelines = models;
*/
CoreManager *coreManager = CoreManager::getInstance();
auto currentAddress = coreManager->getAccountSettingsModel()->getUsedSipAddress();
std::list<std::shared_ptr<linphone::ChatRoom>> allChatRooms = coreManager->getCore()->getChatRooms();
//Remove left participants
//Remove no more chat rooms
auto itTimeline = mTimelines.begin();
while(itTimeline != mTimelines.end()) {
auto itDbTimeline = allChatRooms.begin();
auto timeline = (*itTimeline)->getChatRoomModel()->getChatRoom();
while(itDbTimeline != allChatRooms.end() && *itDbTimeline != timeline ){
++itDbTimeline;
}
if(*itTimeline) {
auto chatRoomModel = (*itTimeline)->getChatRoomModel();
if(chatRoomModel) {
auto timeline = chatRoomModel->getChatRoom();
if( timeline ) {
while(itDbTimeline != allChatRooms.end() && *itDbTimeline != timeline ){
++itDbTimeline;
}
}else
itDbTimeline = allChatRooms.end();
}else
itDbTimeline = allChatRooms.end();
}else
itDbTimeline = allChatRooms.end();
if( itDbTimeline == allChatRooms.end()){
int index = itTimeline - mTimelines.begin();
removeRow(index);
++itTimeline;
//itTimeline = mTimelines.erase(itTimeline);
if(index>0){
--itTimeline;
removeRow(index);
++itTimeline;
}else{
removeRow(0);
itTimeline = mTimelines.begin();
}
}else
++itTimeline;
}
// Add new
// Add new
for(auto dbChatRoom : allChatRooms){
if(!getTimeline(dbChatRoom, false)){// Create a new Timeline if needed
std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(dbChatRoom);
dbChatRoom->addListener(model);
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
add(model);
auto haveTimeline = getTimeline(dbChatRoom, false);
if(!haveTimeline){// Create a new Timeline if needed
std::shared_ptr<TimelineModel> model = TimelineModel::create(dbChatRoom);
if( model){
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
add(model);
}
}
}
}
/*
// Create a new TimelineModel and put it in the list
void TimelineListModel::add(){
int row = mTimelines.count();
beginInsertRows(QModelIndex(), row, row);
auto model = new TimelineModel();
model->init();
mTimelines << model;
endInsertRows();
resetInternalData();
}
*/
void TimelineListModel::add (std::shared_ptr<TimelineModel> timeline){
int row = mTimelines.count();
@ -290,12 +279,6 @@ void TimelineListModel::add (std::shared_ptr<TimelineModel> timeline){
}
void TimelineListModel::remove (TimelineModel* model) {
/*
int index = mTimelines.indexOf(model);
if (index >=0){
ldap->unsave();
removeRow(index);
}*/
}
void TimelineListModel::remove(std::shared_ptr<TimelineModel> model){
int index = mTimelines.indexOf(model);
@ -303,16 +286,30 @@ void TimelineListModel::remove(std::shared_ptr<TimelineModel> model){
removeRow(index);
}
}
void TimelineListModel::removeChatRoomModel(std::shared_ptr<ChatRoomModel> model){
if(model->getChatRoom()->isEmpty() && model->hasBeenLeft()){
auto itTimeline = mTimelines.begin();
while(itTimeline != mTimelines.end()) {
if((*itTimeline)->mChatRoomModel == model){
model->deleteChatRoom();
remove(*itTimeline);
return;
}else
++itTimeline;
}
}
}
void TimelineListModel::onChatRoomStateChanged(const std::shared_ptr<linphone::ChatRoom> &chatRoom,linphone::ChatRoom::State state){
if( state == linphone::ChatRoom::State::Created
&& !getTimeline(chatRoom, false)){// Create a new Timeline if needed
std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom);
chatRoom->addListener(model);
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
add(model);
std::shared_ptr<TimelineModel> model = TimelineModel::create(chatRoom);
if(model){
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(selectedHasChanged(bool)));
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
add(model);
}
}else if(state == linphone::ChatRoom::State::Deleted){
updateTimelines();
}
}
/*

View file

@ -40,6 +40,8 @@ public:
TimelineModel * getAt(const int& index);
std::shared_ptr<TimelineModel> getTimeline(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
Q_INVOKABLE QVariantList getLastChatRooms(const int& maxCount) const;
std::shared_ptr<ChatRoomModel> getChatRoomModel(std::shared_ptr<linphone::ChatRoom> chatRoom, const bool &create);
std::shared_ptr<ChatRoomModel> getChatRoomModel(ChatRoomModel * chatRoom);
int rowCount (const QModelIndex &index = QModelIndex()) const override;
@ -55,11 +57,13 @@ public:
void setSelectedCount(int selectedCount);
public slots:
void update();
void removeChatRoomModel(std::shared_ptr<ChatRoomModel> model);
void selectedHasChanged(bool selected);
void onChatRoomStateChanged(const std::shared_ptr<linphone::ChatRoom> &chatRoom,linphone::ChatRoom::State state);
//void onConferenceLeft();
signals:
void selectedCountChanged(int selectedCount);
void updated();
@ -68,9 +72,6 @@ private:
bool removeRow (int row, const QModelIndex &parent = QModelIndex());
bool removeRows (int row, int count, const QModelIndex &parent = QModelIndex()) override;
void initTimeline ();
void updateTimelines();
QList<std::shared_ptr<TimelineModel>> mTimelines;

View file

@ -23,25 +23,46 @@
#include "components/sip-addresses/SipAddressesModel.hpp"
#include "components/chat-room/ChatRoomModel.hpp"
#include "utils/Utils.hpp"
#include "app/App.hpp"
#include "TimelineModel.hpp"
#include "TimelineListModel.hpp"
#include <QDebug>
#include <qqmlapplicationengine.h>
#include <QTimer>
// =============================================================================
std::shared_ptr<TimelineModel> TimelineModel::create(std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent){
if(!CoreManager::getInstance()->getTimelineListModel() || !CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, false)) {
std::shared_ptr<TimelineModel> model = std::make_shared<TimelineModel>(chatRoom, parent);
if(model && model->getChatRoomModel()){
model->mSelf = model;
chatRoom->addListener(model);
return model;
}
}
return nullptr;
}
TimelineModel::TimelineModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent) : QObject(parent) {
mChatRoomModel = CoreManager::getInstance()->getChatRoomModel(chatRoom);
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
mChatRoomModel = ChatRoomModel::create(chatRoom);
// mChatRoomModel = CoreManager::getInstance()->getTimelineListModel()->getChatRoomModel(chatRoom);
if( mChatRoomModel ){
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::unreadMessagesCountChanged, this, &TimelineModel::updateUnreadCount);
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::missedCallsCountChanged, this, &TimelineModel::updateUnreadCount);
}
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::unreadMessagesCountChanged, this, &TimelineModel::updateUnreadCount);
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::missedCallsCountChanged, this, &TimelineModel::updateUnreadCount);
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::conferenceLeft, this, &TimelineModel::onConferenceLeft);
//QObject::connect(mChatRoomModel.get(), &ChatRoomModel::conferenceLeft, this, &TimelineModel::onConferenceLeft);
//mTimestamp = QDateTime::fromMSecsSinceEpoch(mChatRoomModel->getChatRoom()->getLastUpdateTime());
mSelected = false;
}
TimelineModel::~TimelineModel(){
mChatRoomModel->getChatRoom()->removeListener(mChatRoomModel);
qWarning() << "Destroying Timeline";
}
QString TimelineModel::getFullPeerAddress() const{
@ -53,17 +74,7 @@ QString TimelineModel::getFullLocalAddress() const{
QString TimelineModel::getUsername() const{
std::string username = mChatRoomModel->getChatRoom()->getSubject();
if(username != ""){
return QString::fromStdString(username);
}
username = mChatRoomModel->getChatRoom()->getPeerAddress()->getDisplayName();
if(username != "")
return QString::fromStdString(username);
username = mChatRoomModel->getChatRoom()->getPeerAddress()->getUsername();
if(username != "")
return QString::fromStdString(username);
return QString::fromStdString(mChatRoomModel->getChatRoom()->getPeerAddress()->asStringUriOnly());
return mChatRoomModel->getUsername();
}
QString TimelineModel::getAvatar() const{
@ -81,6 +92,8 @@ ChatRoomModel *TimelineModel::getChatRoomModel() const{
void TimelineModel::setSelected(const bool& selected){
if(selected != mSelected){
mSelected = selected;
if(mSelected)
mChatRoomModel->initEntries();
emit selectedChanged(mSelected);
}
}
@ -104,7 +117,12 @@ void TimelineModel::onChatMessageSent(const std::shared_ptr<linphone::ChatRoom>
void TimelineModel::onParticipantAdded(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantRemoved(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onParticipantAdminStatusChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){}
void TimelineModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){
if(newState == linphone::ChatRoom::State::Created)
QTimer::singleShot(200, [=](){// Delay process in order to let GUI time for Timeline building/linking before doing actions
setSelected(true);
});
}
void TimelineModel::onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){}
void TimelineModel::onSubjectChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog)
{

View file

@ -36,6 +36,7 @@ class TimelineModel : public QObject, public linphone::ChatRoomListener {
Q_OBJECT
public:
static std::shared_ptr<TimelineModel> create(std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent = Q_NULLPTR);
TimelineModel (std::shared_ptr<linphone::ChatRoom> chatRoom, QObject *parent = Q_NULLPTR);
virtual ~TimelineModel();
@ -97,6 +98,7 @@ public:
public slots:
void updateUnreadCount();
//void chatRoomDeleted();
signals:
void fullPeerAddressChanged();
@ -106,6 +108,10 @@ signals:
void presenceStatusChanged();
void selectedChanged(bool selected);
void conferenceLeft();
private:
std::weak_ptr<TimelineModel> mSelf;
};

View file

@ -41,20 +41,20 @@ TimelineProxyModel::TimelineProxyModel (QObject *parent) : QSortFilterProxyModel
connect(model, SIGNAL(selectedCountChanged(int)), this, SIGNAL(selectedCountChanged(int)));
connect(model, &TimelineListModel::updated, this, &TimelineProxyModel::invalidate);
setSourceModel(model);
QObject::connect(accountSettingsModel, &AccountSettingsModel::defaultProxyChanged, this, [this]() {
dynamic_cast<TimelineListModel*>(sourceModel())->update();
invalidate();
//updateCurrentSelection();
invalidate();
//updateCurrentSelection();
});
QObject::connect(coreManager->getSipAddressesModel(), &SipAddressesModel::sipAddressReset, this, [this]() {
dynamic_cast<TimelineListModel*>(sourceModel())->reset();
invalidate();// Invalidate and reload GUI if the model has been reset
//updateCurrentSelection();
invalidate();// Invalidate and reload GUI if the model has been reset
//updateCurrentSelection();
});
sort(0);
sort(0);
}
// -----------------------------------------------------------------------------
@ -82,16 +82,49 @@ void TimelineProxyModel::updateCurrentSelection(){
void TimelineProxyModel::unselectAll(){
dynamic_cast<TimelineListModel*>(sourceModel())->selectAll(false);
}
void TimelineProxyModel::setFilterFlags(const int& filterFlags){
if( mFilterFlags != filterFlags){
mFilterFlags = filterFlags;
invalidate();
emit filterFlagsChanged();
}
}
void TimelineProxyModel::setFilterText(const QString& text){
if( mFilterText != text){
mFilterText = text;
invalidate();
emit filterTextChanged();
}
}
// -----------------------------------------------------------------------------
bool TimelineProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const {
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
return true;
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
auto timeline = sourceModel()->data(index).value<TimelineModel*>();
bool show = (mFilterFlags==0);// Show all at 0 (no hide all)
if( !show && ( (mFilterFlags & TimelineFilter::SimpleChatRoom) == TimelineFilter::SimpleChatRoom))
show = !timeline->getChatRoomModel()->isGroupEnabled() && !timeline->getChatRoomModel()->haveEncryption();
if( !show && ( (mFilterFlags & TimelineFilter::SecureChatRoom) == TimelineFilter::SecureChatRoom))
show = !timeline->getChatRoomModel()->isGroupEnabled() && timeline->getChatRoomModel()->haveEncryption();
if( !show && ( (mFilterFlags & TimelineFilter::GroupChatRoom) == TimelineFilter::GroupChatRoom))
show = timeline->getChatRoomModel()->isGroupEnabled() && !timeline->getChatRoomModel()->haveEncryption();
if( !show && ( (mFilterFlags & TimelineFilter::SecureGroupChatRoom) == TimelineFilter::SecureGroupChatRoom))
show = timeline->getChatRoomModel()->isGroupEnabled() && timeline->getChatRoomModel()->haveEncryption();
if( !show && ( (mFilterFlags & TimelineFilter::EphemeralChatRoom) == TimelineFilter::EphemeralChatRoom))
show = timeline->getChatRoomModel()->isEphemeralEnabled();
if(show && mFilterText != ""){
QRegularExpression search(mFilterText, QRegularExpression::CaseInsensitiveOption);
show = timeline->getChatRoomModel()->getSubject().contains(search)
|| timeline->getChatRoomModel()->getUsername().contains(search);
//|| timeline->getChatRoomModel()->getFullPeerAddress().contains(search); not enough significant?
}
return show;
}
bool TimelineProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
const TimelineModel* a = sourceModel()->data(left).value<TimelineModel*>();
const TimelineModel* b = sourceModel()->data(right).value<TimelineModel*>();
return a->getChatRoomModel()->mLastUpdateTime >= b->getChatRoomModel()->mLastUpdateTime ;
const TimelineModel* a = sourceModel()->data(left).value<TimelineModel*>();
const TimelineModel* b = sourceModel()->data(right).value<TimelineModel*>();
return a->getChatRoomModel()->mLastUpdateTime >= b->getChatRoomModel()->mLastUpdateTime ;
}

View file

@ -33,8 +33,22 @@ class TimelineProxyModel : public QSortFilterProxyModel {
public:
enum TimelineFilter {
SimpleChatRoom=1,
SecureChatRoom=2,
GroupChatRoom=4,
SecureGroupChatRoom=8,
EphemeralChatRoom=16,
AllChatRooms = SimpleChatRoom+SecureChatRoom+GroupChatRoom+SecureGroupChatRoom+EphemeralChatRoom
};
Q_ENUM(TimelineFilter)
TimelineProxyModel (QObject *parent = Q_NULLPTR);
Q_PROPERTY(int filterFlags MEMBER mFilterFlags WRITE setFilterFlags NOTIFY filterFlagsChanged)
Q_PROPERTY(QString filterText MEMBER mFilterText WRITE setFilterText NOTIFY filterTextChanged)
//Q_PROPERTY(ChatRoomModel *currentChatRoomModel WRITE setCurrentChatRoomModel READ getCurrentChatRoomModel NOTIFY currentChatRoomModelChanged)
//void updateCurrentSelection();
@ -42,10 +56,14 @@ public:
//Q_INVOKABLE void setCurrentChatRoomModel(ChatRoomModel *data);
//ChatRoomModel *getCurrentChatRoomModel() const;
Q_INVOKABLE void unselectAll();
Q_INVOKABLE void setFilterFlags(const int& filterFlags);
Q_INVOKABLE void setFilterText(const QString& text);
//Q_INVOKABLE TimelineModel * getTimeline();
signals:
void selectedCountChanged(int selectedCount);
void filterFlagsChanged();
void filterTextChanged();
// void currentChatRoomModelChanged(std::shared_ptr<ChatRoomModel> currentChatRoomModel);
// void currentTimelineChanged(TimelineModel * currentTimeline);
@ -58,7 +76,10 @@ protected:
QString getCleanedLocalAddress () const;
void handleLocalAddressChanged (const QString &localAddress);
private:
int mFilterFlags = 0;
QString mFilterText;
//std::shared_ptr<ChatRoomModel> mCurrentChatRoomModel;
};

View file

@ -28,26 +28,41 @@ void LinphoneEnums::registerMetaTypes(){
qRegisterMetaType<LinphoneEnums::MediaEncryption>();
qRegisterMetaType<LinphoneEnums::FriendCapability>();
qRegisterMetaType<LinphoneEnums::EventLogType>();
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
}
linphone::MediaEncryption LinphoneEnums::toLinphone(const LinphoneEnums::MediaEncryption& encryption){
return static_cast<linphone::MediaEncryption>(encryption);
linphone::MediaEncryption LinphoneEnums::toLinphone(const LinphoneEnums::MediaEncryption& data){
return static_cast<linphone::MediaEncryption>(data);
}
LinphoneEnums::MediaEncryption LinphoneEnums::fromLinphone(const linphone::MediaEncryption& encryption){
return static_cast<LinphoneEnums::MediaEncryption>(encryption);
LinphoneEnums::MediaEncryption LinphoneEnums::fromLinphone(const linphone::MediaEncryption& data){
return static_cast<LinphoneEnums::MediaEncryption>(data);
}
linphone::FriendCapability LinphoneEnums::toLinphone(const LinphoneEnums::FriendCapability& capability){
return static_cast<linphone::FriendCapability>(capability);
linphone::FriendCapability LinphoneEnums::toLinphone(const LinphoneEnums::FriendCapability& data){
return static_cast<linphone::FriendCapability>(data);
}
LinphoneEnums::FriendCapability LinphoneEnums::fromLinphone(const linphone::FriendCapability& capability){
return static_cast<LinphoneEnums::FriendCapability>(capability);
LinphoneEnums::FriendCapability LinphoneEnums::fromLinphone(const linphone::FriendCapability& data){
return static_cast<LinphoneEnums::FriendCapability>(data);
}
linphone::EventLog::Type LinphoneEnums::toLinphone(const LinphoneEnums::EventLogType& capability){
return static_cast<linphone::EventLog::Type>(capability);
linphone::EventLog::Type LinphoneEnums::toLinphone(const LinphoneEnums::EventLogType& data){
return static_cast<linphone::EventLog::Type>(data);
}
LinphoneEnums::EventLogType LinphoneEnums::fromLinphone(const linphone::EventLog::Type& capability){
return static_cast<LinphoneEnums::EventLogType>(capability);
LinphoneEnums::EventLogType LinphoneEnums::fromLinphone(const linphone::EventLog::Type& data){
return static_cast<LinphoneEnums::EventLogType>(data);
}
linphone::ChatMessage::State LinphoneEnums::toLinphone(const LinphoneEnums::ChatMessageState& data){
return static_cast<linphone::ChatMessage::State>(data);
}
LinphoneEnums::ChatMessageState LinphoneEnums::fromLinphone(const linphone::ChatMessage::State& data){
return static_cast<LinphoneEnums::ChatMessageState>(data);
}
linphone::Call::Status LinphoneEnums::toLinphone(const LinphoneEnums::CallStatus& data){
return static_cast<linphone::Call::Status>(data);
}
LinphoneEnums::CallStatus LinphoneEnums::fromLinphone(const linphone::Call::Status& data){
return static_cast<LinphoneEnums::CallStatus>(data);
}

View file

@ -24,6 +24,8 @@
#include <linphone++/linphone.hh>
#include <QObject>
// This namespace is used to pass Linphone enumerators to QML
// =============================================================================
namespace LinphoneEnums {
@ -78,10 +80,45 @@ enum EventLogType {
Q_ENUM_NS(EventLogType)
linphone::EventLog::Type toLinphone(const LinphoneEnums::EventLogType& capability);
LinphoneEnums::EventLogType fromLinphone(const linphone::EventLog::Type& capability);
LinphoneEnums::EventLogType fromLinphone(const linphone::EventLog::Type& data);
enum ChatMessageState {
ChatMessageStateIdle = int(linphone::ChatMessage::State::Idle),
ChatMessageStateInProgress = int(linphone::ChatMessage::State::InProgress),
ChatMessageStateDelivered = int(linphone::ChatMessage::State::Delivered),
ChatMessageStateNotDelivered = int(linphone::ChatMessage::State::NotDelivered),
ChatMessageStateFileTransferError = int(linphone::ChatMessage::State::FileTransferError),
ChatMessageStateFileTransferDone = int(linphone::ChatMessage::State::FileTransferDone),
ChatMessageStateDeliveredToUser = int(linphone::ChatMessage::State::DeliveredToUser),
ChatMessageStateDisplayed = int(linphone::ChatMessage::State::Displayed),
ChatMessageStateFileTransferInProgress = int(linphone::ChatMessage::State::FileTransferInProgress)
};
Q_ENUM_NS(ChatMessageState)
linphone::ChatMessage::State toLinphone(const LinphoneEnums::ChatMessageState& capability);
LinphoneEnums::ChatMessageState fromLinphone(const linphone::ChatMessage::State& capability);
enum CallStatus {
CallStatusDeclined = int(linphone::Call::Status::Declined),
CallStatusMissed = int(linphone::Call::Status::Missed),
CallStatusSuccess = int(linphone::Call::Status::Success),
CallStatusAborted = int(linphone::Call::Status::Aborted),
CallStatusEarlyAborted = int(linphone::Call::Status::EarlyAborted),
CallStatusAcceptedElsewhere = int(linphone::Call::Status::AcceptedElsewhere),
CallStatusDeclinedElsewhere = int(linphone::Call::Status::DeclinedElsewhere)
};
Q_ENUM_NS(CallStatus)
linphone::Call::Status toLinphone(const LinphoneEnums::CallStatus& capability);
LinphoneEnums::CallStatus fromLinphone(const linphone::Call::Status& capability);
}
Q_DECLARE_METATYPE(LinphoneEnums::MediaEncryption)
Q_DECLARE_METATYPE(LinphoneEnums::FriendCapability)
Q_DECLARE_METATYPE(LinphoneEnums::EventLogType)
Q_DECLARE_METATYPE(LinphoneEnums::ChatMessageState)
Q_DECLARE_METATYPE(LinphoneEnums::CallStatus)
#endif

View file

@ -77,6 +77,17 @@ bool Utils::hasCapability(const QString& address, const LinphoneEnums::FriendCap
return false;
}
QString Utils::toDateTimeString(QDateTime date){
return date.toString("yyyy/MM/dd hh:mm:ss");
}
QString Utils::toTimeString(QDateTime date){
return date.toString("hh:mm:ss");
}
QString Utils::toDateString(QDateTime date){
return date.toString("yyyy/MM/dd");
}
QImage Utils::getImage(const QString &pUri) {
QImage image(pUri);
@ -453,7 +464,7 @@ QString Utils::getDisplayName(const std::shared_ptr<const linphone::Address>& ad
if(model && model->getVcardModel())
displayName = model->getVcardModel()->getUsername();
else{
QString displayName = Utils::coreStringToAppString(address->getDisplayName());
displayName = Utils::coreStringToAppString(address->getDisplayName());
if(displayName == "")
displayName = Utils::coreStringToAppString(address->getUsername());
}

View file

@ -25,6 +25,7 @@
#include <QString>
#include <QLocale>
#include <QImage>
#include <QDateTime>
#include <linphone++/address.hh>
@ -52,7 +53,9 @@ public:
Utils(QObject * parent = nullptr) : QObject(parent){}
// Qt interfaces
Q_INVOKABLE static bool hasCapability(const QString& address, const LinphoneEnums::FriendCapability& capability);
Q_INVOKABLE static QString toDateTimeString(QDateTime date);
Q_INVOKABLE static QString toTimeString(QDateTime date);
Q_INVOKABLE static QString toDateString(QDateTime date);
//----------------------------------------------------------------------------------
static constexpr char WindowIconPath[] = ":/assets/images/linphone_logo.svg";

View file

@ -0,0 +1,71 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ChatRoomInitializer.hpp"
#include <QObject>
#include "components/core/CoreManager.hpp"
#include "components/core/CoreHandlers.hpp"
// =============================================================================
ChatRoomInitializer::ChatRoomInitializer(){}
ChatRoomInitializer::~ChatRoomInitializer(){}
void ChatRoomInitializer::onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
if(mAdmins.size() > 0){
setAdminsSync(chatRoom, mAdmins);
}
chatRoom->removeListener(mSelf);
mSelf = nullptr;
}
void ChatRoomInitializer::setAdminsSync(const std::shared_ptr<linphone::ChatRoom> & chatRoom, QList< std::shared_ptr<linphone::Address>> admins){
std::list<std::shared_ptr<linphone::Participant>> chatRoomParticipants = chatRoom->getParticipants();
for(auto participant : chatRoomParticipants){
auto address = participant->getAddress();
auto isAdmin = std::find_if(admins.begin(), admins.end(), [address](std::shared_ptr<linphone::Address> addr){
return addr->weakEqual(address);
});
if( isAdmin != admins.end()){
chatRoom->setParticipantAdminStatus(participant, true);
}
}
}
void ChatRoomInitializer::setAdminsAsync(const std::string& subject, const linphone::ChatRoomBackend& backend, const bool& groupEnabled, QList< std::shared_ptr<linphone::Address>> admins){
QObject * context = new QObject();
QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::chatRoomStateChanged,
context,[context, admins, subject, backend, groupEnabled](const std::shared_ptr<linphone::ChatRoom> &chatRoomEvent,linphone::ChatRoom::State state){
auto params = chatRoomEvent->getCurrentParams();
if( subject == chatRoomEvent->getSubject() && backend == params->getBackend() && groupEnabled == params->groupEnabled()){
if( state == linphone::ChatRoom::State::Created){
std::shared_ptr<ChatRoomInitializer> init = std::make_shared<ChatRoomInitializer>();
init->mAdmins = admins;
init->mSelf = init;
chatRoomEvent->addListener(init);
delete context;
}else if( state > linphone::ChatRoom::State::Created){// The chat room could be completed. Delete the bind.
delete context;
}
}
});
}

View file

@ -0,0 +1,54 @@
/*
* Copyright (c) 2021 Belledonne Communications SARL.
*
* This file is part of linphone-desktop
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CHAT_ROOM_INITIALIZER_H_
#define CHAT_ROOM_INITIALIZER_H_
// Update Admin. We need this hack in order to set parameters without touching on ChatRoom from createChatRoom.
// If something protect the return ChatRoom (like with shared pointer), the future behaviour will be unstable (2 internal instances, wrong ChatRoom objects from callbacks and crash on deletion)
// Thus, we cannot bind to ChatRoom callbacks at the moment of creation and we need to wait for onChatRoomStateChanged from Core Listener and then, react to linphone::ChatRoom::State::Created from the new ChatRoom.
// As we cannot compare exactly the right ChatRoom, we test on subject and parameters that should be enough to be unique at the moment of the creation.
// This is not a 100% (we may protect with a one-time creation) but this workaround should be enough.
// Used on Core::createChatRoom()
#include <linphone++/linphone.hh>
#include <QList>
// =============================================================================
class ChatRoomInitializer : public linphone::ChatRoomListener{
public:
ChatRoomInitializer();
~ChatRoomInitializer();
QList< std::shared_ptr<linphone::Address>> mAdmins;
std::shared_ptr<ChatRoomInitializer> mSelf;
virtual void onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) override;
// Sync : Set Admins to chat room without binding anything (eg. do not wait for any callback and use ChatRoom directly)
static void setAdminsSync(const std::shared_ptr<linphone::ChatRoom> & chatRoom, QList< std::shared_ptr<linphone::Address>> admins);
// Async : Bind to core for onChatRoomStateChanged event and then wait of linphone::ChatRoom::State::Created from ChatRoom listener.
static void setAdminsAsync(const std::string& subject, const linphone::ChatRoomBackend& backend, const bool& groupEnabled, QList< std::shared_ptr<linphone::Address>> admins);
};
#endif

View file

@ -0,0 +1,2 @@
This folder regroup all hacks needed for unexpected behaviour.
The goal is to know more esealy what strange things have been done that could be resolved from SDK fixes.

View file

@ -0,0 +1,8 @@
pragma Singleton
import QtQml 2.2
// =============================================================================
QtObject {
property real dp: 1.0
}

View file

@ -0,0 +1,7 @@
# ==============================================================================
# Tools component to export.
# ==============================================================================
module Tools
singleton Tools 1.0 Tools.qml

View file

@ -21,6 +21,6 @@ DialogPlus {
buttonsAlignment: Qt.AlignCenter
height: DialogStyle.confirmDialog.height
height: DialogStyle.confirmDialog.height + 30
width: DialogStyle.confirmDialog.width
}

View file

@ -16,6 +16,7 @@ Rectangle {
property alias descriptionText: description.text // Optionnal.
property int buttonsAlignment : Qt.AlignLeft
property bool flat : false // Remove margins
property alias showCloseCross : titleBar.showCloseCross
default property alias _content: content.data
property bool _disableExitStatus
@ -62,6 +63,7 @@ Rectangle {
DialogTitle{
id:titleBar
//Layout.fillHeight: dialog.contentIsEmpty
showCloseCross:dialog.showCloseCross
Layout.fillWidth: true
onClose: exitStatus(0)
@ -83,16 +85,16 @@ Rectangle {
Layout.rightMargin: (flat ? 0 : DialogStyle.content.rightMargin)
}
Row {
RowLayout {
id: buttons
Layout.alignment: buttonsAlignment
Layout.bottomMargin: DialogStyle.buttons.bottomMargin
Layout.leftMargin: buttonsAlignment == Qt.AlignLeft
Layout.leftMargin: (buttonsAlignment & Qt.AlignLeft )== Qt.AlignLeft
? DialogStyle.buttons.leftMargin
: buttonsAlignment == Qt.AlignRight
: (buttonsAlignment & Qt.AlignRight) == Qt.AlignRight
? DialogStyle.buttons.rightMargin
: undefined
: DialogStyle.buttons.leftMargin
Layout.rightMargin: DialogStyle.buttons.rightMargin
Layout.topMargin: DialogStyle.buttons.topMargin
spacing: DialogStyle.buttons.spacing

Some files were not shown because too many files have changed in this diff Show more