mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-05-06 20:23:08 +00:00
Merge branch 'release/5.0'
This commit is contained in:
commit
63127c633b
118 changed files with 1482 additions and 797 deletions
|
|
@ -5,7 +5,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## 5.0.0 - [undefined]
|
||||
## 5.0.0 - 2022-12-07
|
||||
|
||||
### Added
|
||||
- Video conference and iCalendars.
|
||||
|
|
@ -13,8 +13,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- New call layouts.
|
||||
- Display a waiting room before going into a conference.
|
||||
- Log viewer.
|
||||
- Read contacts from all friends lists.
|
||||
- Option to set the display name in "using an account" tab of assistant.
|
||||
- Long pressed buttons.
|
||||
- Date and Time pickers.
|
||||
- Phone dialpad on main window.
|
||||
- Animated file in chats/notifications.
|
||||
- Round progress bar for transferring a file and allow to cancel it.
|
||||
|
|
@ -25,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Mark as Read synchronized between devices.
|
||||
- Merge messages into one notification to avoid spam.
|
||||
- Design overhaul on calls.
|
||||
- Audio devices can be changed while being in call.
|
||||
- Use a cryptographic checksum when downloading openH264 from CISCO (Update to 2.2.0)
|
||||
|
||||
### Fixed
|
||||
|
|
|
|||
|
|
@ -204,6 +204,7 @@ set(SOURCES
|
|||
src/components/core/event-count-notifier/AbstractEventCountNotifier.cpp
|
||||
src/components/file/FileDownloader.cpp
|
||||
src/components/file/FileExtractor.cpp
|
||||
src/components/friend/FriendListListener.cpp
|
||||
src/components/history/HistoryModel.cpp
|
||||
src/components/history/HistoryProxyModel.cpp
|
||||
src/components/ldap/LdapModel.cpp
|
||||
|
|
@ -338,6 +339,7 @@ set(HEADERS
|
|||
src/components/core/event-count-notifier/AbstractEventCountNotifier.hpp
|
||||
src/components/file/FileDownloader.hpp
|
||||
src/components/file/FileExtractor.hpp
|
||||
src/components/friend/FriendListListener.hpp
|
||||
src/components/history/HistoryModel.hpp
|
||||
src/components/history/HistoryProxyModel.hpp
|
||||
src/components/ldap/LdapModel.hpp
|
||||
|
|
|
|||
|
|
@ -25,3 +25,4 @@ do
|
|||
inkscape -z -e hicolor/${i}x${i}/apps/icon.png -w $i -h $i ../images/linphone_logo.svg
|
||||
done
|
||||
convert hicolor/16x16/apps/icon.png hicolor/22x22/apps/icon.png hicolor/24x24/apps/icon.png hicolor/32x32/apps/icon.png hicolor/64x64/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png -colors 256 ../icon.ico
|
||||
png2icns ../../cmake_builder/linphone_package/macos/linphone.icns hicolor/16x16/apps/icon.png hicolor/32x32/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png
|
||||
|
|
|
|||
|
|
@ -25,3 +25,4 @@ do
|
|||
inkscape -z --export-type=png --export-file=hicolor/${i}x${i}/apps/icon.png -w $i -h $i ../images/linphone_logo.svg
|
||||
done
|
||||
convert hicolor/16x16/apps/icon.png hicolor/22x22/apps/icon.png hicolor/24x24/apps/icon.png hicolor/32x32/apps/icon.png hicolor/64x64/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png -colors 256 ../icon.ico
|
||||
png2icns ../../cmake_builder/linphone_package/macos/linphone.icns hicolor/16x16/apps/icon.png hicolor/32x32/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png
|
||||
|
|
|
|||
|
|
@ -25,3 +25,4 @@ do
|
|||
inkscape -z --export-type=png --export-filename=hicolor/${i}x${i}/apps/icon.png -w $i -h $i ../images/linphone_logo.svg
|
||||
done
|
||||
convert hicolor/16x16/apps/icon.png hicolor/22x22/apps/icon.png hicolor/24x24/apps/icon.png hicolor/32x32/apps/icon.png hicolor/64x64/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png -colors 256 ../icon.ico
|
||||
png2icns ../../cmake_builder/linphone_package/macos/linphone.icns hicolor/16x16/apps/icon.png hicolor/32x32/apps/icon.png hicolor/128x128/apps/icon.png hicolor/256x256/apps/icon.png
|
||||
|
|
|
|||
|
|
@ -3,16 +3,19 @@
|
|||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg21"
|
||||
id="svg8"
|
||||
sodipodi:docname="chat_room_custom.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview23"
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
|
|
@ -20,57 +23,31 @@
|
|||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
width="30px"
|
||||
inkscape:zoom="5.659091"
|
||||
inkscape:cx="-9.6305219"
|
||||
inkscape:cy="24.738955"
|
||||
inkscape:zoom="6.9166667"
|
||||
inkscape:cx="15.180723"
|
||||
inkscape:cy="22.987952"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg21" />
|
||||
<defs
|
||||
id="defs5">
|
||||
<filter
|
||||
id="d1wmealema"
|
||||
color-interpolation-filters="auto"
|
||||
x="0"
|
||||
y="0"
|
||||
width="1"
|
||||
height="1">
|
||||
<feColorMatrix
|
||||
in="SourceGraphic"
|
||||
values="0 0 0 0 0.349020 0 0 0 0 0.341176 0 0 0 0 0.349020 0 0 0 1.000000 0"
|
||||
id="feColorMatrix2" />
|
||||
</filter>
|
||||
</defs>
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g19"
|
||||
transform="matrix(0.91808004,0,0,0.97218937,14.299365,21.746553)">
|
||||
<g
|
||||
id="g17">
|
||||
<g
|
||||
id="g15">
|
||||
<g
|
||||
filter="url(#d1wmealema)"
|
||||
transform="translate(0.763635,0.775)"
|
||||
id="g13">
|
||||
<g
|
||||
fill="#000000"
|
||||
fill-rule="nonzero"
|
||||
id="g11">
|
||||
<path
|
||||
d="m 45.911,13.38 c 1.019,0 2,-0.213 2.882,-0.616 0.049,-0.022 0.098,-0.04 0.149,-0.055 0.06,-0.018 0.21,-0.075 0.417,-0.178 0.362,-0.18 0.727,-0.419 1.066,-0.723 0.294,-0.264 0.555,-0.565 0.775,-0.906 0.432,-0.67 0.709,-1.305 0.864,-1.88 0.052,-0.19 0.085,-0.358 0.104,-0.498 L 52.18,8.419 52.185,8.326 c 0.018,-0.169 0.026,-0.34 0.026,-0.51 0,-3.046 -2.796,-5.566 -6.3,-5.566 -3.503,0 -6.3,2.52 -6.3,5.565 0,1.452 0.633,2.82 1.758,3.855 0.181,0.166 0.302,0.388 0.346,0.63 l 0.013,0.075 c 0.157,0.635 0.156,1.22 0.026,1.752 0.291,-0.182 0.532,-0.363 0.74,-0.542 0.071,-0.06 0.132,-0.116 0.184,-0.166 l 0.043,-0.041 0.028,-0.028 0.032,-0.03 C 42.8,13.303 42.8,13.303 42.887,13.235 l 0.1,-0.063 0.849,-0.1 c 0.678,0.206 1.367,0.308 2.075,0.308 z m 0,2.25 c -0.707,0 -1.404,-0.078 -2.077,-0.232 -0.258,0.213 -0.545,0.422 -0.86,0.62 -1.44,0.905 -3.045,1.324 -4.733,0.947 -1.135,-0.253 -1.186,-1.852 -0.07,-2.178 0.027,-0.008 0.105,-0.035 0.216,-0.083 0.193,-0.084 0.386,-0.19 0.56,-0.315 0.5,-0.359 0.72,-0.756 0.628,-1.324 -1.41,-1.421 -2.214,-3.275 -2.214,-5.25 0,-4.343 3.853,-7.815 8.55,-7.815 4.697,0 8.55,3.472 8.55,7.815 0,0.235 -0.01,0.468 -0.033,0.7 -0.011,0.253 -0.065,0.625 -0.192,1.095 -0.214,0.794 -0.585,1.641 -1.145,2.51 -0.332,0.516 -0.725,0.969 -1.164,1.363 -0.5,0.448 -1.032,0.798 -1.568,1.064 -0.283,0.14 -0.521,0.236 -0.696,0.293 -1.159,0.518 -2.435,0.79 -3.752,0.79 z M 42.454,5.506 h 6.895 c 1.5,0 1.5,2.25 0,2.25 h -6.895 c -1.5,0 -1.5,-2.25 0,-2.25 z m 0,2.818 h 6.895 c 1.5,0 1.5,2.25 0,2.25 h -6.895 c -1.5,0 -1.5,-2.25 0,-2.25 z M 8.671,32.229 c 2.257,0.675 4.576,1.106 6.87,1.336 1.674,0.167 3.097,0.207 4.157,0.177 0.104,-0.003 0.173,-0.006 0.203,-0.008 l 0.209,-0.002 0.265,0.01 c 1.06,0.03 2.483,-0.01 4.156,-0.177 2.295,-0.23 4.614,-0.66 6.87,-1.336 0.34,-1.838 0.01,-3.916 -1.507,-5.904 -1.151,-1.51 -2.924,-2.845 -5.428,-3.946 -0.064,-0.028 -0.124,-0.061 -0.181,-0.1 l -0.274,-0.187 c -0.607,-0.413 -0.662,-1.287 -0.112,-1.773 0.087,-0.103 0.105,-0.125 0.185,-0.21 0.944,-1.019 1.478,-2.356 1.478,-3.782 0,-3.055 -2.448,-5.527 -5.463,-5.527 h -0.126 c -3.014,0 -5.462,2.472 -5.462,5.527 0,1.426 0.534,2.763 1.48,3.783 0.079,0.086 0.092,0.102 0.163,0.193 0.57,0.5 0.516,1.377 -0.093,1.79 l -0.276,0.187 c -0.056,0.038 -0.116,0.071 -0.178,0.099 -2.504,1.1 -4.277,2.437 -5.428,3.946 -1.517,1.988 -1.848,4.066 -1.508,5.904 z m 11.32,3.753 -0.229,0.009 c -1.151,0.033 -2.67,-0.01 -4.444,-0.187 C 12.671,35.539 9.992,35.021 7.388,34.187 7.05,34.079 6.784,33.818 6.668,33.484 6.615,33.33 6.545,33.081 6.48,32.747 5.999,30.307 6.414,27.55 8.39,24.96 c 1.217,-1.596 2.96,-2.995 5.276,-4.155 -0.905,-1.294 -1.405,-2.848 -1.405,-4.478 0,-4.293 3.45,-7.777 7.712,-7.777 h 0.126 c 4.263,0 7.713,3.484 7.713,7.777 0,1.63 -0.5,3.183 -1.406,4.478 2.316,1.16 4.06,2.56 5.277,4.155 1.976,2.59 2.39,5.347 1.91,7.787 -0.066,0.334 -0.135,0.583 -0.188,0.737 -0.116,0.334 -0.383,0.595 -0.72,0.703 -2.604,0.834 -5.284,1.352 -7.93,1.617 -1.775,0.177 -3.294,0.22 -4.445,0.187 l -0.228,-0.009 z"
|
||||
id="path7" />
|
||||
<path
|
||||
d="m 27.704,16.327 c 0,1.63 -0.5,3.183 -1.405,4.478 3.468,1.736 5.623,3.985 6.655,6.56 1.97,-0.151 4.02,-0.496 6.038,-1.09 0.223,-1.387 -0.052,-2.942 -1.193,-4.437 -0.901,-1.181 -2.296,-2.232 -4.275,-3.102 -0.063,-0.028 -0.123,-0.061 -0.18,-0.1 l -0.221,-0.15 c -0.607,-0.414 -0.662,-1.288 -0.111,-1.774 0.049,-0.062 0.069,-0.085 0.132,-0.153 0.721,-0.778 1.129,-1.799 1.129,-2.889 0,-2.333 -1.868,-4.22 -4.168,-4.22 h -0.102 c -1.611,0 -3.048,0.935 -3.739,2.35 0.928,1.306 1.44,2.878 1.44,4.527 z m 5.278,0.423 0.002,-0.001 z m -7.719,3.57 -0.452,1.03 0.633,-0.93 -0.085,-0.058 c -0.031,-0.015 -0.063,-0.029 -0.096,-0.043 z m -1.287,-0.211 c 0.945,-1.019 1.478,-2.356 1.478,-3.782 0,-1.348 -0.476,-2.617 -1.33,-3.615 -0.255,-0.299 -0.336,-0.71 -0.213,-1.083 C 24.775,9.007 27.216,7.2 30.003,7.2 h 0.102 c 3.547,0 6.418,2.9 6.418,6.47 0,1.269 -0.364,2.482 -1.028,3.515 1.78,0.925 3.133,2.03 4.093,3.289 1.631,2.137 1.974,4.416 1.576,6.434 -0.054,0.279 -0.113,0.489 -0.159,0.622 -0.116,0.334 -0.382,0.594 -0.72,0.702 -2.702,0.866 -5.457,1.303 -8.056,1.432 -0.517,0.026 -0.985,-0.306 -1.133,-0.802 -0.755,-2.53 -2.838,-4.77 -6.738,-6.483 -0.063,-0.028 -0.124,-0.061 -0.18,-0.1 l -0.275,-0.187 c -0.607,-0.413 -0.661,-1.287 -0.111,-1.773 0.086,-0.103 0.105,-0.125 0.184,-0.21 z m -10.31,0.696 c -0.905,-1.294 -1.405,-2.848 -1.405,-4.478 0,-2.066 0.805,-4 2.192,-5.432 C 13.675,9.992 12.54,9.45 11.312,9.45 H 11.21 c -2.3,0 -4.168,1.887 -4.168,4.22 0,1.09 0.408,2.111 1.13,2.89 0.064,0.069 0.08,0.088 0.13,0.15 0.553,0.486 0.498,1.363 -0.111,1.777 l -0.221,0.15 c -0.057,0.038 -0.117,0.071 -0.18,0.099 -1.978,0.87 -3.373,1.92 -4.274,3.102 -1.14,1.495 -1.416,3.05 -1.193,4.438 1.561,0.458 3.157,0.771 4.741,0.96 1.053,-2.522 3.194,-4.725 6.602,-6.431 z M 8.333,16.75 8.332,16.748 v 0.002 z m 6.19,3.667 0.63,0.931 -0.452,-1.03 -0.095,0.042 -0.084,0.057 z m 1.538,1.675 -0.276,0.187 C 15.729,22.317 15.669,22.35 15.607,22.378 11.752,24.072 9.671,26.281 8.894,28.78 8.737,29.287 8.246,29.615 7.717,29.566 5.495,29.362 3.232,28.936 1.03,28.231 0.693,28.123 0.426,27.863 0.31,27.529 0.264,27.396 0.206,27.186 0.15,26.907 -0.247,24.888 0.096,22.61 1.727,20.473 2.687,19.214 4.04,18.108 5.82,17.183 5.157,16.151 4.792,14.938 4.792,13.669 c 0,-3.57 2.871,-6.47 6.418,-6.47 h 0.102 c 2.356,0 4.486,1.29 5.61,3.325 0.267,0.483 0.144,1.089 -0.29,1.43 -1.329,1.04 -2.121,2.638 -2.121,4.372 0,1.426 0.534,2.763 1.48,3.783 0.079,0.086 0.092,0.102 0.163,0.193 0.57,0.5 0.516,1.377 -0.093,1.79 z"
|
||||
id="path9" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
id="g832"
|
||||
transform="matrix(0.67345025,0,0,0.67345025,9.9999997,20)">
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 33.7385,59.5539 c -5.4936,-0.5499 -11.046,-1.5836 -16.4472,-3.2018 -0.8149,-4.4048 -0.0225,-9.3836 3.6084,-14.1483 2.756,-3.6166 7.0003,-6.8186 12.9943,-9.456 0.1497,-0.0658 0.2931,-0.1452 0.4285,-0.2371 l 0.6594,-0.4479 c 1.4585,-0.9906 1.5891,-3.0935 0.2234,-4.291 C 35.0358,27.5543 35.0033,27.5167 34.813,27.3106 32.5497,24.8668 31.2713,21.6615 31.2713,18.2449 31.2713,10.924 37.1314,5 44.3466,5 h 0.3033 c 7.2171,0 13.0769,5.9235 13.0769,13.2449 0,3.4172 -1.278,6.6224 -3.5383,9.063 -0.1905,0.2048 -0.2352,0.2573 -0.4418,0.5031 -1.3173,1.1642 -1.186,3.2589 0.2664,4.2491 L 54.67,32.508 c 0.1365,0.0931 0.2813,0.1734 0.4325,0.2399 5.9945,2.6373 10.2391,5.8394 12.9953,9.456 3.6313,4.7647 4.4238,9.7434 3.609,14.1482 -5.4018,1.6182 -10.9545,2.6519 -16.4482,3.2018 -4.0055,0.4008 -7.4119,0.4967 -9.9495,0.4236 -0.1865,-0.0054 -0.3252,-0.0106 -0.4752,-0.0162 -0.0509,-0.002 -0.1031,-0.0039 -0.1589,-0.006 l -0.4995,0.0041 c -0.0734,0.004 -0.2375,0.0109 -0.4874,0.0181 -2.5377,0.0731 -5.9441,-0.0228 -9.9496,-0.4236 z"
|
||||
fill="#444444"
|
||||
id="path2" />
|
||||
<path
|
||||
d="m 62.1606,17.3664 c 0,4.0408 -1.3225,8.2219 -3.5628,11.4314 8.5813,4.3036 11.0776,8.8212 13.6299,15.2022 4.874,-0.3728 11.6211,-1.122 16.5902,-2.8452 0.8014,-4.0073 -0.0642,-8.6958 -3.6707,-12.3023 -2.6641,-2.6641 -4.1035,-4.1096 -8.7036,-6.1351 -0.1563,-0.0689 -0.3481,-0.1803 -0.4891,-0.2766 -1.7232,-0.8015 -2.5246,-1.6029 -2.1239,-3.2058 0,-0.4008 1.021,-1.3364 1.2022,-1.6029 1.4108,-2.0755 2.5647,-3.3516 2.5647,-7.2132 C 77.5975,4.80874 73.2857,0 66.6175,0 61.408,0 57.8015,4.00729 57,7.21311 c 2.2963,3.23579 5.1606,6.06519 5.1606,10.15329 z"
|
||||
fill="#444444"
|
||||
id="path4" />
|
||||
<path
|
||||
d="m 26.8544,17.3664 c 0,4.0408 1.3187,8.2219 3.5525,11.4314 C 21.8505,33.1014 19.3615,37.619 16.8166,44 11.9569,43.6272 5.22934,42.878 0.274772,41.1548 -0.524352,37.1475 0.338703,32.459 3.93476,28.8525 6.59109,26.1884 8.02628,24.7429 12.613,22.7174 c 0.1559,-0.0689 0.347,-0.1803 0.4877,-0.2766 1.7181,-0.8015 2.5173,-1.6029 2.1177,-3.2058 0,-0.4008 -1.018,-1.3364 -1.1987,-1.6029 C 12.613,15.5566 11.4625,14.2805 11.4625,10.4189 11.4625,4.80874 15.7617,0 22.4105,0 27.6048,0 31.2009,4.00729 32,7.21311 29.7104,10.4489 26.8544,13.2783 26.8544,17.3664 Z"
|
||||
fill="#444444"
|
||||
id="path6" />
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 3.4 KiB |
67
linphone-app/assets/images/conference_merge_custom.svg
Normal file
67
linphone-app/assets/images/conference_merge_custom.svg
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
fill="none"
|
||||
version="1.1"
|
||||
id="svg7"
|
||||
sodipodi:docname="conference_merge_custom.svg"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
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="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="5.6283784"
|
||||
inkscape:cx="72.045618"
|
||||
inkscape:cy="45.661464"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg7" />
|
||||
<g
|
||||
id="rassemblement_conf_over_alpha"
|
||||
transform="matrix(0.67228336,0,0,0.66946229,-9.7483237,-10.083869)">
|
||||
<path
|
||||
id="new_conference_default"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 57.542,109.575 c 0.2349,-0.253 0.6303,-0.268 0.8833,-0.033 6.9396,6.444 18.2098,6.444 25.1494,0 0.253,-0.235 0.6484,-0.22 0.8833,0.033 0.2349,0.253 0.2202,0.648 -0.0327,0.883 -7.4192,6.889 -19.4314,6.889 -26.8506,0 -0.2529,-0.235 -0.2676,-0.63 -0.0327,-0.883 z m 8.9776,-1.922 c 0.1435,0.214 0.1402,0.495 -0.0083,0.706 l -6.3268,9 c -0.1399,0.199 -0.3824,0.299 -0.6217,0.256 -0.2393,-0.043 -0.432,-0.221 -0.494,-0.456 l -1.8876,-7.162 c -0.0433,-0.164 -0.0179,-0.339 0.0704,-0.484 0.0883,-0.145 0.2318,-0.248 0.3975,-0.285 l 8.2144,-1.838 c 0.252,-0.056 0.5127,0.048 0.6561,0.263 z m -7.9643,2.653 1.3796,5.235 4.6243,-6.578 z M 50,46.625 c -9.5977,0 -17.375,7.7777 -17.375,17.375 0,0.3452 -0.2798,0.625 -0.625,0.625 -0.3452,0 -0.625,-0.2798 -0.625,-0.625 0,-10.2877 8.3369,-18.625 18.625,-18.625 0.3452,0 0.625,0.2798 0.625,0.625 0,0.3452 -0.2798,0.625 -0.625,0.625 z m -6.3179,-6.1631 c 0.2267,-0.1339 0.5129,-0.1114 0.7158,0.0562 l 6.0312,4.9797 c 0.2459,0.2031 0.2995,0.5587 0.1244,0.8252 l -3.9555,6.0202 c -0.1399,0.2129 -0.3951,0.3196 -0.6449,0.2697 -0.2499,-0.05 -0.4444,-0.2466 -0.4916,-0.497 l -2.0757,-11 c -0.0488,-0.2587 0.0697,-0.5202 0.2963,-0.654 z m 1.2525,2.1203 1.4683,7.7815 2.7982,-4.2588 z M 93.375,46 c 0,-0.3452 0.2798,-0.625 0.625,-0.625 10.286,0 18.625,8.3394 18.625,18.625 0,0.3452 -0.28,0.625 -0.625,0.625 -0.345,0 -0.625,-0.2798 -0.625,-0.625 0,-9.5953 -7.779,-17.375 -17.375,-17.375 -0.3452,0 -0.625,-0.2798 -0.625,-0.625 z m 23.138,11.6424 c 0.14,0.2018 0.15,0.4674 0.023,0.6785 l -3.853,6.4407 c -0.086,0.1431 -0.225,0.246 -0.387,0.2859 -0.162,0.0399 -0.333,0.0135 -0.475,-0.0735 l -7.147,-4.3647 c -0.22,-0.1348 -0.335,-0.3915 -0.289,-0.6459 0.047,-0.2543 0.245,-0.4537 0.499,-0.5017 l 11,-2.0759 c 0.242,-0.0456 0.488,0.0549 0.629,0.2566 z m -9.801,2.7465 5.222,3.1896 2.816,-4.7066 z"
|
||||
fill="#000000"
|
||||
stroke="#000000"
|
||||
stroke-width="4"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path
|
||||
id="chat_group_new"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 47.171,101.988 c 0.1201,-0.004 0.212,-0.007 0.2743,-0.01 h 0.109 c 0.0623,0.003 0.1542,0.006 0.2743,0.01 1.3829,0.039 3.2061,-0.012 5.3379,-0.225 3.178,-0.318 6.3965,-0.942 9.5244,-1.9443 0.4048,-0.1297 0.725,-0.4426 0.8643,-0.8446 0.0641,-0.1846 0.147,-0.4846 0.2259,-0.8858 0.5774,-2.9339 0.0789,-6.2473 -2.2942,-9.361 -1.4622,-1.9186 -3.5553,-3.6001 -6.3368,-4.995 C 56.2374,82.1758 56.838,80.3087 56.838,78.349 56.838,73.1884 52.6946,69 47.5757,69 h -0.1522 c -5.1179,0 -9.2615,4.1887 -9.2615,9.349 0,1.9599 0.601,3.8273 1.6879,5.3829 -2.7817,1.395 -4.8749,3.0766 -6.3372,4.9955 -2.3728,3.1136 -2.8711,6.427 -2.2938,9.3609 0.0789,0.4012 0.1619,0.7012 0.2259,0.8858 0.1393,0.402 0.4595,0.7148 0.8643,0.8446 3.1276,1.0023 6.3459,1.6263 9.5239,1.9443 2.1318,0.213 3.955,0.264 5.338,0.225 z m -4.5622,-4.1908 c -2.497,-0.2499 -5.0209,-0.7198 -7.476,-1.4553 -0.3703,-2.0022 -0.0102,-4.2653 1.6402,-6.4311 1.2528,-1.6439 3.182,-3.0994 5.9065,-4.2981 0.0681,-0.03 0.1333,-0.0661 0.1948,-0.1078 l 0.2997,-0.2036 c 0.663,-0.4503 0.7223,-1.4062 0.1016,-1.9505 -0.0771,-0.0989 -0.0918,-0.1159 -0.1783,-0.2096 -1.0288,-1.1108 -1.6099,-2.5678 -1.6099,-4.1208 0,-3.3277 2.6637,-6.0204 5.9433,-6.0204 h 0.1379 c 3.2805,0 5.944,2.6925 5.944,6.0204 0,1.5533 -0.5809,3.0102 -1.6083,4.1196 -0.0866,0.093 -0.1069,0.1169 -0.2008,0.2286 -0.5988,0.5292 -0.5391,1.4814 0.1211,1.9315 l 0.2986,0.2035 c 0.062,0.0423 0.1278,0.0788 0.1965,0.1091 2.7248,1.1988 4.6542,2.6543 5.907,4.2981 1.6506,2.1658 2.0108,4.4289 1.6405,6.4311 -2.4554,0.7355 -4.9794,1.2054 -7.4765,1.4553 -1.8207,0.1822 -3.369,0.2258 -4.5225,0.1926 -0.0846,-0.0025 -0.1476,-0.0048 -0.2157,-0.0074 -0.0232,-9e-4 -0.047,-0.0018 -0.0725,-0.0027 l -0.2271,0.0018 c -0.0333,0.0018 -0.1079,0.005 -0.2215,0.0083 -1.1535,0.0332 -2.7019,-0.0104 -4.5226,-0.1926 z"
|
||||
fill="#000000" />
|
||||
<path
|
||||
id="chat_group_new_2"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 100.171,101.988 c 0.12,-0.004 0.212,-0.007 0.274,-0.01 h 0.109 c 0.063,0.003 0.154,0.006 0.275,0.01 1.383,0.039 3.206,-0.012 5.337,-0.225 3.179,-0.318 6.397,-0.942 9.525,-1.9443 0.405,-0.1297 0.725,-0.4426 0.864,-0.8446 0.064,-0.1846 0.147,-0.4846 0.226,-0.8858 0.577,-2.9339 0.079,-6.2473 -2.294,-9.361 -1.462,-1.9186 -3.555,-3.6001 -6.337,-4.995 1.087,-1.5565 1.688,-3.4236 1.688,-5.3833 0,-5.1606 -4.143,-9.349 -9.262,-9.349 h -0.152 c -5.1184,0 -9.262,4.1887 -9.262,9.349 0,1.9599 0.601,3.8273 1.6879,5.3829 -2.7817,1.395 -4.8749,3.0766 -6.3372,4.9955 -2.3728,3.1136 -2.8711,6.427 -2.2938,9.3609 0.0789,0.4012 0.1619,0.7012 0.2259,0.8858 0.1393,0.402 0.4595,0.7148 0.8643,0.8446 3.1276,1.0023 6.3459,1.6263 9.5239,1.9443 2.1318,0.213 3.955,0.264 5.338,0.225 z m -4.5622,-4.1908 c -2.497,-0.2499 -5.0209,-0.7198 -7.476,-1.4553 -0.3703,-2.0022 -0.0102,-4.2653 1.6402,-6.4311 1.2528,-1.6439 3.182,-3.0994 5.9065,-4.2981 0.0681,-0.03 0.1333,-0.0661 0.1948,-0.1078 l 0.2997,-0.2036 c 0.663,-0.4503 0.7223,-1.4062 0.1016,-1.9505 -0.0771,-0.0989 -0.0918,-0.1159 -0.1783,-0.2096 -1.0288,-1.1108 -1.6099,-2.5678 -1.6099,-4.1208 0,-3.3277 2.6637,-6.0204 5.9436,-6.0204 h 0.138 c 3.28,0 5.944,2.6925 5.944,6.0204 0,1.5533 -0.581,3.0102 -1.609,4.1196 -0.086,0.093 -0.107,0.1169 -0.201,0.2286 -0.598,0.5292 -0.539,1.4814 0.122,1.9315 l 0.298,0.2035 c 0.062,0.0423 0.128,0.0788 0.197,0.1091 2.725,1.1988 4.654,2.6543 5.907,4.2981 1.65,2.1658 2.011,4.4289 1.64,6.4311 -2.455,0.7355 -4.979,1.2054 -7.476,1.4553 -1.821,0.1822 -3.369,0.2258 -4.523,0.1926 -0.084,-0.0025 -0.147,-0.0048 -0.215,-0.0074 -0.024,-9e-4 -0.048,-0.0018 -0.073,-0.0027 l -0.227,0.0018 c -0.033,0.0018 -0.108,0.005 -0.222,0.0083 -1.1531,0.0332 -2.7015,-0.0104 -4.5222,-0.1926 z"
|
||||
fill="#000000" />
|
||||
<path
|
||||
id="chat_group_new_3"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="m 73.171,62.9876 c 0.1201,-0.0035 0.212,-0.007 0.2743,-0.01 h 0.109 c 0.0623,0.003 0.1542,0.0065 0.2743,0.01 1.3829,0.0399 3.2061,-0.0115 5.3379,-0.2248 3.178,-0.3181 6.3965,-0.9415 9.5244,-1.9441 0.4048,-0.1297 0.725,-0.4426 0.8643,-0.8446 0.0641,-0.1846 0.147,-0.4846 0.2259,-0.8858 0.5774,-2.9339 0.0789,-6.2473 -2.2942,-9.361 -1.4622,-1.9186 -3.5553,-3.6001 -6.3368,-4.995 C 82.2374,43.1758 82.838,41.3087 82.838,39.349 82.838,34.1884 78.6946,30 73.5757,30 h -0.1522 c -5.1179,0 -9.2615,4.1887 -9.2615,9.349 0,1.9599 0.601,3.8273 1.6879,5.3829 -2.7817,1.395 -4.8749,3.0766 -6.3372,4.9955 -2.3728,3.1136 -2.8711,6.427 -2.2938,9.3609 0.0789,0.4012 0.1619,0.7012 0.2259,0.8858 0.1393,0.402 0.4595,0.7148 0.8643,0.8446 3.1276,1.0026 6.3459,1.626 9.5239,1.9441 2.1318,0.2133 3.955,0.2647 5.338,0.2248 z m -4.5622,-4.1904 c -2.497,-0.2499 -5.0209,-0.7198 -7.476,-1.4553 -0.3703,-2.0022 -0.0102,-4.2653 1.6402,-6.4311 1.2528,-1.6439 3.182,-3.0994 5.9065,-4.2981 0.0681,-0.03 0.1333,-0.0661 0.1948,-0.1078 l 0.2997,-0.2036 c 0.663,-0.4503 0.7223,-1.4062 0.1016,-1.9505 -0.0771,-0.0989 -0.0918,-0.1159 -0.1783,-0.2096 -1.0288,-1.1108 -1.6099,-2.5678 -1.6099,-4.1208 0,-3.3277 2.6637,-6.0204 5.9433,-6.0204 h 0.1379 c 3.2805,0 5.944,2.6925 5.944,6.0204 0,1.5533 -0.5809,3.0102 -1.6083,4.1196 -0.0866,0.093 -0.1069,0.1169 -0.2008,0.2286 -0.5988,0.5292 -0.5391,1.4814 0.1211,1.9315 l 0.2986,0.2035 c 0.062,0.0423 0.1278,0.0788 0.1965,0.1091 2.7248,1.1988 4.6542,2.6543 5.907,4.2981 1.6506,2.1658 2.0108,4.4289 1.6405,6.4311 -2.4554,0.7355 -4.9794,1.2054 -7.4765,1.4553 -1.8207,0.1822 -3.369,0.2258 -4.5225,0.1926 -0.0846,-0.0025 -0.1476,-0.0048 -0.2157,-0.0074 -0.0232,-9e-4 -0.047,-0.0018 -0.0725,-0.0027 l -0.2271,0.0018 c -0.0333,0.0018 -0.1079,0.005 -0.2215,0.0083 -1.1535,0.0332 -2.7019,-0.0104 -4.5226,-0.1926 z"
|
||||
fill="#000000" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.8 KiB |
|
|
@ -1,49 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="80"
|
||||
height="80"
|
||||
viewBox="0 0 80 80"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="menu_forward_custom.svg"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs12" />
|
||||
<sodipodi:namedview
|
||||
id="namedview10"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4.85"
|
||||
inkscape:cx="-16.597938"
|
||||
inkscape:cy="43.917526"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1043"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg8" />
|
||||
<g
|
||||
fill="none"
|
||||
fill-rule="evenodd"
|
||||
id="g6"
|
||||
transform="matrix(0.94339623,0,0,0.90909091,15,19.609091)">
|
||||
<g
|
||||
fill="#444444"
|
||||
fill-rule="nonzero"
|
||||
id="g4">
|
||||
<path
|
||||
d="M 24.071,28.481 V 26.72 h 1.625 c 1.553,0 2.931,0.043 4.13,0.126 1.15,0.08 2.294,0.223 3.428,0.429 1.003,0.182 1.83,0.418 2.48,0.697 0.632,0.271 1.22,0.618 1.772,1.046 0.425,0.33 0.759,0.708 1.02,1.15 0.308,0.521 0.571,1.195 0.775,2.03 0.213,0.872 0.325,1.914 0.325,3.123 l -0.003,0.362 c -0.008,0.496 -0.033,1.038 -0.074,1.628 l -0.043,0.548 -0.018,0.125 c -0.073,0.46 -0.113,0.841 -0.113,1.229 0,1.225 0.446,2.401 1.308,3.312 0.95,0.999 2.203,1.475 3.496,1.475 1.48,0 2.772,-0.657 3.687,-1.716 l 0.04,-0.047 c 0.335,-0.388 0.616,-0.814 0.855,-1.277 l 0.245,-0.483 0.418,-0.853 C 51.77,34.91 53,30.994 53,27.76 53,24.254 52.46,21.216 51.328,18.652 l -0.15,-0.324 C 47.572,10.724 38.85,7.2 25.697,7.2 H 24.072 V 5.44 C 24.072,3.882 23.409,2.474 22.265,1.449 21.208,0.503 19.88,0 18.464,0 17.048,0 15.72,0.503 14.664,1.45 L 1.808,12.968 C 0.663,13.996 0,15.403 0,16.96 c 0,1.557 0.664,2.965 1.807,3.99 l 12.858,11.522 c 1.058,0.946 2.385,1.448 3.8,1.448 1.414,0 2.742,-0.502 3.797,-1.446 1.146,-1.027 1.81,-2.436 1.81,-3.994 z M 18.464,4 c 0.436,0 0.812,0.143 1.13,0.428 0.278,0.249 0.435,0.538 0.47,0.868 l 0.007,0.144 v 5.76 h 5.625 c 11.936,0 19.26,3.023 21.973,9.068 0.887,2.01 1.331,4.508 1.331,7.493 0,2.401 -0.989,5.632 -2.965,9.692 l -0.666,1.355 -0.16,0.314 c -0.102,0.196 -0.21,0.36 -0.327,0.496 C 44.681,39.873 44.447,40 44.179,40 c -0.251,0 -0.448,-0.075 -0.59,-0.225 -0.143,-0.15 -0.214,-0.337 -0.214,-0.562 l 0.003,-0.089 0.02,-0.223 0.087,-0.613 0.014,-0.148 0.002,-0.052 c 0.083,-1.02 0.125,-1.942 0.125,-2.767 0,-1.515 -0.147,-2.873 -0.44,-4.073 -0.292,-1.2 -0.698,-2.238 -1.217,-3.116 -0.52,-0.878 -1.189,-1.635 -2.01,-2.273 -0.82,-0.637 -1.703,-1.158 -2.649,-1.563 -0.946,-0.406 -2.06,-0.724 -3.34,-0.957 -1.28,-0.232 -2.57,-0.394 -3.867,-0.484 -1.135,-0.078 -2.402,-0.123 -3.8,-0.132 l -0.607,-0.002 h -5.625 v 5.76 c 0,0.39 -0.159,0.728 -0.477,1.013 -0.318,0.284 -0.695,0.427 -1.13,0.427 -0.38,0 -0.716,-0.11 -1.008,-0.327 L 17.334,29.494 4.477,17.973 C 4.16,17.688 4,17.351 4,16.961 4,16.619 4.122,16.318 4.365,16.057 L 4.477,15.947 17.334,4.427 C 17.652,4.143 18.029,4 18.464,4 Z"
|
||||
transform="matrix(-1,0,0,1,53,0.43)"
|
||||
id="path2" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
|
|
@ -569,6 +569,11 @@ Server url ikke konfigureret.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ Server URL ist nicht konfiguriert.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ Server URL not configured.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation>Do you really want do cancel this meeting?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation>Meeting has been cancelled</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ URL del servidor no configurada.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ URL du serveur non configurée.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation>Voulez-vous supprimer cette réunion ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished">La réunion a été annulée</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -568,6 +568,11 @@ A kiszolgáló URL-je nincs konfigurálva.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ URL del server non configurato.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -568,6 +568,11 @@
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -570,6 +570,11 @@ Nesukonfigūruotas serverio url.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ URL do servidor não configurado.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -570,6 +570,11 @@
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -569,6 +569,11 @@ Serverwebbadressen är inte konfigurerad.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -568,6 +568,11 @@ Sunucu url'si yapılandırılmadı.</translation>
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -570,6 +570,11 @@
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -568,6 +568,11 @@
|
|||
<extracomment>'Do you really want do cancel this meeting?' : Warning message to confirm the cancellation of a meeting.</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>icsCancelledMeetingInvite</source>
|
||||
<extracomment>'Meeting has been cancelled' : ICS Title for cancelled meetings</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatConferenceInvitationMessage</name>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@
|
|||
<file>assets/images/conference_audio_only_custom.svg</file>
|
||||
<file>assets/images/conference_layout_grid_custom.svg</file>
|
||||
<file>assets/images/conference_layout_active_speaker_custom.svg</file>
|
||||
<file>assets/images/conference_merge_custom.svg</file>
|
||||
<file>assets/images/contact_add_custom.svg</file>
|
||||
<file>assets/images/contact_card_photo_custom.svg</file>
|
||||
<file>assets/images/contact_custom.svg</file>
|
||||
|
|
@ -77,7 +78,6 @@
|
|||
<file>assets/images/declined_outgoing_call_custom.svg</file>
|
||||
<file>assets/images/delete_custom.svg</file>
|
||||
<file>assets/images/download_custom.svg</file>
|
||||
<file>assets/images/draft_custom.svg</file>
|
||||
<file>assets/images/drop_down_custom.svg</file>
|
||||
<file>assets/images/edit_custom.svg</file>
|
||||
<file>assets/images/ended_call_custom.svg</file>
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static inline bool installLocale (App &app, QTranslator &translator, const QLoca
|
|||
}
|
||||
|
||||
static inline string getConfigPathIfExists (const QCommandLineParser &parser) {
|
||||
QString filePath = parser.value("config");
|
||||
QString filePath = parser.isSet("config") ? parser.value("config") : "";
|
||||
string configPath;
|
||||
if(!QUrl(filePath).isRelative()){
|
||||
configPath = Utils::appStringToCoreString(FileDownloader::synchronousDownload(filePath, Utils::coreStringToAppString(Paths::getConfigDirPath(false)), true));
|
||||
|
|
@ -217,12 +217,21 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U
|
|||
}
|
||||
bctbx_set_default_encoding(Constants::LinphoneLocaleEncoding);// Use UTF-8 for internals. Linphone uses UTF-8 so there will be no loss on data with less precise encodings. Qt will do the rest.
|
||||
|
||||
|
||||
createParser();
|
||||
mParser->parse(this->arguments());
|
||||
// Get configuration for translators
|
||||
shared_ptr<linphone::Config> config = Utils::getConfigIfExists (QString::fromStdString(getConfigPathIfExists(*mParser)));
|
||||
|
||||
// Init locale.
|
||||
mTranslator = new DefaultTranslator(this);
|
||||
mDefaultTranslator = new DefaultTranslator(this);
|
||||
initLocale(config);
|
||||
Logger::init(config);
|
||||
|
||||
createParser();// Recreate parser in order to use translations from config.
|
||||
mParser->process(*this);
|
||||
|
||||
// Initialize logger.
|
||||
shared_ptr<linphone::Config> config = Utils::getConfigIfExists (QString::fromStdString(getConfigPathIfExists(*mParser)));
|
||||
Logger::init(config);
|
||||
if (mParser->isSet("verbose"))
|
||||
Logger::getInstance()->setVerbose(true);
|
||||
|
||||
|
|
@ -230,11 +239,6 @@ App::App (int &argc, char *argv[]) : SingleApplication(argc, argv, true, Mode::U
|
|||
for (const auto &locale : QDir(Constants::LanguagePath).entryList())
|
||||
mAvailableLocales << QLocale(locale);
|
||||
|
||||
// Init locale.
|
||||
mTranslator = new DefaultTranslator(this);
|
||||
mDefaultTranslator = new DefaultTranslator(this);
|
||||
initLocale(config);
|
||||
|
||||
if (mParser->isSet("help")) {
|
||||
mParser->showHelp();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,19 @@ ProxyModel::ProxyModel (QAbstractItemModel * model, const int& defaultFilterMode
|
|||
sort(0, Qt::DescendingOrder);
|
||||
}
|
||||
|
||||
ProxyModel::~ProxyModel(){
|
||||
if(mDeleteSourceModel)
|
||||
deleteSourceModel();
|
||||
}
|
||||
|
||||
void ProxyModel::deleteSourceModel(){
|
||||
auto oldSourceModel = sourceModel();
|
||||
if(oldSourceModel) {
|
||||
oldSourceModel->deleteLater();
|
||||
setSourceModel(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int ProxyModel::getFilterMode () const {
|
||||
return mFilterMode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ public:
|
|||
|
||||
ProxyModel (QObject *parent = Q_NULLPTR);
|
||||
ProxyModel (QAbstractItemModel * list, const int& defaultFilterMode, QObject *parent = Q_NULLPTR);
|
||||
virtual ~ProxyModel();
|
||||
|
||||
virtual void deleteSourceModel();
|
||||
|
||||
int getFilterMode () const;
|
||||
void setFilterMode (int filterMode);
|
||||
|
|
@ -56,6 +59,8 @@ protected:
|
|||
bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
|
||||
|
||||
bool mDeleteSourceModel = false;
|
||||
|
||||
private:
|
||||
int mFilterMode;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,19 @@ SortFilterProxyModel::SortFilterProxyModel(QObject * parent) : QSortFilterProxyM
|
|||
connect(this, &SortFilterProxyModel::rowsRemoved, this, &SortFilterProxyModel::countChanged);
|
||||
}
|
||||
|
||||
SortFilterProxyModel::~SortFilterProxyModel(){
|
||||
if(mDeleteSourceModel)
|
||||
deleteSourceModel();
|
||||
}
|
||||
|
||||
void SortFilterProxyModel::deleteSourceModel(){
|
||||
auto oldSourceModel = sourceModel();
|
||||
if(oldSourceModel) {
|
||||
oldSourceModel->deleteLater();
|
||||
setSourceModel(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
int SortFilterProxyModel::getCount() const{
|
||||
return rowCount();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ public:
|
|||
Q_PROPERTY(int filterType READ getFilterType WRITE setFilterType NOTIFY filterTypeChanged)
|
||||
|
||||
SortFilterProxyModel(QObject * parent = nullptr);
|
||||
virtual ~SortFilterProxyModel();
|
||||
virtual void deleteSourceModel();
|
||||
|
||||
virtual int getCount() const;
|
||||
virtual int getFilterType () const;
|
||||
|
|
@ -47,6 +49,7 @@ signals:
|
|||
|
||||
protected:
|
||||
int mFilterType;
|
||||
bool mDeleteSourceModel = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -116,8 +116,10 @@ CallModel::CallModel (shared_ptr<linphone::Call> call){
|
|||
|
||||
if(mCall) {
|
||||
mRemoteAddress = mCall->getRemoteAddress()->clone();
|
||||
if(mCall->getConference())
|
||||
if(mCall->getConference()) {
|
||||
mConferenceModel = ConferenceModel::create(mCall->getConference());
|
||||
connect(mConferenceModel.get(), &ConferenceModel::participantAdminStatusChanged, this, &CallModel::onParticipantAdminStatusChanged);
|
||||
}
|
||||
auto conferenceInfo = CoreManager::getInstance()->getCore()->findConferenceInformationFromUri(getConferenceAddress());
|
||||
if( conferenceInfo ){
|
||||
mConferenceInfoModel = ConferenceInfoModel::create(conferenceInfo);
|
||||
|
|
@ -239,7 +241,8 @@ ConferenceInfoModel * CallModel::getConferenceInfoModel(){
|
|||
|
||||
QSharedPointer<ConferenceModel> CallModel::getConferenceSharedModel(){
|
||||
if(mCall->getConference() && !mConferenceModel){
|
||||
mConferenceModel = ConferenceModel::create(mCall->getConference());
|
||||
mConferenceModel = ConferenceModel::create(mCall->getConference());
|
||||
connect(mConferenceModel.get(), &ConferenceModel::participantAdminStatusChanged, this, &CallModel::onParticipantAdminStatusChanged);
|
||||
emit conferenceModelChanged();
|
||||
}
|
||||
return mConferenceModel;
|
||||
|
|
@ -247,7 +250,24 @@ QSharedPointer<ConferenceModel> CallModel::getConferenceSharedModel(){
|
|||
|
||||
bool CallModel::isConference () const{
|
||||
// Check status to avoid crash when requesting a conference on an ended call.
|
||||
return mCall && (Utils::coreStringToAppString(mCall->getRemoteAddress()->asString()).toLower().contains("conf-id") || (getStatus() != CallStatusEnded && mCall->getConference() != nullptr));
|
||||
bool isConf = false;
|
||||
if(mCall){
|
||||
// Do not call getConference on Ended status.
|
||||
isConf = (getStatus() != CallStatusEnded && mCall->getConference() != nullptr) || mConferenceInfoModel != nullptr;
|
||||
|
||||
if(!isConf){// Check special cases for Linphone. Having conf-id for a conference URI is not standard.
|
||||
auto remoteAddress = mCall->getRemoteAddress();
|
||||
if( remoteAddress->getDomain() == Constants::LinphoneDomain){
|
||||
isConf = remoteAddress->hasUriParam("conf-id");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isConf;
|
||||
}
|
||||
|
||||
bool CallModel::isOneToOne() const{
|
||||
return !isConference();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
@ -972,6 +992,12 @@ void CallModel::onChatRoomInitialized(int state){
|
|||
emit chatRoomModelChanged();
|
||||
}
|
||||
|
||||
void CallModel::onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> & participant){
|
||||
if(mConferenceModel && participant == mConferenceModel->getConference()->getMe()) {
|
||||
emit meAdminChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CallModel::setRemoteDisplayName(const std::string& name){
|
||||
mRemoteAddress->setDisplayName(name);
|
||||
if(mCall) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,9 @@ class CallModel : public QObject {
|
|||
Q_PROPERTY(bool isOutgoing READ isOutgoing CONSTANT)
|
||||
|
||||
Q_PROPERTY(bool isInConference READ isInConference NOTIFY isInConferenceChanged)
|
||||
Q_PROPERTY(bool isConference READ isConference CONSTANT)
|
||||
Q_PROPERTY(bool isConference READ isConference NOTIFY conferenceInfoModelChanged)
|
||||
Q_PROPERTY(bool isOneToOne READ isOneToOne NOTIFY conferenceInfoModelChanged)
|
||||
|
||||
|
||||
Q_PROPERTY(int duration READ getDuration CONSTANT) // Constants but called with a timer in qml.
|
||||
Q_PROPERTY(float quality READ getQuality CONSTANT)
|
||||
|
|
@ -145,6 +147,7 @@ public:
|
|||
return mIsInConference;
|
||||
}
|
||||
bool isConference () const;
|
||||
bool isOneToOne() const;
|
||||
|
||||
void setRecordFile (const std::shared_ptr<linphone::CallParams> &callParams);
|
||||
static void setRecordFile (const std::shared_ptr<linphone::CallParams> &callParams, const QString &to);
|
||||
|
|
@ -205,8 +208,10 @@ public slots:
|
|||
void endCall();
|
||||
void onRemoteRecording(const std::shared_ptr<linphone::Call> & call, bool recording);
|
||||
void onChatRoomInitialized(int state);
|
||||
void onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
|
||||
signals:
|
||||
void meAdminChanged();
|
||||
void callErrorChanged (const QString &callError);
|
||||
void callIdChanged();
|
||||
void isInConferenceChanged (bool status);
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ CallsListModel::CallsListModel (QObject *parent) : ProxyListModel(parent) {
|
|||
mCoreHandlers.get(), &CoreHandlers::callStateChanged,
|
||||
this, &CallsListModel::handleCallStateChanged
|
||||
);
|
||||
connect(this, &CallsListModel::countChanged, this, &CallsListModel::canMergeCallsChanged);
|
||||
}
|
||||
|
||||
CallModel *CallsListModel::findCallModelFromPeerAddress (const QString &peerAddress) const {
|
||||
|
|
@ -343,7 +344,7 @@ QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& se
|
|||
initializer->setAdminsData(admins);
|
||||
ChatRoomInitializer::start(initializer);
|
||||
}
|
||||
timeline = timelineList->getTimeline(chatRoom, ChatRoomModel::isTerminated(chatRoom));
|
||||
timeline = timelineList->getTimeline(chatRoom, true);
|
||||
}else{
|
||||
if(admins.size() > 0){
|
||||
ChatRoomInitializer::create(chatRoom)->setAdmins(admins);
|
||||
|
|
@ -354,9 +355,7 @@ QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& se
|
|||
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = false;
|
||||
result["chatRoomModel"] = QVariant::fromValue(timeline->getChatRoomModel());
|
||||
if(selectAfterCreation) {// The timeline here will not receive the first creation event. Set Selected if needed
|
||||
QTimer::singleShot(200, [timeline](){// Delay process in order to let GUI time for Timeline building/linking before doing actions
|
||||
timeline->setSelected(true);
|
||||
});
|
||||
timeline->delaySelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -368,19 +367,106 @@ QVariantMap CallsListModel::createChatRoom(const QString& subject, const int& se
|
|||
}
|
||||
|
||||
void CallsListModel::prepareConferenceCall(ConferenceInfoModel * model){
|
||||
auto app = App::getInstance();
|
||||
app->smartShowWindow(app->getCallsWindow());
|
||||
emit callConferenceAsked(model);
|
||||
if(model->getConferenceInfoState() != LinphoneEnums::ConferenceInfoStateCancelled) {
|
||||
auto app = App::getInstance();
|
||||
app->smartShowWindow(app->getCallsWindow());
|
||||
emit callConferenceAsked(model);
|
||||
}
|
||||
}
|
||||
|
||||
int CallsListModel::addAllToConference(){
|
||||
return CoreManager::getInstance()->getCore()->addAllToConference();
|
||||
}
|
||||
|
||||
void CallsListModel::mergeAll(){
|
||||
auto core = CoreManager::getInstance()->getCore();
|
||||
auto currentCalls = CoreManager::getInstance()->getCore()->getCalls();
|
||||
shared_ptr<linphone::Conference> conference = core->getConference();
|
||||
|
||||
// Search a managable conference from calls
|
||||
if(!conference){
|
||||
for(auto call : currentCalls){
|
||||
auto dbConference = call->getConference();
|
||||
if(dbConference && dbConference->getMe()->isAdmin()){
|
||||
conference = dbConference;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto currentCall = CoreManager::getInstance()->getCore()->getCurrentCall();
|
||||
bool enablingVideo = false;
|
||||
if( currentCall )
|
||||
enablingVideo = currentCall->getCurrentParams()->videoEnabled();
|
||||
if(!conference){
|
||||
auto parameters = core->createConferenceParams(conference);
|
||||
|
||||
if(!CoreManager::getInstance()->getSettingsModel()->getVideoConferenceEnabled()) {
|
||||
parameters->enableVideo(false);
|
||||
parameters->setConferenceFactoryAddress(nullptr);// Do a local conference
|
||||
parameters->setSubject("Local meeting");
|
||||
}else{
|
||||
parameters->enableVideo(enablingVideo);
|
||||
parameters->setSubject("Meeting");
|
||||
}
|
||||
conference = core->createConferenceWithParams(parameters);
|
||||
}
|
||||
|
||||
list<shared_ptr<linphone::Address>> allLinphoneAddresses;
|
||||
list<shared_ptr<linphone::Address>> newCalls;
|
||||
list<shared_ptr<linphone::Call>> runningCallsToAdd;
|
||||
|
||||
for(auto call : currentCalls){
|
||||
if(!call->getConference()){
|
||||
runningCallsToAdd.push_back(call);
|
||||
}
|
||||
}
|
||||
|
||||
// 1) Add running calls
|
||||
if( runningCallsToAdd.size() > 0){
|
||||
conference->addParticipants(runningCallsToAdd);
|
||||
}
|
||||
/*
|
||||
// 2) Put in pause and remove all calls that are not in the conference list
|
||||
for(const auto &call : CoreManager::getInstance()->getCore()->getCalls()){
|
||||
const std::string callAddress = call->getRemoteAddress()->asStringUriOnly();
|
||||
auto address = allLinphoneAddresses.begin();
|
||||
while(address != allLinphoneAddresses.end() && (*address)->asStringUriOnly() != callAddress)
|
||||
++address;
|
||||
if(address == allLinphoneAddresses.end()){// Not in conference list : put in pause and remove it from conference if it's the case
|
||||
if( call->getParams()->getLocalConferenceMode() ){// Remove conference if it is not yet requested
|
||||
CoreManager::getInstance()->getCore()->removeFromConference(call);
|
||||
}else
|
||||
call->pause();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int CallsListModel::getRunningCallsNumber () const {
|
||||
return CoreManager::getInstance()->getCore()->getCallsNb();
|
||||
}
|
||||
|
||||
bool CallsListModel::canMergeCalls()const{
|
||||
auto calls = CoreManager::getInstance()->getCore()->getCalls();
|
||||
|
||||
bool mergableConference = false;
|
||||
int mergableCalls = 0;
|
||||
bool mergable = false;
|
||||
for(auto itCall = calls.begin(); !mergable && itCall != calls.end() ; ++itCall ) {
|
||||
auto conference = (*itCall)->getConference();
|
||||
if(conference){
|
||||
if( !mergableConference )
|
||||
mergableConference = (conference && conference->getMe()->isAdmin());
|
||||
}else{
|
||||
++mergableCalls;
|
||||
}
|
||||
mergable = (mergableConference && mergableCalls>0) // A call can be merged into the conference
|
||||
|| mergableCalls>1;// 2 calls can be merged
|
||||
}
|
||||
return mergable;
|
||||
}
|
||||
|
||||
void CallsListModel::terminateAllCalls () const {
|
||||
CoreManager::getInstance()->getCore()->terminateAllCalls();
|
||||
}
|
||||
|
|
@ -479,6 +565,8 @@ void CallsListModel::addCall (const shared_ptr<linphone::Call> &call) {
|
|||
qInfo() << QStringLiteral("Add call:") << callModel->getFullLocalAddress() << callModel->getFullPeerAddress();
|
||||
App::getInstance()->getEngine()->setObjectOwnership(callModel.get(), QQmlEngine::CppOwnership);
|
||||
|
||||
connect(callModel.get(), &CallModel::meAdminChanged, this, &CallsListModel::canMergeCallsChanged);
|
||||
|
||||
add(callModel);
|
||||
emit layoutChanged();
|
||||
|
||||
|
|
@ -511,7 +599,7 @@ void CallsListModel::addDummyCall () {
|
|||
int id = findCallIndex(mList, *callModel);
|
||||
emit dataChanged(index(id, 0), index(id, 0));
|
||||
});
|
||||
|
||||
connect(callModel.get(), &CallModel::meAdminChanged, this, &CallsListModel::canMergeCallsChanged);
|
||||
|
||||
add(callModel);
|
||||
emit layoutChanged();
|
||||
|
|
|
|||
|
|
@ -37,6 +37,9 @@ class CallsListModel : public ProxyListModel {
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(bool canMergeCalls READ canMergeCalls NOTIFY canMergeCallsChanged)
|
||||
|
||||
|
||||
CallsListModel (QObject *parent = Q_NULLPTR);
|
||||
|
||||
CallModel *findCallModelFromPeerAddress (const QString &peerAddress) const;
|
||||
|
|
@ -57,9 +60,11 @@ public:
|
|||
Q_INVOKABLE void prepareConferenceCall(ConferenceInfoModel * model);
|
||||
|
||||
Q_INVOKABLE int addAllToConference();
|
||||
Q_INVOKABLE void mergeAll();
|
||||
|
||||
|
||||
Q_INVOKABLE int getRunningCallsNumber () const;
|
||||
bool canMergeCalls()const;
|
||||
|
||||
Q_INVOKABLE void terminateAllCalls () const;
|
||||
Q_INVOKABLE void terminateCall (const QString& sipAddress) const;
|
||||
|
|
@ -73,6 +78,7 @@ signals:
|
|||
void callConferenceAsked(ConferenceInfoModel * conferenceInfoModel);
|
||||
|
||||
void callMissed (CallModel *callModel);
|
||||
void canMergeCallsChanged();
|
||||
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ int Camera::mPreviewCounter;
|
|||
|
||||
// =============================================================================
|
||||
Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) {
|
||||
qDebug() << "[Camera] Camera constructor" << this;
|
||||
updateWindowIdLocation();
|
||||
setTextureFollowsItemSize(true);
|
||||
// The fbo content must be y-mirrored because the ms rendering is y-inverted.
|
||||
|
|
@ -66,9 +67,11 @@ Camera::Camera (QQuickItem *parent) : QQuickFramebufferObject(parent) {
|
|||
|
||||
Camera::~Camera(){
|
||||
qDebug() << "[Camera] Camera destructor" << this;
|
||||
mRefreshTimer->stop();
|
||||
|
||||
if(mIsPreview)
|
||||
deactivatePreview();
|
||||
setWindowIdLocation(None);
|
||||
setWindowIdLocation(None);// We need to remove the Qt Buffer from SDK ot avoid to reuse it.
|
||||
}
|
||||
|
||||
void Camera::resetWindowId() const{
|
||||
|
|
@ -157,8 +160,6 @@ void Camera::removeParticipantDeviceModel(){
|
|||
}
|
||||
|
||||
QQuickFramebufferObject::Renderer *Camera::createRenderer () const {
|
||||
resetWindowId();
|
||||
|
||||
QQuickFramebufferObject::Renderer * renderer = NULL;
|
||||
if(mWindowIdLocation == CorePreview){
|
||||
qDebug() << "[Camera] Setting Camera to Preview";
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ void ChatRoomInitializer::setAdmins(QList< std::shared_ptr<linphone::Address>> a
|
|||
|
||||
void ChatRoomInitializer::start(QSharedPointer<ChatRoomInitializer> initializer){
|
||||
QObject * context = new QObject();
|
||||
QObject::connect(initializer.get(), &ChatRoomInitializer::finished, context, [context, initializer](int state){
|
||||
QObject::connect(initializer.get(), &ChatRoomInitializer::finished, context, [context, initializer](LinphoneEnums::ChatRoomState state){
|
||||
qDebug() << "[ChatRoomInitializer] initialized";
|
||||
context->deleteLater();// This will destroy context and initializer
|
||||
});
|
||||
|
|
@ -93,7 +93,7 @@ void ChatRoomInitializer::checkInitialization(){
|
|||
if( mAdmins.size() > 0 && !mAdminsSet)
|
||||
return;
|
||||
|
||||
emit finished((int)mChatRoom->getState());
|
||||
emit finished(LinphoneEnums::fromLinphone(mChatRoom->getState()));
|
||||
}
|
||||
|
||||
void ChatRoomInitializer::onConferenceJoined(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <linphone++/linphone.hh>
|
||||
#include "ChatRoomInitializer.hpp"
|
||||
#include "utils/LinphoneEnums.hpp"
|
||||
|
||||
|
||||
#include <QList>
|
||||
|
|
@ -54,7 +55,7 @@ public:
|
|||
virtual void onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState);
|
||||
|
||||
signals:
|
||||
void finished(int state); // this signal is emit before deletion and give the current linphone::ChatRoom:State of the chat room.
|
||||
void finished(LinphoneEnums::ChatRoomState state); // this signal is emit before deletion and give the current linphone::ChatRoom:State of the chat room.
|
||||
|
||||
private:
|
||||
void connectTo(ChatRoomListener * listener);
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ void ChatRoomModel::connectTo(ChatRoomListener * listener){
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
QSharedPointer<ChatRoomModel> ChatRoomModel::create(std::shared_ptr<linphone::ChatRoom> chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs){
|
||||
QSharedPointer<ChatRoomModel> ChatRoomModel::create(const std::shared_ptr<linphone::ChatRoom>& chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs){
|
||||
QSharedPointer<ChatRoomModel> model = QSharedPointer<ChatRoomModel>::create(chatRoom, callLogs);
|
||||
if(model){
|
||||
model->mSelf = model;
|
||||
|
|
@ -117,7 +117,7 @@ QSharedPointer<ChatRoomModel> ChatRoomModel::create(std::shared_ptr<linphone::Ch
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ChatRoomModel::ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs, QObject * parent) : ProxyListModel(parent){
|
||||
ChatRoomModel::ChatRoomModel (const std::shared_ptr<linphone::ChatRoom>& chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs, QObject * parent) : ProxyListModel(parent){
|
||||
App::getInstance()->getEngine()->setObjectOwnership(this, QQmlEngine::CppOwnership);// Avoid QML to destroy it when passing by Q_INVOKABLE
|
||||
CoreManager *coreManager = CoreManager::getInstance();
|
||||
mCoreHandlers = coreManager->getHandlers();
|
||||
|
|
@ -149,6 +149,7 @@ ChatRoomModel::ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, cons
|
|||
QObject::connect(coreManager->getContactsListModel(), &ContactsListModel::contactUpdated, this, &ChatRoomModel::avatarChanged);
|
||||
|
||||
connect(this, &ChatRoomModel::fullPeerAddressChanged, this, &ChatRoomModel::usernameChanged);
|
||||
connect(this, &ChatRoomModel::stateChanged, this, &ChatRoomModel::updatingChanged);
|
||||
|
||||
if(mChatRoom){
|
||||
mParticipantListModel = QSharedPointer<ParticipantListModel>::create(this);
|
||||
|
|
@ -311,11 +312,11 @@ QString ChatRoomModel::getLocalAddress () const {
|
|||
}
|
||||
|
||||
QString ChatRoomModel::getFullPeerAddress () const {
|
||||
return mChatRoom ? Utils::coreStringToAppString(mChatRoom->getPeerAddress()->asString()) : "";
|
||||
return mChatRoom && mChatRoom->getPeerAddress() ? Utils::coreStringToAppString(mChatRoom->getPeerAddress()->asString()) : "";
|
||||
}
|
||||
|
||||
QString ChatRoomModel::getFullLocalAddress () const {
|
||||
return mChatRoom ? Utils::coreStringToAppString(mChatRoom->getLocalAddress()->asString()) : "";
|
||||
return mChatRoom && mChatRoom->getLocalAddress()? Utils::coreStringToAppString(mChatRoom->getLocalAddress()->asString()) : "";
|
||||
}
|
||||
|
||||
QString ChatRoomModel::getConferenceAddress () const {
|
||||
|
|
@ -404,8 +405,8 @@ std::list<std::shared_ptr<linphone::Participant>> ChatRoomModel::getParticipants
|
|||
return participantList;
|
||||
}
|
||||
|
||||
int ChatRoomModel::getState() const {
|
||||
return mChatRoom ? (int)mChatRoom->getState() : 0;
|
||||
LinphoneEnums::ChatRoomState ChatRoomModel::getState() const {
|
||||
return mChatRoom ? LinphoneEnums::fromLinphone(mChatRoom->getState()) : LinphoneEnums::ChatRoomStateNone;
|
||||
}
|
||||
|
||||
bool ChatRoomModel::isReadOnly() const{
|
||||
|
|
@ -481,6 +482,10 @@ bool ChatRoomModel::isBasic() const{
|
|||
return mChatRoom && mChatRoom->hasCapability((int)linphone::ChatRoomCapabilities::Basic);
|
||||
}
|
||||
|
||||
bool ChatRoomModel::isUpdating() const{
|
||||
return getState() == LinphoneEnums::ChatRoomStateCreationPending || getState() == LinphoneEnums::ChatRoomStateTerminationPending;
|
||||
}
|
||||
|
||||
std::shared_ptr<linphone::ChatRoom> ChatRoomModel::getChatRoom(){
|
||||
return mChatRoom;
|
||||
}
|
||||
|
|
@ -523,14 +528,6 @@ int ChatRoomModel::getAllUnreadCount(){
|
|||
return mUnreadMessagesCount + mMissedCallsCount;
|
||||
}
|
||||
|
||||
QString ChatRoomModel::getCachedText()const{
|
||||
return mCachedText;
|
||||
}
|
||||
|
||||
bool ChatRoomModel::hasDraft() const{
|
||||
return mHasDraft;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomModel::setSubject(QString& subject){
|
||||
|
|
@ -605,23 +602,6 @@ void ChatRoomModel::enableMarkAsRead(const bool& enable){
|
|||
}
|
||||
}
|
||||
|
||||
bool ChatRoomModel::setCachedText(const QString& text){
|
||||
if(mCachedText != text){
|
||||
mCachedText = text;
|
||||
emit cachedTextChanged();
|
||||
setHasDraft(!mCachedText.isEmpty());
|
||||
return true;
|
||||
}else
|
||||
return false;
|
||||
}
|
||||
|
||||
void ChatRoomModel::setHasDraft(const bool& cached){
|
||||
if(mHasDraft != cached){
|
||||
mHasDraft = cached;
|
||||
emit hasDraftChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomModel::setReply(ChatMessageModel * model){
|
||||
if(model != mReplyModel.get()){
|
||||
if( model && model->getChatMessage() )
|
||||
|
|
@ -645,15 +625,14 @@ void ChatRoomModel::markAsToDelete(){
|
|||
void ChatRoomModel::deleteChatRoom(){
|
||||
qInfo() << "Deleting ChatRoom : " << getSubject() << ", address=" << getFullPeerAddress();
|
||||
if(mChatRoom){
|
||||
mChatRoom->removeListener(mChatRoomListener);
|
||||
CoreManager::getInstance()->getCore()->deleteChatRoom(mChatRoom);
|
||||
}
|
||||
emit chatRoomDeleted();
|
||||
}
|
||||
|
||||
void ChatRoomModel::leaveChatRoom (){
|
||||
if(mChatRoom){
|
||||
mChatRoom->leave();
|
||||
if(!isReadOnly())
|
||||
mChatRoom->leave();
|
||||
if( mChatRoom->getHistorySize() == 0 && mChatRoom->getHistoryEventsSize() == 0)
|
||||
deleteChatRoom();
|
||||
}
|
||||
|
|
@ -724,7 +703,6 @@ void ChatRoomModel::sendMessage (const QString &message) {
|
|||
if(recorder->haveVocalRecorder())
|
||||
recorder->clearVocalRecorder();
|
||||
CoreManager::getInstance()->getChatModel()->clear();
|
||||
setCachedText("");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -744,8 +722,8 @@ void ChatRoomModel::forwardMessage(ChatMessageModel * model){
|
|||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void ChatRoomModel::compose (const QString& text) {
|
||||
if( setCachedText(text) && mChatRoom)// only send a compose if text has changed
|
||||
void ChatRoomModel::compose () {
|
||||
if( mChatRoom)
|
||||
mChatRoom->compose();
|
||||
}
|
||||
|
||||
|
|
@ -880,23 +858,31 @@ int ChatRoomModel::loadTillMessage(ChatMessageModel * message){
|
|||
});
|
||||
// if not find, load more entries and find it in new entries.
|
||||
if( entry == mList.end()){
|
||||
mPostModelChangedEvents = false;
|
||||
beginResetModel();
|
||||
int newEntries = loadMoreEntries();
|
||||
while( newEntries > 0){// no more new entries
|
||||
int entryCount = 0;
|
||||
entry = mList.begin();
|
||||
auto chatEventEntry = entry->objectCast<ChatEvent>();
|
||||
auto chatEventEntry = entry->objectCast<ChatEvent>();
|
||||
while(entryCount < newEntries &&
|
||||
(chatEventEntry->mType != ChatRoomModel::EntryType::MessageEntry || chatEventEntry.objectCast<ChatMessageModel>()->getChatMessage() != linphoneMessage)
|
||||
){
|
||||
++entryCount;
|
||||
++entry;
|
||||
if( entry != mList.end())
|
||||
chatEventEntry = entry->objectCast<ChatEvent>();
|
||||
}
|
||||
if( entryCount < newEntries){// We got it
|
||||
qDebug() << "Find message at " << entryCount << " after loading new entries";
|
||||
mPostModelChangedEvents = true;
|
||||
endResetModel();
|
||||
return entryCount;
|
||||
}else
|
||||
newEntries = loadMoreEntries();// continue
|
||||
}
|
||||
mPostModelChangedEvents = true;
|
||||
endResetModel();
|
||||
}else{
|
||||
int entryCount = entry - mList.begin();
|
||||
qDebug() << "Find message at " << entryCount;
|
||||
|
|
@ -1051,18 +1037,21 @@ int ChatRoomModel::loadMoreEntries(){
|
|||
EntrySorterHelper::getLimitedSelection(&entries, prepareEntries, mLastEntriesStep, this);
|
||||
|
||||
if(entries.size() >0){
|
||||
beginInsertRows(QModelIndex(), 0, entries.size()-1);
|
||||
if(mPostModelChangedEvents)
|
||||
beginInsertRows(QModelIndex(), 0, entries.size()-1);
|
||||
for(auto entry : entries)
|
||||
mList.prepend(entry);
|
||||
endInsertRows();
|
||||
if(mPostModelChangedEvents)
|
||||
endInsertRows();
|
||||
//emit layoutChanged();
|
||||
updateLastUpdateTime();
|
||||
}
|
||||
newEntries = entries.size();
|
||||
}while( newEntries>0 && currentRowCount == rowCount());
|
||||
currentRowCount = rowCount() - currentRowCount + 1;
|
||||
currentRowCount = rowCount() - currentRowCount;
|
||||
setEntriesLoading(false);
|
||||
emit moreEntriesLoaded(currentRowCount);
|
||||
if(mPostModelChangedEvents)
|
||||
emit moreEntriesLoaded(currentRowCount);
|
||||
return currentRowCount;
|
||||
}
|
||||
|
||||
|
|
@ -1337,6 +1326,11 @@ void ChatRoomModel::onParticipantAdminStatusChanged(const std::shared_ptr<linpho
|
|||
void ChatRoomModel::onStateChanged(const std::shared_ptr<linphone::ChatRoom> & chatRoom, linphone::ChatRoom::State newState){
|
||||
updateLastUpdateTime();
|
||||
emit stateChanged(getState());
|
||||
if(newState == linphone::ChatRoom::State::Deleted){
|
||||
mChatRoom->removeListener(mChatRoomListener);
|
||||
mChatRoom = nullptr;
|
||||
emit chatRoomDeleted();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatRoomModel::onSecurityEvent(const std::shared_ptr<linphone::ChatRoom> & chatRoom, const std::shared_ptr<const linphone::EventLog> & eventLog){
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@
|
|||
#include "app/proxyModel/ProxyListModel.hpp"
|
||||
#include <QDateTime>
|
||||
|
||||
#include "utils/LinphoneEnums.hpp"
|
||||
|
||||
// =============================================================================
|
||||
// Fetch all N messages of a ChatRoom.
|
||||
// =============================================================================
|
||||
|
|
@ -73,13 +75,14 @@ public:
|
|||
Q_PROPERTY(bool isComposing READ getIsRemoteComposing NOTIFY isRemoteComposingChanged)
|
||||
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
|
||||
Q_PROPERTY(bool isReadOnly READ isReadOnly NOTIFY isReadOnlyChanged)
|
||||
Q_PROPERTY(bool updating READ isUpdating NOTIFY updatingChanged)
|
||||
|
||||
Q_PROPERTY(QString sipAddress READ getFullPeerAddress NOTIFY fullPeerAddressChanged)
|
||||
Q_PROPERTY(QString sipAddressUriOnly READ getPeerAddress NOTIFY fullPeerAddressChanged)
|
||||
Q_PROPERTY(QString username READ getUsername NOTIFY usernameChanged)
|
||||
Q_PROPERTY(QString avatar READ getAvatar NOTIFY avatarChanged)
|
||||
Q_PROPERTY(int presenceStatus READ getPresenceStatus NOTIFY presenceStatusChanged)
|
||||
Q_PROPERTY(int state READ getState NOTIFY stateChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ChatRoomState state READ getState NOTIFY stateChanged)
|
||||
|
||||
Q_PROPERTY(long ephemeralLifetime READ getEphemeralLifetime WRITE setEphemeralLifetime NOTIFY ephemeralLifetimeChanged)
|
||||
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE setEphemeralEnabled NOTIFY ephemeralEnabledChanged)
|
||||
|
|
@ -92,12 +95,9 @@ public:
|
|||
|
||||
Q_PROPERTY(bool entriesLoading READ isEntriesLoading WRITE setEntriesLoading NOTIFY entriesLoadingChanged)
|
||||
|
||||
Q_PROPERTY(QString cachedText READ getCachedText WRITE setCachedText NOTIFY cachedTextChanged)
|
||||
Q_PROPERTY(bool hasDraft READ hasDraft WRITE setHasDraft NOTIFY hasDraftChanged)
|
||||
|
||||
|
||||
static QSharedPointer<ChatRoomModel> create(std::shared_ptr<linphone::ChatRoom> chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs = std::list<std::shared_ptr<linphone::CallLog>>());
|
||||
ChatRoomModel (std::shared_ptr<linphone::ChatRoom> chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs = std::list<std::shared_ptr<linphone::CallLog>>(), QObject * parent = nullptr);
|
||||
static QSharedPointer<ChatRoomModel> create(const std::shared_ptr<linphone::ChatRoom>& chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs = std::list<std::shared_ptr<linphone::CallLog>>());
|
||||
ChatRoomModel (const std::shared_ptr<linphone::ChatRoom>& chatRoom, const std::list<std::shared_ptr<linphone::CallLog>>& callLogs = std::list<std::shared_ptr<linphone::CallLog>>(), QObject * parent = nullptr);
|
||||
|
||||
~ChatRoomModel ();
|
||||
|
||||
|
|
@ -119,7 +119,7 @@ public:
|
|||
QString getUsername () const;
|
||||
QString getAvatar () const;
|
||||
int getPresenceStatus() const;
|
||||
int getState() const;
|
||||
LinphoneEnums::ChatRoomState getState() const;
|
||||
bool isReadOnly() const;
|
||||
bool isEphemeralEnabled() const;
|
||||
long getEphemeralLifetime() const;
|
||||
|
|
@ -138,14 +138,14 @@ public:
|
|||
bool getIsRemoteComposing () const;
|
||||
bool isEntriesLoading() const;
|
||||
bool isBasic() const;
|
||||
bool isUpdating() const;
|
||||
|
||||
ParticipantListModel* getParticipantListModel() const;
|
||||
std::list<std::shared_ptr<linphone::Participant>> getParticipants(const bool& withMe = true) const;
|
||||
std::shared_ptr<linphone::ChatRoom> getChatRoom();
|
||||
QList<QString> getComposers();
|
||||
QString getParticipantAddress(); // return peerAddress if not secure else return the first participant SIP address.
|
||||
int getAllUnreadCount(); // Return unread messages and missed call.
|
||||
QString getCachedText() const;
|
||||
bool hasDraft() const;
|
||||
|
||||
//---- Setters
|
||||
void setSubject(QString& subject);
|
||||
|
|
@ -159,8 +159,6 @@ public:
|
|||
void setEphemeralEnabled(bool enabled);
|
||||
void setEphemeralLifetime(long lifetime);
|
||||
void enableMarkAsRead(const bool& enable);
|
||||
bool setCachedText(const QString& text); // return true if cache changed
|
||||
void setHasDraft(const bool& draft);
|
||||
|
||||
void setReply(ChatMessageModel * model);
|
||||
ChatMessageModel * getReply()const;
|
||||
|
|
@ -175,7 +173,7 @@ public:
|
|||
Q_INVOKABLE void updateParticipants(const QVariantList& participants);
|
||||
void sendMessage (const QString &message);
|
||||
Q_INVOKABLE void forwardMessage(ChatMessageModel * model);
|
||||
void compose (const QString& text);
|
||||
void compose ();
|
||||
Q_INVOKABLE void resetMessageCount ();
|
||||
void initEntries();
|
||||
Q_INVOKABLE int loadMoreEntries(); // return new entries count
|
||||
|
|
@ -280,8 +278,7 @@ signals:
|
|||
void markAsReadEnabledChanged();
|
||||
void chatRoomDeleted();// Must be connected with DirectConnection mode
|
||||
void replyChanged();
|
||||
void cachedTextChanged();
|
||||
void hasDraftChanged();
|
||||
void updatingChanged();
|
||||
|
||||
// Chat Room listener callbacks
|
||||
|
||||
|
|
@ -314,8 +311,7 @@ private:
|
|||
QSharedPointer<ChatMessageModel> mReplyModel;
|
||||
QSharedPointer<ChatNoticeModel> mUnreadMessageNotice;
|
||||
int mBindingCalls = 0;
|
||||
QString mCachedText; // TODO : replace it by content to manage files/audio etc.
|
||||
bool mHasDraft = false;
|
||||
bool mPostModelChangedEvents = true;
|
||||
|
||||
QWeakPointer<ChatRoomModel> mSelf;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
QString ChatRoomProxyModel::gCachedText;
|
||||
|
||||
// =============================================================================
|
||||
|
||||
ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel(parent) {
|
||||
|
|
@ -55,6 +57,7 @@ ChatRoomProxyModel::ChatRoomProxyModel (QObject *parent) : QSortFilterProxyModel
|
|||
}
|
||||
|
||||
ChatRoomProxyModel::~ChatRoomProxyModel(){
|
||||
setSourceModel(nullptr);
|
||||
setChatRoomModel(nullptr); // Do remove process like setting haveCall if is Call.
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +102,8 @@ CREATE_PARENT_MODEL_FUNCTION(deleteChatRoom)
|
|||
|
||||
void ChatRoomProxyModel::compose (const QString& text) {
|
||||
if (mChatRoomModel)
|
||||
mChatRoomModel->compose(text);
|
||||
mChatRoomModel->compose();
|
||||
gCachedText = text;
|
||||
}
|
||||
|
||||
int ChatRoomProxyModel::getEntryTypeFilter () {
|
||||
|
|
@ -239,6 +243,10 @@ QVariant ChatRoomProxyModel::getAt(int row){
|
|||
return sourceModel()->data(sourceIndex);
|
||||
}
|
||||
|
||||
QString ChatRoomProxyModel::getCachedText() const{
|
||||
return gCachedText;
|
||||
}
|
||||
|
||||
void ChatRoomProxyModel::setIsCall(const bool& isCall){
|
||||
if(mIsCall != isCall) {
|
||||
if(mChatRoomModel){
|
||||
|
|
@ -328,7 +336,7 @@ void ChatRoomProxyModel::setChatRoomModel (ChatRoomModel *chatRoomModel){
|
|||
}else{
|
||||
if(mIsCall && mChatRoomModel)
|
||||
mChatRoomModel->removeBindingCall();
|
||||
mChatRoomModel = nullptr;
|
||||
mChatRoomModel = nullptr;
|
||||
}
|
||||
}
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ChatRoomProxyModel : public QSortFilterProxyModel {
|
|||
Q_PROPERTY(QString fullLocalAddress READ getFullLocalAddress WRITE setFullLocalAddress NOTIFY fullLocalAddressChanged)
|
||||
Q_PROPERTY(ChatRoomModel *chatRoomModel READ getChatRoomModel WRITE setChatRoomModel NOTIFY chatRoomModelChanged)
|
||||
Q_PROPERTY(QList<QString> composers READ getComposers NOTIFY isRemoteComposingChanged)
|
||||
Q_PROPERTY(QString cachedText READ getCachedText)
|
||||
|
||||
Q_PROPERTY(QString filterText MEMBER mFilterText WRITE setFilterText NOTIFY filterTextChanged)
|
||||
Q_PROPERTY(bool markAsReadEnabled READ markAsReadEnabled WRITE enableMarkAsRead NOTIFY markAsReadEnabledChanged)// Focus is at end of the list. Used to reset message count if not at end
|
||||
|
|
@ -119,6 +120,9 @@ private:
|
|||
void setChatRoomModel (ChatRoomModel *chatRoomModel);
|
||||
|
||||
QList<QString> getComposers () const;
|
||||
|
||||
QString getCachedText() const;
|
||||
|
||||
void reload (ChatRoomModel *chatRoomModel);
|
||||
|
||||
void handleIsActiveChanged (QWindow *window);
|
||||
|
|
@ -134,6 +138,7 @@ private:
|
|||
QString mLocalAddress;
|
||||
QString mFullPeerAddress;
|
||||
QString mFullLocalAddress;
|
||||
static QString gCachedText;
|
||||
bool mMarkAsReadEnabled;
|
||||
bool mIsCall = false;
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,11 @@ ConferenceListener::~ConferenceListener(){
|
|||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
// LINPHONE LISTENERS
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void ConferenceListener::onActiveSpeakerParticipantDevice(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice) {
|
||||
qDebug() << "onActiveSpeakerParticipantDevice: " << participantDevice->getAddress()->asString().c_str();
|
||||
emit activeSpeakerParticipantDevice(participantDevice);
|
||||
}
|
||||
|
||||
void ConferenceListener::onParticipantAdded(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::Participant> & participant){
|
||||
qDebug() << "onParticipantAdded: " << participant->getAddress()->asString().c_str();
|
||||
emit participantAdded(participant);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public:
|
|||
virtual ~ConferenceListener();
|
||||
|
||||
// LINPHONE LISTENERS
|
||||
virtual void onActiveSpeakerParticipantDevice(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice) override;
|
||||
virtual void onParticipantAdded(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::Participant> & participant) override;
|
||||
virtual void onParticipantRemoved(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::Participant> & participant) override;
|
||||
virtual void onParticipantAdminStatusChanged(const std::shared_ptr<linphone::Conference> & conference, const std::shared_ptr<const linphone::Participant> & participant) override;
|
||||
|
|
@ -50,6 +51,7 @@ public:
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
signals:
|
||||
void activeSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice);
|
||||
void participantAdded(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
void participantRemoved(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
void participantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
|
|
@ -61,6 +63,7 @@ signals:
|
|||
void participantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice, bool isSpeaking);
|
||||
void conferenceStateChanged(linphone::Conference::State newState);
|
||||
void subjectChanged(const std::string & subject);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "components/Components.hpp"
|
||||
|
||||
void ConferenceModel::connectTo(ConferenceListener * listener){
|
||||
connect(listener, &ConferenceListener::activeSpeakerParticipantDevice, this, &ConferenceModel::onActiveSpeakerParticipantDevice);
|
||||
connect(listener, &ConferenceListener::participantAdded, this, &ConferenceModel::onParticipantAdded);
|
||||
connect(listener, &ConferenceListener::participantRemoved, this, &ConferenceModel::onParticipantRemoved);
|
||||
connect(listener, &ConferenceListener::participantAdminStatusChanged, this, &ConferenceModel::onParticipantAdminStatusChanged);
|
||||
|
|
@ -140,6 +141,9 @@ void ConferenceModel::setIsReady(bool state){
|
|||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
// LINPHONE LISTENERS
|
||||
//-----------------------------------------------------------------------------------------------------------------------
|
||||
void ConferenceModel::onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice){
|
||||
emit activeSpeakerParticipantDevice(participantDevice);
|
||||
}
|
||||
void ConferenceModel::onParticipantAdded(const std::shared_ptr<const linphone::Participant> & participant){
|
||||
qDebug() << "Added call, participant count: " << getParticipantList().size() << ". Me devices : " << mConference->getMe()->getDevices().size();
|
||||
updateLocalParticipant();
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ public:
|
|||
|
||||
void setIsReady(bool state);
|
||||
|
||||
|
||||
virtual void onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice);
|
||||
virtual void onParticipantAdded(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
virtual void onParticipantRemoved(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
virtual void onParticipantAdminStatusChanged(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
|
|
@ -77,6 +77,7 @@ public:
|
|||
//---------------------------------------------------------------------------
|
||||
|
||||
signals:
|
||||
void activeSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice);
|
||||
void localParticipantChanged();
|
||||
void participantAdded(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
void participantRemoved(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
using namespace std;
|
||||
|
||||
ConferenceProxyModel::ConferenceProxyModel (QObject *parent) : SortFilterProxyModel(parent) {
|
||||
mDeleteSourceModel = false;
|
||||
setSourceModel(CoreManager::getInstance()->getCallsListModel());
|
||||
emit conferenceChanged();
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ ConferenceInfoListModel::ConferenceInfoListModel (QObject *parent) : ProxyListMo
|
|||
auto conferenceInfos = coreManager->getCore()->getConferenceInformationList();
|
||||
QList<QSharedPointer<ConferenceInfoModel> > items;
|
||||
for(auto conferenceInfo : conferenceInfos){
|
||||
auto item = build(conferenceInfo);
|
||||
auto item = build(conferenceInfo, mBuildAll);
|
||||
if(item)
|
||||
items << item;
|
||||
}
|
||||
|
|
@ -53,10 +53,10 @@ ConferenceInfoListModel::ConferenceInfoListModel (QObject *parent) : ProxyListMo
|
|||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QSharedPointer<ConferenceInfoModel> ConferenceInfoListModel::build(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo) const{
|
||||
QSharedPointer<ConferenceInfoModel> ConferenceInfoListModel::build(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo, const bool& buildAll) const{
|
||||
auto me = CoreManager::getInstance()->getCore()->getDefaultAccount()->getParams()->getIdentityAddress();
|
||||
std::list<std::shared_ptr<linphone::Address>> participants = conferenceInfo->getParticipants();
|
||||
bool haveMe = conferenceInfo->getOrganizer()->weakEqual(me);
|
||||
bool haveMe = buildAll || conferenceInfo->getOrganizer()->weakEqual(me);
|
||||
if(!haveMe)
|
||||
haveMe = (std::find_if(participants.begin(), participants.end(), [me](const std::shared_ptr<linphone::Address>& address){
|
||||
return me->weakEqual(address);
|
||||
|
|
@ -70,7 +70,7 @@ QSharedPointer<ConferenceInfoModel> ConferenceInfoListModel::build(const std::sh
|
|||
}
|
||||
|
||||
void ConferenceInfoListModel::add(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo, const bool& sendEvents){
|
||||
auto item = build(conferenceInfo);
|
||||
auto item = build(conferenceInfo, mBuildAll);
|
||||
if( item)
|
||||
ProxyListModel::add(item);
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ QVariant ConferenceInfoListModel::data (const QModelIndex &index, int role ) con
|
|||
if (role == Qt::DisplayRole)
|
||||
return QVariant::fromValue(mList[row].get());
|
||||
else if (role == Qt::DisplayRole +1 )
|
||||
return QVariant::fromValue(mList[row].objectCast<ConferenceInfoModel>()->getDateTimeUtc().date());
|
||||
return QVariant::fromValue(mList[row].objectCast<ConferenceInfoModel>()->getDateTimeSystem().date());
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ class ConferenceInfoListModel : public ProxyListModel {
|
|||
|
||||
public:
|
||||
ConferenceInfoListModel (QObject *parent = Q_NULLPTR);
|
||||
QSharedPointer<ConferenceInfoModel> build(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo) const;
|
||||
QSharedPointer<ConferenceInfoModel> build(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo, const bool& buildAll) const;
|
||||
void add(const std::shared_ptr<linphone::ConferenceInfo> & conferenceInfo, const bool& sendEvents = true);
|
||||
|
||||
|
||||
|
|
@ -50,7 +50,8 @@ public slots:
|
|||
void onRemoved(bool byUser);
|
||||
signals:
|
||||
void filterTypeChanged(int filterType);
|
||||
|
||||
private:
|
||||
bool mBuildAll = true; // Short term design choice : display all. As of 5.2.0 SDK and on cancel, there are no more more links between conference info and current account.
|
||||
};
|
||||
Q_DECLARE_METATYPE(ConferenceInfoListModel*)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ ConferenceInfoModel::ConferenceInfoModel (QObject * parent) : QObject(parent){
|
|||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::isScheduledChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::inviteModeChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::conferenceInfoStateChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::conferenceSchedulerStateChanged);
|
||||
}
|
||||
|
||||
// Callable from C++
|
||||
|
|
@ -124,6 +125,7 @@ ConferenceInfoModel::ConferenceInfoModel (std::shared_ptr<linphone::ConferenceIn
|
|||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::isScheduledChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::inviteModeChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::conferenceInfoStateChanged);
|
||||
connect(this, &ConferenceInfoModel::conferenceInfoChanged, this, &ConferenceInfoModel::conferenceSchedulerStateChanged);
|
||||
}
|
||||
|
||||
ConferenceInfoModel::~ConferenceInfoModel () {
|
||||
|
|
@ -139,14 +141,15 @@ std::shared_ptr<linphone::ConferenceInfo> ConferenceInfoModel::findConferenceInf
|
|||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
QDateTime ConferenceInfoModel::getDateTimeUtc() const{
|
||||
return QDateTime::fromMSecsSinceEpoch(mConferenceInfo->getDateTime() * 1000).toUTC();
|
||||
//Note conferenceInfo->getDateTime uses system timezone and fromMSecsSinceEpoch need a UTC
|
||||
QDateTime ConferenceInfoModel::getDateTimeSystem() const{
|
||||
QDateTime reference(QDateTime::fromMSecsSinceEpoch(mConferenceInfo->getDateTime() * 1000));// Get a reference for timezone offset computing
|
||||
qint64 utcMs = (mConferenceInfo->getDateTime() - QTimeZone::systemTimeZone().offsetFromUtc(reference)) * 1000;// Remove system timezone offset to get UTC
|
||||
return QDateTime::fromMSecsSinceEpoch(utcMs, QTimeZone::systemTimeZone()); // Return a System Timezone datetime based
|
||||
}
|
||||
|
||||
QDateTime ConferenceInfoModel::getDateTimeSystem() const{
|
||||
QDateTime utc = getDateTimeUtc();
|
||||
return utc.addSecs(QTimeZone::systemTimeZone().offsetFromUtc(utc));
|
||||
QDateTime ConferenceInfoModel::getDateTimeUtc() const{
|
||||
return getDateTimeSystem().toUTC();
|
||||
}
|
||||
|
||||
int ConferenceInfoModel::getDuration() const{
|
||||
|
|
@ -204,11 +207,29 @@ QVariantList ConferenceInfoModel::getParticipants() const{
|
|||
}
|
||||
return addresses;
|
||||
}
|
||||
QVariantList ConferenceInfoModel::getAllParticipants() const{
|
||||
QVariantList addresses = getParticipants();
|
||||
QString organizerAddress = QString::fromStdString(mConferenceInfo->getOrganizer()->asStringUriOnly());
|
||||
for(auto item : addresses){
|
||||
if( item.toMap()["address"] == organizerAddress)
|
||||
return addresses;
|
||||
}
|
||||
QVariantMap participant;
|
||||
participant["displayName"] = Utils::getDisplayName(mConferenceInfo->getOrganizer());
|
||||
participant["address"] = organizerAddress;
|
||||
addresses << participant;
|
||||
return addresses;
|
||||
}
|
||||
|
||||
|
||||
int ConferenceInfoModel::getParticipantCount()const{
|
||||
return mConferenceInfo->getParticipants().size();
|
||||
}
|
||||
|
||||
int ConferenceInfoModel::getAllParticipantCount()const{
|
||||
return getAllParticipants().size();
|
||||
}
|
||||
|
||||
TimeZoneModel* ConferenceInfoModel::getTimeZoneModel() const{
|
||||
TimeZoneModel * model = new TimeZoneModel(mTimeZone);
|
||||
App::getInstance()->getEngine()->setObjectOwnership(model, QQmlEngine::JavaScriptOwnership);
|
||||
|
|
@ -223,12 +244,18 @@ LinphoneEnums::ConferenceInfoState ConferenceInfoModel::getConferenceInfoState()
|
|||
return LinphoneEnums::fromLinphone(mConferenceInfo->getState());
|
||||
}
|
||||
|
||||
LinphoneEnums::ConferenceSchedulerState ConferenceInfoModel::getConferenceSchedulerState() const{
|
||||
return LinphoneEnums::fromLinphone(mLastConferenceSchedulerState);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
// Convert into UTC with TimeZone and pass system timezone to conference info
|
||||
// Datetime is in Custom (Locale/UTC/System). Convert into system timezone for conference info
|
||||
void ConferenceInfoModel::setDateTime(const QDateTime& dateTime){
|
||||
QDateTime utc = dateTime.addSecs( -mTimeZone.offsetFromUtc(dateTime));
|
||||
QDateTime system = utc.addSecs(QTimeZone::systemTimeZone().offsetFromUtc(utc));
|
||||
mConferenceInfo->setDateTime(system.toMSecsSinceEpoch() / 1000);
|
||||
QDateTime system = dateTime.toTimeZone(QTimeZone::systemTimeZone());//System
|
||||
int offset = QTimeZone::systemTimeZone().offsetFromUtc(system);//Get UTC offset in system coordinate
|
||||
system = system.addSecs( offset - mTimeZone.offsetFromUtc(dateTime));// Delta on offsets
|
||||
mConferenceInfo->setDateTime(system.toMSecsSinceEpoch() / 1000 + offset);// toMSecsSinceEpoch() is UTC, add system reference.
|
||||
|
||||
emit dateTimeChanged();
|
||||
}
|
||||
|
||||
|
|
@ -254,6 +281,7 @@ void ConferenceInfoModel::setDescription(const QString& description){
|
|||
|
||||
void ConferenceInfoModel::setParticipants(ParticipantListModel * participants){
|
||||
mConferenceInfo->setParticipants(participants->getParticipants());
|
||||
emit participantsChanged();
|
||||
}
|
||||
|
||||
void ConferenceInfoModel::setTimeZoneModel(TimeZoneModel * model){
|
||||
|
|
@ -314,23 +342,22 @@ void ConferenceInfoModel::createConference(const int& securityLevel) {
|
|||
CoreManager::getInstance()->getTimelineListModel()->mAutoSelectAfterCreation = false;
|
||||
shared_ptr<linphone::Core> core = CoreManager::getInstance()->getCore();
|
||||
static std::shared_ptr<linphone::Conference> conference;
|
||||
qInfo() << "Conference creation of " << getSubject() << " at " << securityLevel << " security, organized by " << getOrganizer();
|
||||
qInfo() << "Conference creation of " << getSubject() << " at " << securityLevel << " security, organized by " << getOrganizer() << " for " << getDateTimeSystem().toString();
|
||||
qInfo() << "Participants:";
|
||||
for(auto p : mConferenceInfo->getParticipants())
|
||||
qInfo() << "\t" << p->asString().c_str();
|
||||
|
||||
|
||||
mConferenceScheduler = ConferenceScheduler::create();
|
||||
mConferenceScheduler->mSendInvite = mInviteMode;
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::invitationsSent, this, &ConferenceInfoModel::onInvitationsSent);
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::stateChanged, this, &ConferenceInfoModel::onStateChanged);
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::stateChanged, this, &ConferenceInfoModel::onConferenceSchedulerStateChanged);
|
||||
mConferenceScheduler->getConferenceScheduler()->setInfo(mConferenceInfo);
|
||||
}
|
||||
|
||||
void ConferenceInfoModel::cancelConference(){
|
||||
mConferenceScheduler = ConferenceScheduler::create();
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::invitationsSent, this, &ConferenceInfoModel::onInvitationsSent);
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::stateChanged, this, &ConferenceInfoModel::onStateChanged);
|
||||
connect(mConferenceScheduler.get(), &ConferenceScheduler::stateChanged, this, &ConferenceInfoModel::onConferenceSchedulerStateChanged);
|
||||
mConferenceScheduler->getConferenceScheduler()->cancelConference(mConferenceInfo);
|
||||
}
|
||||
|
||||
|
|
@ -343,12 +370,14 @@ void ConferenceInfoModel::deleteConferenceInfo(){
|
|||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
void ConferenceInfoModel::onStateChanged(linphone::ConferenceScheduler::State state){
|
||||
qDebug() << "ConferenceInfoModel::onStateChanged: " << (int) state;
|
||||
void ConferenceInfoModel::onConferenceSchedulerStateChanged(linphone::ConferenceScheduler::State state){
|
||||
qDebug() << "ConferenceInfoModel::onConferenceSchedulerStateChanged: " << (int) state;
|
||||
mLastConferenceSchedulerState = state;
|
||||
if( state == linphone::ConferenceScheduler::State::Ready)
|
||||
emit conferenceCreated();
|
||||
else if( state == linphone::ConferenceScheduler::State::Error)
|
||||
emit conferenceCreationFailed();
|
||||
emit conferenceInfoChanged();
|
||||
}
|
||||
void ConferenceInfoModel::onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> & failedInvitations) {
|
||||
qDebug() << "ConferenceInfoModel::onInvitationsSent";
|
||||
|
|
|
|||
|
|
@ -49,7 +49,10 @@ public:
|
|||
Q_PROPERTY(QString uri READ getUri NOTIFY uriChanged)
|
||||
Q_PROPERTY(bool isScheduled READ isScheduled WRITE setIsScheduled NOTIFY isScheduledChanged)
|
||||
Q_PROPERTY(int inviteMode READ getInviteMode WRITE setInviteMode NOTIFY inviteModeChanged)
|
||||
Q_PROPERTY(int participantCount READ getParticipantCount NOTIFY participantsChanged)
|
||||
Q_PROPERTY(int allParticipantCount READ getAllParticipantCount NOTIFY participantsChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ConferenceInfoState state READ getConferenceInfoState NOTIFY conferenceInfoStateChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ConferenceSchedulerState conferenceSchedulerState READ getConferenceSchedulerState NOTIFY conferenceSchedulerStateChanged)
|
||||
|
||||
static QSharedPointer<ConferenceInfoModel> create(std::shared_ptr<linphone::ConferenceInfo> conferenceInfo);
|
||||
ConferenceInfoModel (QObject * parent = nullptr);
|
||||
|
|
@ -72,10 +75,13 @@ public:
|
|||
bool isScheduled() const;
|
||||
int getInviteMode() const;
|
||||
Q_INVOKABLE QVariantList getParticipants() const;
|
||||
Q_INVOKABLE QVariantList getAllParticipants() const;
|
||||
Q_INVOKABLE int getParticipantCount()const;
|
||||
Q_INVOKABLE int getAllParticipantCount()const;
|
||||
Q_INVOKABLE TimeZoneModel* getTimeZoneModel() const;
|
||||
Q_INVOKABLE QString getIcalendarString() const;
|
||||
LinphoneEnums::ConferenceInfoState getConferenceInfoState() const;
|
||||
LinphoneEnums::ConferenceSchedulerState getConferenceSchedulerState() const;
|
||||
|
||||
void setDateTime(const QDateTime& dateTime);
|
||||
void setDuration(const int& duration);
|
||||
|
|
@ -97,10 +103,9 @@ public:
|
|||
|
||||
// SCHEDULER
|
||||
|
||||
virtual void onStateChanged(linphone::ConferenceScheduler::State state);
|
||||
virtual void onConferenceSchedulerStateChanged(linphone::ConferenceScheduler::State state);
|
||||
virtual void onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> & failedInvitations);
|
||||
|
||||
|
||||
signals:
|
||||
void timeZoneModelChanged();
|
||||
void dateTimeChanged();
|
||||
|
|
@ -113,6 +118,7 @@ signals:
|
|||
void isScheduledChanged();
|
||||
void inviteModeChanged();
|
||||
void conferenceInfoStateChanged();
|
||||
void conferenceSchedulerStateChanged();
|
||||
|
||||
void conferenceCreated();
|
||||
void conferenceCreationFailed();
|
||||
|
|
@ -128,6 +134,7 @@ private:
|
|||
bool mIsScheduled = true;
|
||||
int mInviteMode = 0;
|
||||
bool mRemoveRequested = false;// true if user has request its deletion from DB
|
||||
linphone::ConferenceScheduler::State mLastConferenceSchedulerState = linphone::ConferenceScheduler::State::Idle;// Workaround for missing getter in scheduler.
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(QSharedPointer<ConferenceInfoModel>)
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ bool ConferenceInfoProxyModel::filterAcceptsRow (int sourceRow, const QModelInde
|
|||
QModelIndex index = listModel->index(sourceRow, 0, QModelIndex());
|
||||
const ConferenceInfoModel* ics = sourceModel()->data(index).value<ConferenceInfoModel*>();
|
||||
if(ics){
|
||||
if(ics->getDuration() == 0)
|
||||
return false;
|
||||
QDateTime currentDateTime = QDateTime::currentDateTime();
|
||||
if( mFilterType == 0){
|
||||
return ics->getEndDateTime() < currentDateTime;
|
||||
|
|
@ -65,7 +67,7 @@ bool ConferenceInfoProxyModel::filterAcceptsRow (int sourceRow, const QModelInde
|
|||
return mFilterType == -1;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConferenceInfoProxyModel::lessThan (const QModelIndex &left, const QModelIndex &right) const {
|
||||
|
|
|
|||
|
|
@ -215,3 +215,7 @@ Presence::PresenceLevel ContactModel::getPresenceLevel () const {
|
|||
bool ContactModel::hasCapability(const LinphoneEnums::FriendCapability& capability){
|
||||
return mLinphoneFriend->hasCapability(LinphoneEnums::toLinphone(capability));
|
||||
}
|
||||
|
||||
std::shared_ptr<linphone::Friend> ContactModel::getFriend() const{
|
||||
return mLinphoneFriend;
|
||||
}
|
||||
|
|
@ -57,6 +57,8 @@ public:
|
|||
Q_INVOKABLE VcardModel *cloneVcardModel () const;
|
||||
Presence::PresenceLevel getPresenceLevel () const;
|
||||
Q_INVOKABLE bool hasCapability(const LinphoneEnums::FriendCapability& capability);
|
||||
|
||||
std::shared_ptr<linphone::Friend> getFriend() const;
|
||||
|
||||
signals:
|
||||
void contactUpdated ();
|
||||
|
|
|
|||
|
|
@ -460,9 +460,12 @@ QVariantList VcardModel::getUrls () const {
|
|||
return list;
|
||||
}
|
||||
|
||||
bool VcardModel::addUrl (const QString &url) {
|
||||
bool VcardModel::addUrl (QString url) {
|
||||
CHECK_VCARD_IS_WRITABLE(this);
|
||||
|
||||
QUrl urlParser(url);
|
||||
if( urlParser.scheme() == ""){
|
||||
url = "https://"+url;
|
||||
}
|
||||
shared_ptr<belcard::BelCard> belcard = mVcard->getVcard();
|
||||
if (findBelCardValue(belcard->getURLs(), url))
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ public:
|
|||
Q_INVOKABLE void removeEmail (const QString &email);
|
||||
Q_INVOKABLE bool updateEmail (const QString &oldEmail, const QString &email);
|
||||
|
||||
Q_INVOKABLE bool addUrl (const QString &url);
|
||||
Q_INVOKABLE bool addUrl (QString url);
|
||||
Q_INVOKABLE void removeUrl (const QString &url);
|
||||
Q_INVOKABLE bool updateUrl (const QString &oldUrl, const QString &url);
|
||||
|
||||
|
|
|
|||
|
|
@ -24,40 +24,26 @@
|
|||
#include "components/contact/ContactModel.hpp"
|
||||
#include "components/contact/VcardModel.hpp"
|
||||
#include "components/core/CoreManager.hpp"
|
||||
#include "components/friend/FriendListListener.hpp"
|
||||
|
||||
#include "ContactsListModel.hpp"
|
||||
|
||||
// =============================================================================
|
||||
void ContactsListModel::connectTo(FriendListListener * listener){
|
||||
connect(listener, &FriendListListener::contactCreated, this, &ContactsListModel::onContactCreated);
|
||||
connect(listener, &FriendListListener::contactDeleted, this, &ContactsListModel::onContactDeleted);
|
||||
connect(listener, &FriendListListener::contactUpdated, this, &ContactsListModel::onContactUpdated);
|
||||
connect(listener, &FriendListListener::syncStatusChanged, this, &ContactsListModel::onSyncStatusChanged);
|
||||
connect(listener, &FriendListListener::presenceReceived, this, &ContactsListModel::onPresenceReceived);
|
||||
}
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
ContactsListModel::ContactsListModel (QObject *parent) : ProxyListModel(parent) {
|
||||
mLinphoneFriends = CoreManager::getInstance()->getCore()->getFriendsLists().front();
|
||||
// Clean friends.
|
||||
{
|
||||
list<shared_ptr<linphone::Friend>> toRemove;
|
||||
for (const auto &linphoneFriend : mLinphoneFriends->getFriends()) {
|
||||
if (!linphoneFriend->getVcard())
|
||||
toRemove.push_back(linphoneFriend);
|
||||
}
|
||||
|
||||
for (const auto &linphoneFriend : toRemove) {
|
||||
qWarning() << QStringLiteral("Remove one friend without vcard.");
|
||||
mLinphoneFriends->removeFriend(linphoneFriend);
|
||||
}
|
||||
}
|
||||
|
||||
// Init contacts with linphone friends list.
|
||||
QQmlEngine *engine = App::getInstance()->getEngine();
|
||||
for (const auto &linphoneFriend : mLinphoneFriends->getFriends()) {
|
||||
auto contact = QSharedPointer<ContactModel>::create(linphoneFriend);
|
||||
|
||||
// See: http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership
|
||||
// The returned value must have a explicit parent or a QQmlEngine::CppOwnership.
|
||||
engine->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership);
|
||||
|
||||
addContact(contact);
|
||||
}
|
||||
mFriendListListener = std::make_shared<FriendListListener>();
|
||||
connectTo(mFriendListListener.get());
|
||||
update();
|
||||
}
|
||||
|
||||
ContactsListModel::~ContactsListModel(){
|
||||
|
|
@ -65,7 +51,7 @@ ContactsListModel::~ContactsListModel(){
|
|||
beginResetModel();
|
||||
mOptimizedSearch.clear();
|
||||
mList.clear();
|
||||
mLinphoneFriends = nullptr;
|
||||
mLinphoneFriends.clear();
|
||||
endResetModel();
|
||||
}
|
||||
}
|
||||
|
|
@ -75,7 +61,9 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren
|
|||
|
||||
if (row < 0 || count < 0 || limit >= mList.count())
|
||||
return false;
|
||||
|
||||
|
||||
auto friendsList = CoreManager::getInstance()->getCore()->getFriendsLists();
|
||||
|
||||
beginRemoveRows(parent, row, limit);
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
|
|
@ -84,7 +72,8 @@ bool ContactsListModel::removeRows (int row, int count, const QModelIndex &paren
|
|||
mOptimizedSearch.remove(address.toString());
|
||||
}
|
||||
|
||||
mLinphoneFriends->removeFriend(contact->mLinphoneFriend);
|
||||
for(auto l : friendsList)
|
||||
l->removeFriend(contact->mLinphoneFriend);
|
||||
|
||||
emit contactRemoved(contact);
|
||||
}
|
||||
|
|
@ -111,6 +100,10 @@ QSharedPointer<ContactModel> ContactsListModel::findContactModelFromUsername (co
|
|||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
ContactModel *ContactsListModel::getContactModelFromAddress (const QString& address) const{
|
||||
auto contact = findContactModelFromSipAddress(address);
|
||||
return contact.get();
|
||||
}
|
||||
|
||||
ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) {
|
||||
// Try to merge vcardModel to an existing contact.
|
||||
|
|
@ -123,7 +116,16 @@ ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) {
|
|||
contact = QSharedPointer<ContactModel>::create(vcardModel);
|
||||
App::getInstance()->getEngine()->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership);
|
||||
|
||||
if (mLinphoneFriends->addFriend(contact->mLinphoneFriend) != linphone::FriendList::Status::OK) {
|
||||
if( mLinphoneFriends.size() == 0){
|
||||
update();// Friends were not loaded correctly. Update them.
|
||||
}
|
||||
auto friendsList = CoreManager::getInstance()->getCore()->getDefaultFriendList();
|
||||
if( !friendsList){
|
||||
qWarning() << "There is no friends list available, cannot add a contact" ;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (friendsList->addFriend(contact->mLinphoneFriend) != linphone::FriendList::Status::OK) {
|
||||
qWarning() << QStringLiteral("Unable to add contact from vcard:") << vcardModel;
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -131,9 +133,8 @@ ContactModel *ContactsListModel::addContact (VcardModel *vcardModel) {
|
|||
qInfo() << QStringLiteral("Add contact from vcard:") << contact.get() << vcardModel;
|
||||
|
||||
// Make sure new subscribe is issued.
|
||||
mLinphoneFriends->updateSubscriptions();
|
||||
friendsList->updateSubscriptions();
|
||||
|
||||
addContact(contact);
|
||||
emit layoutChanged();
|
||||
|
||||
emit contactAdded(contact);
|
||||
|
|
@ -177,3 +178,47 @@ void ContactsListModel::addContact (QSharedPointer<ContactModel> contact) {
|
|||
mOptimizedSearch[address.toString()] = contact;
|
||||
}
|
||||
}
|
||||
|
||||
void ContactsListModel::update(){
|
||||
beginResetModel();
|
||||
for(auto l : mLinphoneFriends)
|
||||
l->removeListener(mFriendListListener);
|
||||
mLinphoneFriends.clear();
|
||||
mOptimizedSearch.clear();
|
||||
mList.clear();
|
||||
endResetModel();
|
||||
|
||||
mLinphoneFriends = CoreManager::getInstance()->getCore()->getFriendsLists();
|
||||
|
||||
for(auto l : mLinphoneFriends){
|
||||
l->addListener(mFriendListListener);
|
||||
for (const auto &linphoneFriend : l->getFriends()) {
|
||||
onContactCreated(linphoneFriend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------
|
||||
|
||||
void ContactsListModel::onContactCreated(const std::shared_ptr<linphone::Friend> & linphoneFriend){
|
||||
QQmlEngine *engine = App::getInstance()->getEngine();
|
||||
auto haveContact = std::find_if(mList.begin(), mList.end(), [linphoneFriend] (const QSharedPointer<QObject>& item){
|
||||
return item.objectCast<ContactModel>()->getFriend() == linphoneFriend;
|
||||
});
|
||||
if(haveContact == mList.end()) {
|
||||
auto contact = QSharedPointer<ContactModel>::create(linphoneFriend);
|
||||
// See: http://doc.qt.io/qt-5/qtqml-cppintegration-data.html#data-ownership
|
||||
// The returned value must have a explicit parent or a QQmlEngine::CppOwnership.
|
||||
engine->setObjectOwnership(contact.get(), QQmlEngine::CppOwnership);
|
||||
addContact(contact);
|
||||
}
|
||||
}
|
||||
void ContactsListModel::onContactDeleted(const std::shared_ptr<linphone::Friend> & linphoneFriend){
|
||||
}
|
||||
void ContactsListModel::onContactUpdated(const std::shared_ptr<linphone::Friend> & newFriend, const std::shared_ptr<linphone::Friend> & oldFriend){
|
||||
}
|
||||
void ContactsListModel::onSyncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message){
|
||||
}
|
||||
void ContactsListModel::onPresenceReceived(const std::list<std::shared_ptr<linphone::Friend>> & friends){
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace linphone {
|
|||
|
||||
class ContactModel;
|
||||
class VcardModel;
|
||||
class FriendListListener;
|
||||
|
||||
class ContactsListModel : public ProxyListModel {
|
||||
friend class SipAddressesModel;
|
||||
|
|
@ -48,10 +49,21 @@ public:
|
|||
QSharedPointer<ContactModel> findContactModelFromSipAddress (const QString &sipAddress) const;
|
||||
QSharedPointer<ContactModel> findContactModelFromUsername (const QString &username) const;
|
||||
|
||||
Q_INVOKABLE ContactModel *getContactModelFromAddress (const QString& address) const;
|
||||
Q_INVOKABLE ContactModel *addContact (VcardModel *vcardModel);
|
||||
Q_INVOKABLE void removeContact (ContactModel *contact);
|
||||
|
||||
Q_INVOKABLE void cleanAvatars ();
|
||||
Q_INVOKABLE void update ();
|
||||
|
||||
void connectTo(FriendListListener * listener);
|
||||
|
||||
public slots:
|
||||
void onContactCreated(const std::shared_ptr<linphone::Friend> & linphoneFriend);
|
||||
void onContactDeleted(const std::shared_ptr<linphone::Friend> & linphoneFriend);
|
||||
void onContactUpdated(const std::shared_ptr<linphone::Friend> & newFriend, const std::shared_ptr<linphone::Friend> & oldFriend);
|
||||
void onSyncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message);
|
||||
void onPresenceReceived(const std::list<std::shared_ptr<linphone::Friend>> & friends);
|
||||
|
||||
signals:
|
||||
void contactAdded (QSharedPointer<ContactModel>);
|
||||
|
|
@ -65,7 +77,8 @@ private:
|
|||
void addContact (QSharedPointer<ContactModel> contact);
|
||||
|
||||
QMap<QString, QSharedPointer<ContactModel>> mOptimizedSearch;
|
||||
std::shared_ptr<linphone::FriendList> mLinphoneFriends;
|
||||
std::list<std::shared_ptr<linphone::FriendList>> mLinphoneFriends;
|
||||
std::shared_ptr<FriendListListener> mFriendListListener;
|
||||
};
|
||||
|
||||
#endif // CONTACTS_LIST_MODEL_H_
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ void CoreManager::createLinphoneCore (const QString &configPath) {
|
|||
Paths::getFactoryConfigFilePath(),
|
||||
nullptr
|
||||
);
|
||||
setDatabasesPaths();
|
||||
// Enable LIME on your core to use encryption.
|
||||
mCore->enableLimeX3Dh(mCore->limeX3DhAvailable());
|
||||
// Now see the CoreService.CreateGroupChatRoom to see how to create a secure chat room
|
||||
|
|
@ -279,12 +280,13 @@ void CoreManager::createLinphoneCore (const QString &configPath) {
|
|||
QString userAgent = Utils::computeUserAgent(config);
|
||||
mCore->setUserAgent(Utils::appStringToCoreString(userAgent), mCore->getVersion());
|
||||
mCore->start();
|
||||
setDatabasesPaths();
|
||||
setOtherPaths();
|
||||
mCore->enableFriendListSubscription(true);
|
||||
mCore->enableRecordAware(true);
|
||||
if(mCore->getAccountCreatorUrl() == "")
|
||||
mCore->setAccountCreatorUrl(Constants::DefaultFlexiAPIURL);
|
||||
if( mCore->getAccountList().size() == 0)
|
||||
mCore->setLogCollectionUploadServerUrl(Constants::DefaultUploadLogsServer);
|
||||
}
|
||||
|
||||
void CoreManager::updateUserAgent(){
|
||||
|
|
|
|||
51
linphone-app/src/components/friend/FriendListListener.cpp
Normal file
51
linphone-app/src/components/friend/FriendListListener.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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 "FriendListListener.hpp"
|
||||
#include "../../utils/Utils.hpp"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
FriendListListener::FriendListListener(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void FriendListListener::onContactCreated(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & linphoneFriend) {
|
||||
qDebug() << "onContactCreated: " << Utils::coreStringToAppString(linphoneFriend->getName());
|
||||
emit contactCreated(linphoneFriend);
|
||||
}
|
||||
void FriendListListener::onContactDeleted(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & linphoneFriend) {
|
||||
qDebug() << "onContactDeleted: " << Utils::coreStringToAppString(linphoneFriend->getName());
|
||||
emit contactDeleted(linphoneFriend);
|
||||
}
|
||||
void FriendListListener::onContactUpdated(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & newFriend, const std::shared_ptr<linphone::Friend> & oldFriend) {
|
||||
qDebug() << "onContactUpdated: " << Utils::coreStringToAppString(newFriend->getName());
|
||||
emit contactUpdated(newFriend, oldFriend);
|
||||
}
|
||||
void FriendListListener::onSyncStatusChanged(const std::shared_ptr<linphone::FriendList> & friendList, linphone::FriendList::SyncStatus status, const std::string & message) {
|
||||
qDebug() << "onSyncStatusChanged: [" << (int)status<<"] " << Utils::coreStringToAppString(message);
|
||||
emit syncStatusChanged(status, message);
|
||||
}
|
||||
void FriendListListener::onPresenceReceived(const std::shared_ptr<linphone::FriendList> & friendList, const std::list<std::shared_ptr<linphone::Friend>> & friends) {
|
||||
qDebug() << "onPresenceReceived: " <<friends.size();
|
||||
emit presenceReceived(friends);
|
||||
}
|
||||
50
linphone-app/src/components/friend/FriendListListener.hpp
Normal file
50
linphone-app/src/components/friend/FriendListListener.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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 FRIEND_LIST_LISTENER_H_
|
||||
#define FRIEND_LIST_LISTENER_H_
|
||||
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class FriendListListener : public QObject, public linphone::FriendListListener {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FriendListListener (QObject *parent = nullptr);
|
||||
virtual void onContactCreated(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & linphoneFriend) override;
|
||||
virtual void onContactDeleted(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & linphoneFriend) override;
|
||||
virtual void onContactUpdated(const std::shared_ptr<linphone::FriendList> & friendList, const std::shared_ptr<linphone::Friend> & newFriend, const std::shared_ptr<linphone::Friend> & oldFriend) override;
|
||||
virtual void onSyncStatusChanged(const std::shared_ptr<linphone::FriendList> & friendList, linphone::FriendList::SyncStatus status, const std::string & message) override;
|
||||
virtual void onPresenceReceived(const std::shared_ptr<linphone::FriendList> & friendList, const std::list<std::shared_ptr<linphone::Friend>> & friends) override;
|
||||
|
||||
signals:
|
||||
void contactCreated(const std::shared_ptr<linphone::Friend> & linphoneFriend);
|
||||
void contactDeleted(const std::shared_ptr<linphone::Friend> & linphoneFriend);
|
||||
void contactUpdated(const std::shared_ptr<linphone::Friend> & newFriend, const std::shared_ptr<linphone::Friend> & oldFriend);
|
||||
void syncStatusChanged(linphone::FriendList::SyncStatus status, const std::string & message);
|
||||
void presenceReceived(const std::list<std::shared_ptr<linphone::Friend>> & friends);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
TimeZoneProxyModel::TimeZoneProxyModel (QObject *parent) : SortFilterProxyModel(parent) {
|
||||
mDeleteSourceModel = true;
|
||||
setSourceModel(new TimeZoneListModel(parent));
|
||||
sort(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ void ParticipantDeviceListModel::initConferenceModel(){
|
|||
updateDevices(conferenceModel->getConference()->getParticipantDeviceList(), false);
|
||||
|
||||
qDebug() << "Conference have " << mList.size() << " devices";
|
||||
connect(conferenceModel.get(), &ConferenceModel::activeSpeakerParticipantDevice, this, &ParticipantDeviceListModel::onActiveSpeakerParticipantDevice);
|
||||
connect(conferenceModel.get(), &ConferenceModel::participantAdded, this, &ParticipantDeviceListModel::onParticipantAdded);
|
||||
connect(conferenceModel.get(), &ConferenceModel::participantRemoved, this, &ParticipantDeviceListModel::onParticipantRemoved);
|
||||
connect(conferenceModel.get(), &ConferenceModel::participantDeviceAdded, this, &ParticipantDeviceListModel::onParticipantDeviceAdded);
|
||||
|
|
@ -98,6 +99,8 @@ void ParticipantDeviceListModel::updateDevices(const std::list<std::shared_ptr<l
|
|||
}
|
||||
|
||||
bool ParticipantDeviceListModel::add(std::shared_ptr<linphone::ParticipantDevice> deviceToAdd){
|
||||
auto deviceToAddAddr = deviceToAdd->getAddress();
|
||||
int row = 0;
|
||||
qDebug() << "Adding device " << deviceToAdd->getAddress()->asString().c_str();
|
||||
for(auto item : mList) {
|
||||
auto deviceModel = item.objectCast<ParticipantDeviceModel>();
|
||||
|
|
@ -105,7 +108,12 @@ bool ParticipantDeviceListModel::add(std::shared_ptr<linphone::ParticipantDevice
|
|||
qDebug() << "Device already exist. Send video update event";
|
||||
deviceModel->updateVideoEnabled();
|
||||
return false;
|
||||
}else if(deviceToAddAddr->equal(deviceModel->getDevice()->getAddress())){// Address is the same (same device) but the model is using another linphone object. Replace it.
|
||||
deviceModel->updateVideoEnabled();
|
||||
removeRow(row);
|
||||
break;
|
||||
}
|
||||
++row;
|
||||
}
|
||||
bool addMe = isMe(deviceToAdd);
|
||||
auto deviceModel = ParticipantDeviceModel::create(mCallModel, deviceToAdd, addMe);
|
||||
|
|
@ -113,9 +121,18 @@ bool ParticipantDeviceListModel::add(std::shared_ptr<linphone::ParticipantDevice
|
|||
connect(deviceModel.get(), &ParticipantDeviceModel::isSpeakingChanged, this, &ParticipantDeviceListModel::onParticipantDeviceSpeaking);
|
||||
ProxyListModel::add<ParticipantDeviceModel>(deviceModel);
|
||||
qDebug() << "Device added. Count=" << mList.count();
|
||||
QStringList debugDevices;
|
||||
for(auto i : mList){
|
||||
auto item = i.objectCast<ParticipantDeviceModel>();
|
||||
debugDevices.push_back( item->getAddress());
|
||||
}
|
||||
qDebug() << debugDevices.join("\n");
|
||||
if( addMe){
|
||||
qDebug() << "Added a me device";
|
||||
emit meChanged();
|
||||
}else if(mList.size() == 1 || (mList.size() == 2 && isMe(mList.front().objectCast<ParticipantDeviceModel>()->getDevice()))){
|
||||
mActiveSpeaker = mList.back().objectCast<ParticipantDeviceModel>();
|
||||
emit activeSpeakerChanged();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -126,7 +143,6 @@ bool ParticipantDeviceListModel::remove(std::shared_ptr<const linphone::Particip
|
|||
auto device = item.objectCast<ParticipantDeviceModel>();
|
||||
if( device->getDevice() == deviceToRemove){
|
||||
device->updateVideoEnabled();
|
||||
mActiveSpeakers.removeAll(device.get());
|
||||
removeRow(row);
|
||||
return true;
|
||||
}else
|
||||
|
|
@ -163,14 +179,8 @@ QSharedPointer<ParticipantDeviceModel> ParticipantDeviceListModel::getMe(int * i
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
ParticipantDeviceModel* ParticipantDeviceListModel::getLastActiveSpeaking() const{
|
||||
if( mActiveSpeakers.size() == 0){
|
||||
if( mList.size() == 0)
|
||||
return getMe().get();
|
||||
else
|
||||
return mList.back().objectCast<ParticipantDeviceModel>().get();
|
||||
}else
|
||||
return mActiveSpeakers.first();
|
||||
ParticipantDeviceModel* ParticipantDeviceListModel::getActiveSpeakerModel() const{
|
||||
return mActiveSpeaker.get();
|
||||
}
|
||||
|
||||
bool ParticipantDeviceListModel::isMe(std::shared_ptr<linphone::ParticipantDevice> deviceToCheck)const{
|
||||
|
|
@ -280,6 +290,13 @@ void ParticipantDeviceListModel::onParticipantDeviceMediaAvailabilityChanged(con
|
|||
else
|
||||
onParticipantDeviceAdded(participantDevice);
|
||||
}
|
||||
void ParticipantDeviceListModel::onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice>& participantDevice){
|
||||
auto device = get(participantDevice);
|
||||
if( device){
|
||||
mActiveSpeaker = device;
|
||||
emit activeSpeakerChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged(const std::shared_ptr<const linphone::ParticipantDevice> & participantDevice, bool isSpeaking){
|
||||
auto device = get(participantDevice);
|
||||
|
|
@ -288,14 +305,5 @@ void ParticipantDeviceListModel::onParticipantDeviceIsSpeakingChanged(const std:
|
|||
}
|
||||
|
||||
void ParticipantDeviceListModel::onParticipantDeviceSpeaking(){
|
||||
auto deviceModel = qobject_cast<ParticipantDeviceModel*>(sender());
|
||||
bool changed = false;
|
||||
// Me should not be in the list.
|
||||
if( !deviceModel->isMe() && (mActiveSpeakers.size() == 0 || deviceModel->getIsSpeaking())) {// Ensure to have at least one last active speaker
|
||||
changed = mActiveSpeakers.removeAll(deviceModel) > 0;
|
||||
mActiveSpeakers.push_front(deviceModel);
|
||||
changed = true;
|
||||
}
|
||||
if(changed)
|
||||
emit participantSpeaking(deviceModel);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,12 +47,13 @@ public:
|
|||
bool remove(std::shared_ptr<const linphone::ParticipantDevice> deviceToAdd);
|
||||
QSharedPointer<ParticipantDeviceModel> get(std::shared_ptr<const linphone::ParticipantDevice> deviceToGet, int * index = nullptr);
|
||||
QSharedPointer<ParticipantDeviceModel> getMe(int * index = nullptr)const;
|
||||
ParticipantDeviceModel* getLastActiveSpeaking() const;
|
||||
ParticipantDeviceModel* getActiveSpeakerModel() const;
|
||||
|
||||
bool isMe(std::shared_ptr<linphone::ParticipantDevice> device)const;
|
||||
bool isMeAlone() const;
|
||||
|
||||
public slots:
|
||||
void onActiveSpeakerParticipantDevice(const std::shared_ptr<const linphone::ParticipantDevice>& participantDevice);
|
||||
void onConferenceModelChanged ();
|
||||
void onSecurityLevelChanged(std::shared_ptr<const linphone::Address> device);
|
||||
void onParticipantAdded(const std::shared_ptr<const linphone::Participant> & participant);
|
||||
|
|
@ -66,6 +67,7 @@ public slots:
|
|||
void onParticipantDeviceSpeaking();
|
||||
|
||||
signals:
|
||||
void activeSpeakerChanged();
|
||||
void securityLevelChanged(std::shared_ptr<const linphone::Address> device);
|
||||
void participantSpeaking(ParticipantDeviceModel *speakingDevice);
|
||||
void conferenceCreated();
|
||||
|
|
@ -73,7 +75,8 @@ signals:
|
|||
|
||||
private:
|
||||
CallModel * mCallModel = nullptr;
|
||||
QList<ParticipantDeviceModel*> mActiveSpeakers;// First item is last speaker
|
||||
QSharedPointer<ParticipantDeviceModel> mActiveSpeaker;
|
||||
//QList<ParticipantDeviceModel*> mActiveSpeakers;// First item is last speaker
|
||||
bool mInitialized = false;
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,6 +31,10 @@
|
|||
// =============================================================================
|
||||
|
||||
ParticipantDeviceProxyModel::ParticipantDeviceProxyModel (QObject *parent) : SortFilterProxyModel(parent){
|
||||
mDeleteSourceModel = true;
|
||||
}
|
||||
|
||||
ParticipantDeviceProxyModel::~ParticipantDeviceProxyModel(){
|
||||
}
|
||||
|
||||
bool ParticipantDeviceProxyModel::filterAcceptsRow (
|
||||
|
|
@ -57,9 +61,9 @@ ParticipantDeviceModel *ParticipantDeviceProxyModel::getAt(int row){
|
|||
return sourceModel()->data(sourceIndex).value<ParticipantDeviceModel *>();
|
||||
}
|
||||
|
||||
ParticipantDeviceModel* ParticipantDeviceProxyModel::getLastActiveSpeaking(){
|
||||
ParticipantDeviceModel* ParticipantDeviceProxyModel::getActiveSpeakerModel(){
|
||||
auto listModel = qobject_cast<ParticipantDeviceListModel*>(sourceModel());
|
||||
return listModel ? listModel->getLastActiveSpeaking() : nullptr;
|
||||
return listModel ? listModel->getActiveSpeakerModel() : nullptr;
|
||||
}
|
||||
|
||||
CallModel * ParticipantDeviceProxyModel::getCallModel() const{
|
||||
|
|
@ -74,28 +78,31 @@ ParticipantDeviceModel * ParticipantDeviceProxyModel::getMe() const{
|
|||
bool ParticipantDeviceProxyModel::isShowMe() const{
|
||||
return mShowMe;
|
||||
}
|
||||
|
||||
|
||||
void ParticipantDeviceProxyModel::connectTo(ParticipantDeviceListModel* model){
|
||||
connect(model, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::onCountChanged);
|
||||
connect(model, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::onParticipantSpeaking);
|
||||
connect(model, &ParticipantDeviceListModel::conferenceCreated, this, &ParticipantDeviceProxyModel::conferenceCreated);
|
||||
connect(model, &ParticipantDeviceListModel::meChanged, this, &ParticipantDeviceProxyModel::meChanged);
|
||||
connect(model, &ParticipantDeviceListModel::activeSpeakerChanged, this, &ParticipantDeviceProxyModel::activeSpeakerChanged);
|
||||
}
|
||||
void ParticipantDeviceProxyModel::setCallModel(CallModel * callModel){
|
||||
setFilterType(1);
|
||||
mCallModel = callModel;
|
||||
auto sourceModel = new ParticipantDeviceListModel(mCallModel);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::onCountChanged);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::onParticipantSpeaking);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::conferenceCreated, this, &ParticipantDeviceProxyModel::conferenceCreated);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::meChanged, this, &ParticipantDeviceProxyModel::meChanged);
|
||||
setSourceModel(sourceModel);
|
||||
deleteSourceModel();
|
||||
auto newSourceModel = new ParticipantDeviceListModel(mCallModel);
|
||||
connectTo(newSourceModel);
|
||||
setSourceModel(newSourceModel);
|
||||
emit countChanged();
|
||||
emit meChanged();
|
||||
}
|
||||
|
||||
void ParticipantDeviceProxyModel::setParticipant(ParticipantModel * participant){
|
||||
setFilterType(0);
|
||||
auto sourceModel = participant->getParticipantDevices().get();
|
||||
connect(sourceModel, &ParticipantDeviceListModel::countChanged, this, &ParticipantDeviceProxyModel::countChanged);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::participantSpeaking, this, &ParticipantDeviceProxyModel::onParticipantSpeaking);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::conferenceCreated, this, &ParticipantDeviceProxyModel::conferenceCreated);
|
||||
connect(sourceModel, &ParticipantDeviceListModel::meChanged, this, &ParticipantDeviceProxyModel::meChanged);
|
||||
setSourceModel(sourceModel);
|
||||
deleteSourceModel();
|
||||
auto newSourceModel = participant->getParticipantDevices().get();
|
||||
connectTo(newSourceModel);
|
||||
setSourceModel(newSourceModel);
|
||||
emit countChanged();
|
||||
emit meChanged();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,12 +42,15 @@ public:
|
|||
Q_PROPERTY(CallModel * callModel READ getCallModel WRITE setCallModel NOTIFY callModelChanged)
|
||||
Q_PROPERTY(bool showMe READ isShowMe WRITE setShowMe NOTIFY showMeChanged)
|
||||
Q_PROPERTY(ParticipantDeviceModel * me READ getMe NOTIFY meChanged)
|
||||
Q_PROPERTY(ParticipantDeviceModel* activeSpeaker READ getActiveSpeakerModel NOTIFY activeSpeakerChanged)
|
||||
|
||||
ParticipantDeviceProxyModel (QObject *parent = nullptr);
|
||||
~ParticipantDeviceProxyModel();
|
||||
|
||||
Q_INVOKABLE ParticipantDeviceModel* getAt(int row);
|
||||
Q_INVOKABLE ParticipantDeviceModel* getLastActiveSpeaking();
|
||||
ParticipantDeviceModel * getMe() const;
|
||||
ParticipantDeviceModel* getActiveSpeakerModel();
|
||||
ParticipantDeviceModel* getMe() const;
|
||||
|
||||
CallModel * getCallModel() const;
|
||||
bool isShowMe() const;
|
||||
|
||||
|
|
@ -56,11 +59,14 @@ public:
|
|||
void setParticipant(ParticipantModel * participant);
|
||||
void setShowMe(const bool& show);
|
||||
|
||||
void connectTo(ParticipantDeviceListModel* model);
|
||||
|
||||
public slots:
|
||||
void onCountChanged();
|
||||
void onParticipantSpeaking(ParticipantDeviceModel * speakingDevice);
|
||||
|
||||
signals:
|
||||
void activeSpeakerChanged();
|
||||
void callModelChanged();
|
||||
void showMeChanged();
|
||||
void meChanged();
|
||||
|
|
@ -71,7 +77,6 @@ protected:
|
|||
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
virtual bool lessThan (const QModelIndex &left, const QModelIndex &right) const override;
|
||||
|
||||
QSharedPointer<ParticipantDeviceListModel> mDevices;
|
||||
CallModel * mCallModel;
|
||||
bool mShowMe = true;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -92,8 +92,11 @@ void ParticipantProxyModel::setChatRoomModel(ChatRoomModel * chatRoomModel){
|
|||
connect(participants, &ParticipantListModel::countChanged, this, &ParticipantProxyModel::countChanged);
|
||||
setSourceModel(participants);
|
||||
emit participantListModelChanged();
|
||||
for(int i = 0 ; i < participants->getCount() ; ++i)
|
||||
emit addressAdded(participants->getAt<ParticipantModel>(i)->getSipAddress());
|
||||
for(int i = 0 ; i < participants->getCount() ; ++i) {
|
||||
auto participant = participants->getAt<ParticipantModel>(i);
|
||||
connect(participant.get(), &ParticipantModel::invitationTimeout, this, &ParticipantProxyModel::removeModel);
|
||||
emit addressAdded(participant->getSipAddress());
|
||||
}
|
||||
}else if(!sourceModel()){
|
||||
auto model = new ParticipantListModel((ChatRoomModel*)nullptr, this);
|
||||
connect(model, &ParticipantListModel::countChanged, this, &ParticipantProxyModel::countChanged);
|
||||
|
|
@ -113,8 +116,11 @@ void ParticipantProxyModel::setConferenceModel(ConferenceModel * conferenceModel
|
|||
connect(participants, &ParticipantListModel::countChanged, this, &ParticipantProxyModel::countChanged);
|
||||
setSourceModel(participants);
|
||||
emit participantListModelChanged();
|
||||
for(int i = 0 ; i < participants->getCount() ; ++i)
|
||||
emit addressAdded(participants->getAt<ParticipantModel>(i)->getSipAddress());
|
||||
for(int i = 0 ; i < participants->getCount() ; ++i) {
|
||||
auto participant = participants->getAt<ParticipantModel>(i);
|
||||
connect(participant.get(), &ParticipantModel::invitationTimeout, this, &ParticipantProxyModel::removeModel);
|
||||
emit addressAdded(participant->getSipAddress());
|
||||
}
|
||||
}else if(!sourceModel()){
|
||||
auto model = new ParticipantListModel((ConferenceModel*)nullptr, this);
|
||||
connect(model, &ParticipantListModel::countChanged, this, &ParticipantProxyModel::countChanged);
|
||||
|
|
@ -144,12 +150,12 @@ void ParticipantProxyModel::addAddress(const QString& address){
|
|||
ParticipantListModel * participantsModel = qobject_cast<ParticipantListModel*>(sourceModel());
|
||||
if(!participantsModel->contains(address)){
|
||||
QSharedPointer<ParticipantModel> participant = QSharedPointer<ParticipantModel>::create(nullptr);
|
||||
connect(participant.get(), &ParticipantModel::invitationTimeout, this, &ParticipantProxyModel::removeModel);
|
||||
participant->setSipAddress(address);
|
||||
participantsModel->add(participant);
|
||||
if(mChatRoomModel && mChatRoomModel->getChatRoom()){// Invite and wait for its creation
|
||||
mChatRoomModel->getChatRoom()->addParticipant(Utils::interpretUrl(address));
|
||||
connect(participant.get(), &ParticipantModel::invitationTimeout, this, &ParticipantProxyModel::removeModel);
|
||||
participant->startInvitation();
|
||||
mChatRoomModel->getChatRoom()->addParticipant(Utils::interpretUrl(address));
|
||||
}
|
||||
if( mConferenceModel && mConferenceModel->getConference()){
|
||||
auto addressToInvite = Utils::interpretUrl(address);
|
||||
|
|
@ -158,23 +164,18 @@ void ParticipantProxyModel::addAddress(const QString& address){
|
|||
auto haveCall = std::find_if(currentCalls.begin(), currentCalls.end(), [addressToInvite](const std::shared_ptr<linphone::Call>& call){
|
||||
return call->getRemoteAddress()->weakEqual(addressToInvite);
|
||||
});
|
||||
participant->startInvitation();
|
||||
if( haveCall == currentCalls.end())
|
||||
mConferenceModel->getConference()->addParticipant(addressToInvite);
|
||||
else{
|
||||
runningCallsToAdd.push_back(*haveCall);
|
||||
mConferenceModel->getConference()->addParticipants(runningCallsToAdd);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
std::list<std::shared_ptr<linphone::Address>> addressesToInvite;
|
||||
addressesToInvite.push_back(addressToInvite);
|
||||
auto callParameters = CoreManager::getInstance()->getCore()->createCallParams(mConferenceModel->getConference()->getCall());
|
||||
mConferenceModel->getConference()->inviteParticipants(addressesToInvite, callParameters);*/
|
||||
|
||||
connect(participant.get(), &ParticipantModel::invitationTimeout, this, &ParticipantProxyModel::removeModel);
|
||||
participant->startInvitation();
|
||||
|
||||
mConferenceModel->getConference()->inviteParticipants(addressesToInvite, callParameters);*/
|
||||
}
|
||||
emit countChanged();
|
||||
emit addressAdded(address);
|
||||
|
|
|
|||
|
|
@ -507,7 +507,11 @@ QString AccountSettingsModel::getPrimarySipAddress () const {
|
|||
}
|
||||
|
||||
QString AccountSettingsModel::getDefaultAccountDomain() const{
|
||||
return Utils::coreStringToAppString(CoreManager::getInstance()->getCore()->getDefaultAccount()->getParams()->getDomain());
|
||||
auto account = CoreManager::getInstance()->getCore()->getDefaultAccount();
|
||||
if(account)
|
||||
return Utils::coreStringToAppString(account->getParams()->getDomain());
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -69,7 +69,6 @@ SettingsModel::SettingsModel (QObject *parent) : QObject(parent) {
|
|||
connect(coreManager->getAccountSettingsModel(), &AccountSettingsModel::accountSettingsUpdated, this, &SettingsModel::videoConferenceEnabledChanged);
|
||||
connect(coreManager->getAccountSettingsModel(), &AccountSettingsModel::accountSettingsUpdated, this, &SettingsModel::secureChatEnabledChanged);
|
||||
|
||||
|
||||
configureRlsUri();
|
||||
}
|
||||
|
||||
|
|
@ -548,12 +547,9 @@ static inline QVariantMap createMapFromVideoDefinition (const shared_ptr<const l
|
|||
QVariantMap map;
|
||||
|
||||
if (!definition) {
|
||||
Q_ASSERT(!CoreManager::getInstance()->getCore()->videoSupported());
|
||||
|
||||
map["name"] = QStringLiteral("Bad EGG");
|
||||
map["width"] = QStringLiteral("?????");
|
||||
map["height"] = QStringLiteral("?????");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
|
@ -987,9 +983,6 @@ void SettingsModel::setMediaEncryption (MediaEncryption encryption) {
|
|||
if (encryption == getMediaEncryption())
|
||||
return;
|
||||
|
||||
if (encryption != SettingsModel::MediaEncryptionZrtp)
|
||||
setLimeState(false);
|
||||
|
||||
CoreManager::getInstance()->getCore()->setMediaEncryption(
|
||||
static_cast<linphone::MediaEncryption>(encryption)
|
||||
);
|
||||
|
|
@ -1032,10 +1025,7 @@ void SettingsModel::setLimeState (const bool& state) {
|
|||
if (state == getLimeState())
|
||||
return;
|
||||
|
||||
if (state)
|
||||
setMediaEncryption(SettingsModel::MediaEncryptionZrtp);
|
||||
|
||||
CoreManager::getInstance()->getCore()->enableLimeX3Dh(!state);
|
||||
CoreManager::getInstance()->getCore()->enableLimeX3Dh(state);
|
||||
|
||||
emit limeStateChanged(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -455,8 +455,10 @@ void SipAddressesModel::handleMessageCountReset (ChatRoomModel *chatRoomModel) {
|
|||
}
|
||||
|
||||
void SipAddressesModel::handleMessageSent (const shared_ptr<linphone::ChatMessage> &message) {
|
||||
const QString peerAddress(Utils::coreStringToAppString(message->getChatRoom()->getPeerAddress()->asStringUriOnly()));
|
||||
addOrUpdateSipAddress(peerAddress, message);
|
||||
if(message->getChatRoom() && message->getChatRoom()->getPeerAddress()){
|
||||
const QString peerAddress(Utils::coreStringToAppString(message->getChatRoom()->getPeerAddress()->asStringUriOnly()));
|
||||
addOrUpdateSipAddress(peerAddress, message);
|
||||
}
|
||||
}
|
||||
|
||||
void SipAddressesModel::handleIsComposingChanged (const shared_ptr<linphone::ChatRoom> &chatRoom) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ TimelineListModel::TimelineListModel(const TimelineListModel* model){
|
|||
auto newItem = qobject_cast<TimelineModel*>(item)->clone();
|
||||
connect(newItem.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
|
||||
connect(newItem.get(), &TimelineModel::chatRoomDeleted, this, &TimelineListModel::onChatRoomDeleted);
|
||||
connect(newItem->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
|
||||
mList << newItem;
|
||||
}
|
||||
}
|
||||
|
|
@ -141,7 +140,6 @@ QSharedPointer<TimelineModel> TimelineListModel::getTimeline(std::shared_ptr<lin
|
|||
QSharedPointer<TimelineModel> model = TimelineModel::create(this, chatRoom);
|
||||
if(model){
|
||||
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
|
||||
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
|
||||
add(model);
|
||||
return model;
|
||||
}
|
||||
|
|
@ -189,7 +187,6 @@ QSharedPointer<ChatRoomModel> TimelineListModel::getChatRoomModel(std::shared_pt
|
|||
QSharedPointer<TimelineModel> model = TimelineModel::create(this, chatRoom);
|
||||
if(model){
|
||||
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
|
||||
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
|
||||
add(model);
|
||||
return model->mChatRoomModel;
|
||||
}
|
||||
|
|
@ -249,7 +246,17 @@ void TimelineListModel::updateTimelines () {
|
|||
allChatRooms.remove_if([](std::shared_ptr<linphone::ChatRoom> chatRoom){
|
||||
if( ChatRoomModel::isTerminated(chatRoom) && chatRoom->getUnreadMessagesCount() > 0)
|
||||
chatRoom->markAsRead();
|
||||
return !chatRoom->hasCapability((int)linphone::ChatRoomCapabilities::Basic) && chatRoom->getConferenceAddress() && chatRoom->getHistoryEventsSize() == 0;
|
||||
if(chatRoom->getState() == linphone::ChatRoom::State::Deleted)
|
||||
return true;
|
||||
if(!chatRoom->hasCapability((int)linphone::ChatRoomCapabilities::Basic)){
|
||||
auto conferenceAddress = chatRoom->getConferenceAddress();
|
||||
if( conferenceAddress && conferenceAddress->getDomain() == Constants::LinphoneDomain) {
|
||||
QString conferenceAddressStr = Utils::coreStringToAppString(conferenceAddress->asStringUriOnly());
|
||||
if( conferenceAddressStr.contains("conf-id"))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
//Remove no more chat rooms
|
||||
|
|
@ -294,7 +301,6 @@ void TimelineListModel::updateTimelines () {
|
|||
QSharedPointer<TimelineModel> model = TimelineModel::create(this, dbChatRoom, callLogs);
|
||||
if( model){
|
||||
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
|
||||
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
|
||||
add(model);
|
||||
}
|
||||
}
|
||||
|
|
@ -306,12 +312,10 @@ void TimelineListModel::add (QSharedPointer<TimelineModel> timeline){
|
|||
auto chatRoomModel = timeline->getChatRoomModel();
|
||||
auto chatRoom = chatRoomModel->getChatRoom();
|
||||
connect(timeline.get(), &TimelineModel::chatRoomDeleted, this, &TimelineListModel::onChatRoomDeleted);
|
||||
if( !chatRoomModel->haveConferenceAddress() || chatRoom->getHistoryEventsSize() != 0) {
|
||||
connect(chatRoomModel, &ChatRoomModel::lastUpdateTimeChanged, this, &TimelineListModel::updated);
|
||||
ProxyListModel::add(timeline);
|
||||
emit layoutChanged();
|
||||
emit countChanged();
|
||||
}
|
||||
connect(chatRoomModel, &ChatRoomModel::lastUpdateTimeChanged, this, &TimelineListModel::updated);
|
||||
ProxyListModel::add(timeline);
|
||||
emit layoutChanged();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void TimelineListModel::removeChatRoomModel(QSharedPointer<ChatRoomModel> model){
|
||||
|
|
@ -334,7 +338,10 @@ void TimelineListModel::select(ChatRoomModel * chatRoomModel){
|
|||
if(chatRoomModel) {
|
||||
auto timeline = getTimeline(chatRoomModel->getChatRoom(), false);
|
||||
if(timeline){
|
||||
timeline->setSelected(true);
|
||||
if(timeline->isUpdating())
|
||||
timeline->delaySelected();
|
||||
else
|
||||
timeline->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -356,7 +363,6 @@ void TimelineListModel::onChatRoomStateChanged(const std::shared_ptr<linphone::C
|
|||
QSharedPointer<TimelineModel> model = TimelineModel::create(this, chatRoom);
|
||||
if(model){
|
||||
connect(model.get(), SIGNAL(selectedChanged(bool)), this, SLOT(onSelectedHasChanged(bool)));
|
||||
connect(model->getChatRoomModel(), &ChatRoomModel::allEntriesRemoved, this, &TimelineListModel::removeChatRoomModel);
|
||||
add(model);
|
||||
}
|
||||
}else if(state == linphone::ChatRoom::State::Deleted || state == linphone::ChatRoom::State::Terminated){
|
||||
|
|
@ -368,6 +374,11 @@ void TimelineListModel::onChatRoomStateChanged(const std::shared_ptr<linphone::C
|
|||
remove(timeline);// This will call removeRows()
|
||||
}
|
||||
}
|
||||
}else if(state == linphone::ChatRoom::State::CreationFailed){
|
||||
auto timeline = getTimeline(chatRoom, false);
|
||||
if(timeline) {
|
||||
remove(timeline);// This will call removeRows()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@ TimelineModel::TimelineModel (std::shared_ptr<linphone::ChatRoom> chatRoom, cons
|
|||
QObject::connect(this, &TimelineModel::selectedChanged, this, &TimelineModel::updateUnreadCount);
|
||||
QObject::connect(CoreManager::getInstance()->getAccountSettingsModel(), &AccountSettingsModel::defaultAccountChanged, this, &TimelineModel::onDefaultAccountChanged);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::chatRoomDeleted, this, &TimelineModel::onChatRoomDeleted);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::updatingChanged, this, &TimelineModel::updatingChanged);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::stateChanged, this, &TimelineModel::onChatRoomStateChanged);
|
||||
}
|
||||
if(chatRoom){
|
||||
mChatRoomListener = std::make_shared<ChatRoomListener>();
|
||||
|
|
@ -103,6 +105,8 @@ TimelineModel::TimelineModel(const TimelineModel * model){
|
|||
QObject::connect(this, &TimelineModel::selectedChanged, this, &TimelineModel::updateUnreadCount);
|
||||
QObject::connect(CoreManager::getInstance()->getAccountSettingsModel(), &AccountSettingsModel::defaultAccountChanged, this, &TimelineModel::onDefaultAccountChanged);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::chatRoomDeleted, this, &TimelineModel::onChatRoomDeleted);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::updatingChanged, this, &TimelineModel::updatingChanged);
|
||||
QObject::connect(mChatRoomModel.get(), &ChatRoomModel::stateChanged, this, &TimelineModel::onChatRoomStateChanged);
|
||||
}
|
||||
if(mChatRoomModel->getChatRoom()){
|
||||
mChatRoomListener = model->mChatRoomListener;
|
||||
|
|
@ -141,6 +145,10 @@ int TimelineModel::getPresenceStatus() const{
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool TimelineModel::isUpdating() const{
|
||||
return !mChatRoomModel || mChatRoomModel->isUpdating();
|
||||
}
|
||||
|
||||
ChatRoomModel *TimelineModel::getChatRoomModel() const{
|
||||
return mChatRoomModel.get();
|
||||
}
|
||||
|
|
@ -165,6 +173,15 @@ void TimelineModel::setSelected(const bool& selected){
|
|||
}
|
||||
}
|
||||
|
||||
void TimelineModel::delaySelected(){
|
||||
if( mChatRoomModel->getState() == LinphoneEnums::ChatRoomStateCreated){
|
||||
QTimer::singleShot(200, [&](){// Delay process in order to let GUI time for Timeline building/linking before doing actions
|
||||
setSelected(true);
|
||||
});
|
||||
}else
|
||||
mDelaySelection = true;
|
||||
}
|
||||
|
||||
void TimelineModel::updateUnreadCount(){
|
||||
if(!mSelected){// updateUnreadCount is called when selected has changed;: So if mSelected is false then we are going out of it.
|
||||
mChatRoomModel->resetMessageCount();// The reset will appear when the chat room has "mark as read enabled", that means that we should have read messages when going out.
|
||||
|
|
@ -230,4 +247,11 @@ void TimelineModel::onChatMessageParticipantImdnStateChanged(const std::shared_p
|
|||
|
||||
void TimelineModel::onChatRoomDeleted(){
|
||||
emit chatRoomDeleted();
|
||||
}
|
||||
|
||||
void TimelineModel::onChatRoomStateChanged(){
|
||||
if(mDelaySelection && mChatRoomModel->getState() == LinphoneEnums::ChatRoomStateCreated){
|
||||
mDelaySelection = false;
|
||||
setSelected(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@ public:
|
|||
Q_PROPERTY(ChatRoomModel* chatRoomModel READ getChatRoomModel CONSTANT)
|
||||
|
||||
Q_PROPERTY(bool selected MEMBER mSelected WRITE setSelected NOTIFY selectedChanged)
|
||||
Q_PROPERTY(bool updating READ isUpdating NOTIFY updatingChanged)
|
||||
|
||||
|
||||
QString getFullPeerAddress() const;
|
||||
|
|
@ -61,7 +62,10 @@ public:
|
|||
QString getAvatar() const;
|
||||
int getPresenceStatus() const;
|
||||
|
||||
bool isUpdating() const;
|
||||
|
||||
void setSelected(const bool& selected);
|
||||
void delaySelected();
|
||||
|
||||
Q_INVOKABLE ChatRoomModel* getChatRoomModel() const;
|
||||
|
||||
|
|
@ -102,6 +106,7 @@ public slots:
|
|||
void updateUnreadCount();
|
||||
void onDefaultAccountChanged();
|
||||
void onChatRoomDeleted();
|
||||
void onChatRoomStateChanged();
|
||||
|
||||
signals:
|
||||
void fullPeerAddressChanged();
|
||||
|
|
@ -112,9 +117,12 @@ signals:
|
|||
void selectedChanged(bool selected);
|
||||
void conferenceLeft();
|
||||
void chatRoomDeleted();
|
||||
void updatingChanged();
|
||||
|
||||
private:
|
||||
|
||||
bool mDelaySelection = false;
|
||||
|
||||
void connectTo(ChatRoomListener * listener);
|
||||
std::shared_ptr<ChatRoomListener> mChatRoomListener;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ constexpr int Constants::ThumbnailImageFileHeight;
|
|||
constexpr qint64 Constants::FileSizeLimit;
|
||||
|
||||
constexpr char Constants::DefaultXmlrpcUri[];
|
||||
constexpr char Constants::DefaultUploadLogsServer[];
|
||||
constexpr char Constants::DefaultConferenceURI[];
|
||||
constexpr char Constants::DefaultVideoConferenceURI[];
|
||||
constexpr char Constants::DefaultLimeServerURL[];
|
||||
|
|
|
|||
|
|
@ -36,21 +36,17 @@ public:
|
|||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
||||
static constexpr char WindowIconPath[] = ":/assets/images/linphone_logo.svg";
|
||||
static constexpr char DefaultLocale[] = "en";
|
||||
|
||||
static constexpr char ApplicationMinimalQtVersion[] = "5.10.0";
|
||||
static constexpr char DefaultFont[] = "Noto Sans";
|
||||
|
||||
static constexpr size_t MaxLogsCollectionSize = 10485760*5; // 50MB.
|
||||
|
||||
|
||||
#ifdef ENABLE_UPDATE_CHECK
|
||||
static constexpr int VersionUpdateCheckInterval = 86400000; // 24 hours in milliseconds.
|
||||
#endif // ifdef ENABLE_UPDATE_CHECK
|
||||
|
||||
static constexpr char DefaultXmlrpcUri[] = "https://subscribe.linphone.org:444/wizard.php";
|
||||
static constexpr char LinphoneDomain[] = "sip.linphone.org";
|
||||
static constexpr char DefaultUploadLogsServer[] = "https://www.linphone.org:444/lft.php";
|
||||
static constexpr char DefaultContactParameters[] = "message-expires=604800";
|
||||
static constexpr char DefaultContactParametersOnRemove[] = "message-expires=0";
|
||||
static constexpr int DefaultExpires = 3600;
|
||||
|
|
@ -69,9 +65,6 @@ public:
|
|||
static constexpr char LinphoneBZip2_dll[] = "https://www.linphone.org/releases/windows/tools/bzip2/bzip2.dll";
|
||||
static constexpr char DefaultRlsUri[] = "sips:rls@sip.linphone.org";
|
||||
static constexpr char DefaultLogsEmail[] = "linphone-desktop@belledonne-communications.com";
|
||||
static constexpr char DefaultConferenceURI[] = "sip:conference-factory@sip.linphone.org";
|
||||
static constexpr char DefaultVideoConferenceURI[] = "sip:videoconference-factory@sip.linphone.org";
|
||||
static constexpr char DefaultLimeServerURL[] = "https://lime.linphone.org/lime-server/lime-server.php";
|
||||
|
||||
static constexpr char DefaultFlexiAPIURL[] = "http://fs-test-sandbox.linphone.org/flexiapi/api/";// Need "/" at the end
|
||||
static constexpr char RemoteProvisioningURL[] = "http://fs-test-sandbox.linphone.org/flexiapi/provisioning";
|
||||
|
|
@ -94,7 +87,18 @@ public:
|
|||
static constexpr qint64 FileSizeLimit = 524288000;// In Bytes.
|
||||
static constexpr int ThumbnailImageFileWidth = 100;
|
||||
static constexpr int ThumbnailImageFileHeight = 100;
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// LINPHONE
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
static constexpr char LinphoneDomain[] = "sip.linphone.org"; // Use for checking if config are a Linphone
|
||||
static constexpr char WindowIconPath[] = ":/assets/images/linphone_logo.svg";
|
||||
static constexpr char ApplicationMinimalQtVersion[] = "5.10.0";
|
||||
static constexpr char DefaultConferenceURI[] = "sip:conference-factory@sip.linphone.org"; // Default for a Linphone account
|
||||
static constexpr char DefaultVideoConferenceURI[] = "sip:videoconference-factory@sip.linphone.org"; // Default for a Linphone account
|
||||
static constexpr char DefaultLimeServerURL[] = "https://lime.linphone.org/lime-server/lime-server.php"; // Default for a Linphone account
|
||||
|
||||
static constexpr char PathAssistantConfig[] = "/" EXECUTABLE_NAME "/assistant/";
|
||||
static constexpr char PathAvatars[] = "/avatars/";
|
||||
static constexpr char PathCaptures[] = "/" EXECUTABLE_NAME "/captures/";
|
||||
|
|
@ -146,8 +150,6 @@ public:
|
|||
// 3 = CPIM on basic chat rooms
|
||||
// 4 = RTP bundle mode
|
||||
// 5 = Video Conference URI
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// CISCO
|
||||
//--------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -25,14 +25,19 @@
|
|||
// =============================================================================
|
||||
|
||||
void LinphoneEnums::registerMetaTypes(){
|
||||
qRegisterMetaType<LinphoneEnums::MediaEncryption>();
|
||||
qRegisterMetaType<LinphoneEnums::FriendCapability>();
|
||||
qRegisterMetaType<LinphoneEnums::EventLogType>();
|
||||
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
|
||||
qRegisterMetaType<LinphoneEnums::CallStatus>();
|
||||
qRegisterMetaType<LinphoneEnums::ChatMessageState>();
|
||||
qRegisterMetaType<LinphoneEnums::ChatRoomState>();
|
||||
qRegisterMetaType<LinphoneEnums::ConferenceLayout>();
|
||||
qRegisterMetaType<LinphoneEnums::TunnelMode>();
|
||||
qRegisterMetaType<LinphoneEnums::ConferenceInfoState>();
|
||||
qRegisterMetaType<LinphoneEnums::ConferenceSchedulerState>();
|
||||
qRegisterMetaType<LinphoneEnums::EventLogType>();
|
||||
qRegisterMetaType<LinphoneEnums::FriendCapability>();
|
||||
qRegisterMetaType<LinphoneEnums::MediaEncryption>();
|
||||
qRegisterMetaType<LinphoneEnums::ParticipantDeviceState>();
|
||||
qRegisterMetaType<LinphoneEnums::RecorderState>();
|
||||
qRegisterMetaType<LinphoneEnums::TunnelMode>();
|
||||
qRegisterMetaType<LinphoneEnums::TransportType>();
|
||||
}
|
||||
|
||||
linphone::MediaEncryption LinphoneEnums::toLinphone(const LinphoneEnums::MediaEncryption& data){
|
||||
|
|
@ -63,6 +68,14 @@ LinphoneEnums::ChatMessageState LinphoneEnums::fromLinphone(const linphone::Chat
|
|||
return static_cast<LinphoneEnums::ChatMessageState>(data);
|
||||
}
|
||||
|
||||
linphone::ChatRoom::State LinphoneEnums::toLinphone(const LinphoneEnums::ChatRoomState& data){
|
||||
return static_cast<linphone::ChatRoom::State>(data);
|
||||
}
|
||||
|
||||
LinphoneEnums::ChatRoomState LinphoneEnums::fromLinphone(const linphone::ChatRoom::State& data){
|
||||
return static_cast<LinphoneEnums::ChatRoomState>(data);
|
||||
}
|
||||
|
||||
linphone::Call::Status LinphoneEnums::toLinphone(const LinphoneEnums::CallStatus& data){
|
||||
return static_cast<linphone::Call::Status>(data);
|
||||
}
|
||||
|
|
@ -89,6 +102,14 @@ LinphoneEnums::ConferenceInfoState LinphoneEnums::fromLinphone(const linphone::C
|
|||
return static_cast<LinphoneEnums::ConferenceInfoState>(state);
|
||||
}
|
||||
|
||||
linphone::ConferenceScheduler::State LinphoneEnums::toLinphone(const LinphoneEnums::ConferenceSchedulerState& state){
|
||||
return static_cast<linphone::ConferenceScheduler::State>(state);
|
||||
}
|
||||
|
||||
LinphoneEnums::ConferenceSchedulerState LinphoneEnums::fromLinphone(const linphone::ConferenceScheduler::State& state){
|
||||
return static_cast<LinphoneEnums::ConferenceSchedulerState>(state);
|
||||
}
|
||||
|
||||
linphone::ParticipantDeviceState LinphoneEnums::toLinphone(const LinphoneEnums::ParticipantDeviceState& state){
|
||||
return static_cast<linphone::ParticipantDeviceState>(state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,8 +95,25 @@ enum ChatMessageState {
|
|||
};
|
||||
Q_ENUM_NS(ChatMessageState)
|
||||
|
||||
linphone::ChatMessage::State toLinphone(const LinphoneEnums::ChatMessageState& capability);
|
||||
LinphoneEnums::ChatMessageState fromLinphone(const linphone::ChatMessage::State& capability);
|
||||
linphone::ChatMessage::State toLinphone(const LinphoneEnums::ChatMessageState& data);
|
||||
LinphoneEnums::ChatMessageState fromLinphone(const linphone::ChatMessage::State& data);
|
||||
|
||||
enum ChatRoomState {
|
||||
ChatRoomStateNone = int(linphone::ChatRoom::State::None),
|
||||
ChatRoomStateInstantiated = int(linphone::ChatRoom::State::Instantiated),
|
||||
ChatRoomStateCreationPending = int(linphone::ChatRoom::State::CreationPending),
|
||||
ChatRoomStateCreated = int(linphone::ChatRoom::State::Created),
|
||||
ChatRoomStateCreationFailed = int(linphone::ChatRoom::State::CreationFailed),
|
||||
ChatRoomStateTerminationPending = int(linphone::ChatRoom::State::TerminationPending),
|
||||
ChatRoomStateTerminated = int(linphone::ChatRoom::State::Terminated),
|
||||
ChatRoomStateTerminationFailed = int(linphone::ChatRoom::State::TerminationFailed),
|
||||
ChatRoomStateDeleted = int(linphone::ChatRoom::State::Deleted),
|
||||
};
|
||||
Q_ENUM_NS(ChatRoomState)
|
||||
|
||||
linphone::ChatRoom::State toLinphone(const LinphoneEnums::ChatRoomState& data);
|
||||
LinphoneEnums::ChatRoomState fromLinphone(const linphone::ChatRoom::State& data);
|
||||
|
||||
|
||||
enum CallStatus {
|
||||
CallStatusDeclined = int(linphone::Call::Status::Declined),
|
||||
|
|
@ -133,6 +150,18 @@ Q_ENUM_NS(ConferenceInfoState)
|
|||
linphone::ConferenceInfo::State toLinphone(const LinphoneEnums::ConferenceInfoState& state);
|
||||
LinphoneEnums::ConferenceInfoState fromLinphone(const linphone::ConferenceInfo::State& state);
|
||||
|
||||
enum ConferenceSchedulerState {
|
||||
ConferenceSchedulerStateAllocationPending = int(linphone::ConferenceScheduler::State::AllocationPending),
|
||||
ConferenceSchedulerStateError = int(linphone::ConferenceScheduler::State::Error),
|
||||
ConferenceSchedulerStateIdle = int(linphone::ConferenceScheduler::State::Idle),
|
||||
ConferenceSchedulerStateReady = int(linphone::ConferenceScheduler::State::Ready),
|
||||
ConferenceSchedulerStateUpdating = int(linphone::ConferenceScheduler::State::Updating)
|
||||
};
|
||||
Q_ENUM_NS(ConferenceSchedulerState)
|
||||
|
||||
linphone::ConferenceScheduler::State toLinphone(const LinphoneEnums::ConferenceSchedulerState& state);
|
||||
LinphoneEnums::ConferenceSchedulerState fromLinphone(const linphone::ConferenceScheduler::State& state);
|
||||
|
||||
|
||||
enum ParticipantDeviceState {
|
||||
ParticipantDeviceStateJoining = int(linphone::ParticipantDeviceState::Joining),
|
||||
|
|
@ -190,14 +219,16 @@ void fromString(const QString& transportType, LinphoneEnums::TransportType *tran
|
|||
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::CallStatus)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ChatMessageState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ChatRoomState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ConferenceLayout)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ConferenceInfoState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ConferenceSchedulerState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::EventLogType)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::FriendCapability)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::MediaEncryption)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::ParticipantDeviceState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::RecorderState)
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::TunnelMode)
|
||||
|
||||
Q_DECLARE_METATYPE(LinphoneEnums::TransportType)
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ ColumnLayout{
|
|||
}
|
||||
|
||||
function add(item){
|
||||
if( !grid.isLayoutWillChanged() || !transitionningTimer.running)
|
||||
if( !grid.isLayoutWillChanged())
|
||||
appendItem(item)
|
||||
else
|
||||
bufferModels.append(item)
|
||||
|
|
@ -34,7 +34,7 @@ ColumnLayout{
|
|||
}
|
||||
|
||||
function tryToAdd(item){
|
||||
if( !grid.isLayoutWillChanged() || !transitionningTimer.running) {
|
||||
if( !grid.isLayoutWillChanged()) {
|
||||
appendItem(item)
|
||||
return true
|
||||
}else
|
||||
|
|
@ -51,21 +51,7 @@ ColumnLayout{
|
|||
|
||||
property int transitionCount : 0
|
||||
property var bufferModels : ListModel{}
|
||||
property int maxTransitionTime: 250
|
||||
Timer{
|
||||
id: transitionningTimer
|
||||
running: false
|
||||
interval: maxTransitionTime + 5
|
||||
onTriggered: updateBuffers()
|
||||
}
|
||||
function startTransition(){
|
||||
transitionningTimer.restart()
|
||||
}
|
||||
function updateBuffers(){
|
||||
while(bufferModels.count > 0 && tryToAdd(bufferModels.get(0))){
|
||||
bufferModels.remove(0,1)
|
||||
}
|
||||
}
|
||||
|
||||
onWidthChanged: grid.updateLayout()
|
||||
onHeightChanged: grid.updateLayout()
|
||||
GridView{
|
||||
|
|
@ -120,63 +106,6 @@ ColumnLayout{
|
|||
interactive: false
|
||||
model: DelegateModel{}
|
||||
|
||||
//------------------- ANIMATIONS
|
||||
property Transition defaultTransition: Transition {
|
||||
SequentialAnimation {
|
||||
ScriptAction {
|
||||
script: {
|
||||
mainLayout.startTransition()
|
||||
}
|
||||
}
|
||||
ParallelAnimation {
|
||||
NumberAnimation { properties: "x,y"; duration: mainLayout.maxTransitionTime }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
SequentialAnimation {
|
||||
ScriptAction {
|
||||
script: {
|
||||
mainLayout.startTransition()
|
||||
}
|
||||
}
|
||||
ParallelAnimation {
|
||||
NumberAnimation { property: "opacity"; from: 0; duration: mainLayout.maxTransitionTime }
|
||||
NumberAnimation { properties: "x,y"; from: 0; duration: mainLayout.maxTransitionTime; easing.type: Easing.OutBounce }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addDisplaced: defaultTransition
|
||||
displaced: defaultTransition
|
||||
move: defaultTransition
|
||||
moveDisplaced: defaultTransition
|
||||
remove: Transition {
|
||||
SequentialAnimation {
|
||||
PropertyAction { target: grid; property: "GridView.delayRemove"; value: true }
|
||||
ScriptAction {
|
||||
script: {
|
||||
mainLayout.startTransition()
|
||||
}
|
||||
}
|
||||
ParallelAnimation {
|
||||
NumberAnimation { property: "opacity"; to: 0; duration: mainLayout.maxTransitionTime }
|
||||
NumberAnimation { properties: "x,y"; to: 0; duration: mainLayout.maxTransitionTime }
|
||||
}
|
||||
PropertyAction { target: grid; property: "GridView.delayRemove"; value: false }
|
||||
}
|
||||
}
|
||||
removeDisplaced: defaultTransition
|
||||
populate:defaultTransition
|
||||
|
||||
Timer{ // if cell sizes change while adding/removing an item the animation will not end at the right position.
|
||||
id: updateLayoutDelay
|
||||
interval: mainLayout.maxTransitionTime
|
||||
onTriggered: grid.updateLayout()
|
||||
}
|
||||
onItemCountChanged: {
|
||||
updateLayoutDelay.restart()
|
||||
}
|
||||
onCountChanged: grid.updateLayout()
|
||||
}
|
||||
}
|
||||
|
|
@ -17,6 +17,14 @@ Control.RadioButton{
|
|||
font.pointSize: RadioButtonStyle.pointSize
|
||||
spacing: 10
|
||||
FontMetrics{id: fontMetrics}
|
||||
|
||||
MouseArea{
|
||||
anchors.fill:parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
}
|
||||
|
||||
indicator: Rectangle {
|
||||
height: fontMetrics.height - 5
|
||||
width: height
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import Common 1.0
|
|||
import Common.Styles 1.0
|
||||
import Units 1.0
|
||||
|
||||
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
|
||||
|
||||
Item{
|
||||
id: mainItem
|
||||
property bool allYears : false // if false : years from today
|
||||
|
|
@ -33,9 +35,10 @@ Item{
|
|||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
horizontalAlignment: Qt.AlignCenter
|
||||
text: new Date(monthList.currentYear, monthList.currentMonth, 1).toLocaleString(Qt.locale(), 'MMMM yyyy')
|
||||
text: new Date(monthList.currentYear, monthList.currentMonth, 15).toLocaleString(Qt.locale(), 'MMMM yyyy')// 15 because of timezones that can change the date for localeString
|
||||
color: DatePickerStyle.title.color
|
||||
font.pointSize: DatePickerStyle.title.pointSize
|
||||
font.capitalization: Font.Capitalize
|
||||
}
|
||||
ActionButton{
|
||||
isCustom: true
|
||||
|
|
@ -62,7 +65,7 @@ Item{
|
|||
}
|
||||
|
||||
property date selectedDate: new Date()
|
||||
property int minYear: mainItem.allYears ? new Date(0,0,0).getFullYear() : new Date().getFullYear()
|
||||
property int minYear: mainItem.allYears ? new Date(0,0,1).getFullYear() : new Date().getFullYear()
|
||||
|
||||
snapMode: ListView.SnapOneItem
|
||||
orientation: Qt.Horizontal
|
||||
|
|
@ -70,7 +73,7 @@ Item{
|
|||
|
||||
// One model per month
|
||||
model: (new Date().getFullYear()- minYear + maxYears) * 12
|
||||
|
||||
currentIndex: 0
|
||||
property int currentYear: Math.floor(currentIndex / 12) + minYear
|
||||
property int currentMonth: currentIndex % 12
|
||||
|
||||
|
|
@ -87,7 +90,7 @@ Item{
|
|||
property int year: Math.floor(index / 12) + monthList.minYear
|
||||
property int month: index % 12
|
||||
property int firstDay: new Date(year, month, 1).getDay()
|
||||
|
||||
|
||||
GridLayout { // 1 month calender
|
||||
id: grid
|
||||
|
||||
|
|
@ -105,9 +108,12 @@ Item{
|
|||
|
||||
delegate: Item{
|
||||
id: cellItem
|
||||
property int day: index - 7 // 0 = top left below Sunday (-7 to 41)
|
||||
property int day: index - 7 // 0 = top left below Sunday (-7 to 41)
|
||||
property int date: day - firstDay + 1 // 1-31
|
||||
property bool selected : new Date(year, month, date).toDateString() == monthList.selectedDate.toDateString() && text.text && day >= 0
|
||||
property date cellDate: new Date(year, month, date)
|
||||
property bool selected : text.text != '-'
|
||||
&& Utils.equalDate(cellDate, monthList.selectedDate)
|
||||
&& text.text && day >= 0
|
||||
width: grid.cellMinSize
|
||||
height: width
|
||||
|
||||
|
|
@ -132,12 +138,12 @@ Item{
|
|||
: cellItem.day < 0
|
||||
? DatePickerStyle.cell.dayHeaderPointSize
|
||||
: DatePickerStyle.cell.dayPointSize
|
||||
font.bold: cellItem.day < 0 || cellItem.selected || new Date(year, month, cellItem.date).toDateString() == new Date().toDateString() // today
|
||||
font.bold: cellItem.day < 0 || cellItem.selected || Utils.equalDate(cellItem.cellDate, new Date()) // today
|
||||
text: {
|
||||
if(cellItem.day < 0)
|
||||
if(cellItem.day < 0){
|
||||
// Magic date to set day names in this order : 'S', 'M', 'T', 'W', 'T', 'F', 'S' in Locale
|
||||
return new Date(1,3,index).toLocaleString(Qt.locale(), 'ddd')[0]
|
||||
else if(new Date(year, month, cellItem.date).getMonth() == month && (!hideOldDates || new Date(year, month, cellItem.date+1) >= new Date())) // new Date use time too
|
||||
return Utils.exactDate(new Date(2000,9,index+1)).toLocaleString(Qt.locale(), 'ddd')[0].toUpperCase()
|
||||
}else if(cellItem.cellDate.getMonth() == month && (!hideOldDates || new Date(year, month, cellItem.date+1) >= new Date())) // new Date use time too
|
||||
return cellItem.date
|
||||
else
|
||||
return '-'
|
||||
|
|
@ -152,7 +158,7 @@ Item{
|
|||
enabled: text.text && text.text != '-' && cellItem.day >= 0
|
||||
|
||||
onClicked: {
|
||||
monthList.selectedDate = new Date(year, month, cellItem.date)
|
||||
monthList.selectedDate = cellItem.cellDate
|
||||
mainItem.clicked(monthList.selectedDate)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import ColorsList 1.0
|
|||
QtObject {
|
||||
property string sectionName: 'Busy'
|
||||
property color color: ColorsList.add(sectionName+'_indicator', 'q').color
|
||||
property color alternateColor: ColorsList.add(sectionName+'_indicator_alt', 'i').color
|
||||
property int duration: 1250
|
||||
property int nSpheres: 8
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Rectangle {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
default property alias _content: content.data
|
||||
property alias isDarkMode: contact.isDarkMode
|
||||
|
||||
property alias signIcon: signIcon.icon
|
||||
property alias subtitleColor: contact.subtitleColor
|
||||
|
|
|
|||
|
|
@ -144,20 +144,17 @@ ListView {
|
|||
id: _callControls
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
function useColorStatus () {
|
||||
return calls.currentIndex === index && $modelData && $modelData.status !== CallModel.CallStatusEnded
|
||||
}
|
||||
isDarkMode: calls.currentIndex === index && $modelData!=undefined && $modelData.status!=undefined && $modelData.status !== CallModel.CallStatusEnded
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
color: useColorStatus()
|
||||
color: isDarkMode
|
||||
? CallsStyle.entry.color.selected
|
||||
: CallsStyle.entry.color.normal
|
||||
subtitleColor: useColorStatus()
|
||||
subtitleColor: isDarkMode
|
||||
? CallsStyle.entry.subtitleColor.selected
|
||||
: CallsStyle.entry.subtitleColor.normal
|
||||
titleColor: useColorStatus()
|
||||
titleColor: isDarkMode
|
||||
? CallsStyle.entry.titleColor.selected
|
||||
: CallsStyle.entry.titleColor.normal
|
||||
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ Item {
|
|||
property bool isFullscreen: false
|
||||
property bool hideCamera: false
|
||||
property bool isPaused: false
|
||||
property bool deactivateCamera: false
|
||||
property bool deactivateCamera: true
|
||||
property bool isVideoEnabled: !deactivateCamera && (!callModel || callModel.videoEnabled)
|
||||
&& (!container.currentDevice || callModel && (container.currentDevice
|
||||
&& (container.currentDevice.videoEnabled || (container.currentDevice.isMe && callModel.cameraEnabled))))
|
||||
&& (!container.currentDevice || ( callModel && container.currentDevice &&
|
||||
( (!container.currentDevice.isMe && container.currentDevice.videoEnabled)
|
||||
|| (container.currentDevice.isMe && callModel.cameraEnabled))))
|
||||
|
||||
property bool a : callModel && callModel.videoEnabled
|
||||
property bool b: container.currentDevice && container.currentDevice.videoEnabled
|
||||
|
|
@ -51,6 +52,10 @@ Item {
|
|||
anchors.fill: parent
|
||||
|
||||
active: !resetActive && container.isVideoEnabled
|
||||
onActiveChanged: {
|
||||
console.log("QML Camera status : " + active)
|
||||
}
|
||||
|
||||
sourceComponent: container.isVideoEnabled && !container.isPaused? camera : null
|
||||
|
||||
Timer{
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ Item{
|
|||
anchors.fill: parent
|
||||
visible: false
|
||||
onVideoDefinitionChanged: mainItem.videoDefinitionChanged()
|
||||
deactivateCamera: false
|
||||
}
|
||||
OpacityMask{
|
||||
id: renderedCamera
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import LinphoneEnums 1.0
|
|||
import Units 1.0
|
||||
|
||||
import 'Chat.js' as Logic
|
||||
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
|
||||
|
||||
// =============================================================================
|
||||
|
||||
|
|
@ -32,10 +33,17 @@ Rectangle {
|
|||
|
||||
color: ChatStyle.color
|
||||
clip: true
|
||||
|
||||
Timer{// Let some time to have a better cell sizes
|
||||
id: repositionerDelay
|
||||
property int indexToMove
|
||||
interval: 100
|
||||
onTriggered: chat.positionViewAtIndex(indexToMove, ListView.Center)
|
||||
}
|
||||
function positionViewAtIndex(index){
|
||||
chat.bindToEnd = false
|
||||
chat.positionViewAtIndex(index, ListView.Beginning)
|
||||
chat.positionViewAtIndex(index, ListView.Center)
|
||||
repositionerDelay.indexToMove = index
|
||||
repositionerDelay.restart()
|
||||
}
|
||||
|
||||
function goToMessage(message){
|
||||
|
|
@ -290,10 +298,10 @@ Rectangle {
|
|||
//: 'Choose where to forward the message' : Dialog title for choosing where to forward the current message.
|
||||
, {title: qsTr('forwardDialogTitle'),
|
||||
addressSelectedCallback: function (sipAddress) {
|
||||
var chat = CallsListModel.createChat(sipAddress)
|
||||
var chat = CallsListModel.createChatRoom( '', proxyModel.chatRoomModel.haveEncryption, [sipAddress], false )
|
||||
if(chat){
|
||||
chat.forwardMessage($chatEntry)
|
||||
TimelineListModel.select(chat)
|
||||
chat.chatRoomModel.forwardMessage($chatEntry)
|
||||
TimelineListModel.select(chat.chatRoomModel)
|
||||
}
|
||||
},
|
||||
chatRoomSelectedCallback: function (chatRoomModel){
|
||||
|
|
@ -379,6 +387,7 @@ Rectangle {
|
|||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: textAreaBorders.height + chatMessagePreview.height+messageBlock.height
|
||||
color: ChatStyle.sendArea.backgroundBorder.color
|
||||
visible: proxyModel.chatRoomModel && !proxyModel.chatRoomModel.isReadOnly && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
|
@ -411,7 +420,6 @@ Rectangle {
|
|||
Layout.leftMargin: ChatStyle.sendArea.backgroundBorder.width
|
||||
borderColor: ChatStyle.sendArea.border.color
|
||||
topWidth: ChatStyle.sendArea.border.width
|
||||
visible: proxyModel.chatRoomModel && !proxyModel.chatRoomModel.isReadOnly && (!proxyModel.chatRoomModel.haveEncryption && SettingsModel.standardChatEnabled || proxyModel.chatRoomModel.haveEncryption && SettingsModel.secureChatEnabled)
|
||||
|
||||
DroppableTextArea {
|
||||
id: textArea
|
||||
|
|
@ -423,7 +431,7 @@ Rectangle {
|
|||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
height:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
height: visible ? ChatStyle.sendArea.height + ChatStyle.sendArea.border.width : 0
|
||||
minimumHeight:ChatStyle.sendArea.height + ChatStyle.sendArea.border.width
|
||||
maximumHeight:container.height/2
|
||||
|
||||
|
|
@ -445,10 +453,7 @@ Rectangle {
|
|||
}
|
||||
}
|
||||
onAudioRecordRequest: RecorderManager.resetVocalRecorder()
|
||||
Component.onCompleted: {
|
||||
text = proxyModel.chatRoomModel.cachedText
|
||||
cursorPosition=text.length
|
||||
}
|
||||
Component.onCompleted: {text = proxyModel.cachedText; cursorPosition=text.length}
|
||||
Rectangle{
|
||||
anchors.fill:parent
|
||||
color:'white'
|
||||
|
|
|
|||
|
|
@ -111,7 +111,8 @@ Loader{
|
|||
color: ChatCalendarMessageStyle.schedule.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: ChatCalendarMessageStyle.schedule.pointSize
|
||||
text: Qt.formatDateTime(mainItem.conferenceInfoModel.dateTime, 'hh:mm')
|
||||
// Reminder: QML use locale time (not system). Use UTC from C++ => convert it into QML => pass QML => convert it into UTC and apply our timezone.
|
||||
text: UtilsCpp.toTimeString(Utils.fromUTC(mainItem.conferenceInfoModel.dateTimeUtc), 'hh:mm')
|
||||
+ (mainItem.conferenceInfoModel.duration > 0 ? ' (' +Utils.formatDuration(mainItem.conferenceInfoModel.duration * 60) + ')'
|
||||
: '')
|
||||
}
|
||||
|
|
@ -143,10 +144,10 @@ Loader{
|
|||
color: ChatCalendarMessageStyle.type.cancelledColor
|
||||
font.pointSize: ChatCalendarMessageStyle.type.pointSize
|
||||
font.weight: Font.Bold
|
||||
text: 'You have cancelled the conference'
|
||||
//: 'Meeting has been cancelled' : ICS Title for cancelled meetings
|
||||
text:qsTr('icsCancelledMeetingInvite')
|
||||
}
|
||||
|
||||
|
||||
Text{
|
||||
id: title
|
||||
Layout.fillWidth: true
|
||||
|
|
@ -178,6 +179,8 @@ Loader{
|
|||
Layout.preferredHeight: parent.participantLineHeight
|
||||
Layout.preferredWidth: ChatCalendarMessageStyle.participants.iconSize
|
||||
Layout.alignment: Qt.AlignTop
|
||||
|
||||
visible: mainItem.conferenceInfoModel.participantCount > 0
|
||||
clip: false
|
||||
Icon{
|
||||
anchors.top: parent.top
|
||||
|
|
@ -209,7 +212,11 @@ Loader{
|
|||
Layout.alignment: Qt.AlignTop
|
||||
spacing: 0
|
||||
visible: mainItem.isExpanded
|
||||
onVisibleChanged: model= mainItem.conferenceInfoModel.getParticipants()
|
||||
onVisibleChanged: visible ? model= mainItem.conferenceInfoModel.getAllParticipants() : model = []
|
||||
Connections{
|
||||
target: mainItem.conferenceInfoModel
|
||||
onParticipantsChanged: if(expandedParticipantsList.visible) expandedParticipantsList.model = mainItem.conferenceInfoModel.getAllParticipants()
|
||||
}
|
||||
|
||||
delegate: Row{
|
||||
spacing: 5
|
||||
|
|
|
|||
|
|
@ -109,12 +109,14 @@ Loader{
|
|||
}
|
||||
RowLayout {
|
||||
id: participantsRow
|
||||
property int participantCount: mainItem.conferenceInfoModel.allParticipantCount
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: ChatCalendarMessageStyle.participants.iconSize
|
||||
Layout.leftMargin: 5
|
||||
Layout.rightMargin: 15
|
||||
|
||||
spacing: ChatCalendarMessageStyle.participants.spacing
|
||||
spacing: ChatCalendarMessageStyle.participants.spacing
|
||||
visible: participantsRow.participantCount > 0
|
||||
|
||||
Icon{
|
||||
icon: ChatCalendarMessageStyle.participants.icon
|
||||
|
|
@ -124,13 +126,12 @@ Loader{
|
|||
|
||||
Text {
|
||||
id: participantsList
|
||||
property int participantCount: mainItem.conferenceInfoModel.getParticipantCount()
|
||||
Layout.fillWidth: true
|
||||
color: ChatCalendarMessageStyle.participants.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: ChatCalendarMessageStyle.participants.pointSize
|
||||
//: '%1 participant' : number(=%1) of participant.
|
||||
text: qsTr('icsParticipants', '', participantCount).arg(participantCount)
|
||||
text: qsTr('icsParticipants', '', participantsRow.participantCount).arg(participantsRow.participantCount)
|
||||
}
|
||||
}
|
||||
ColumnLayout{
|
||||
|
|
@ -158,7 +159,7 @@ Loader{
|
|||
color: ChatCalendarMessageStyle.schedule.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Units.dp * 8
|
||||
text: Qt.formatDate(mainItem.conferenceInfoModel.dateTimeUtc, 'yyyy/MM/dd')
|
||||
text: UtilsCpp.toDateString(Utils.fromUTC(mainItem.conferenceInfoModel.dateTimeUtc), 'yyyy/MM/dd')
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
|
|
@ -182,7 +183,8 @@ Loader{
|
|||
color: ChatCalendarMessageStyle.schedule.color
|
||||
elide: Text.ElideRight
|
||||
font.pointSize: Units.dp * 8
|
||||
text: Qt.formatDateTime(mainItem.conferenceInfoModel.dateTimeUtc, 'hh:mm')
|
||||
// Reminder: QML use locale time (not system). Use UTC from C++ => convert it into QML => pass QML => convert it into UTC and apply our timezone.
|
||||
text: UtilsCpp.toTimeString( Utils.fromUTC(mainItem.conferenceInfoModel.dateTimeUtc), 'hh:mm')
|
||||
+ (mainItem.conferenceInfoModel.duration > 0 ? ' ('+Utils.formatDuration(mainItem.conferenceInfoModel.duration * 60) + ')'
|
||||
: '')
|
||||
}
|
||||
|
|
@ -202,7 +204,11 @@ Loader{
|
|||
Layout.leftMargin: 10
|
||||
spacing: 0
|
||||
visible: mainItem.isExpanded
|
||||
onVisibleChanged: model= mainItem.conferenceInfoModel.getParticipants()
|
||||
onVisibleChanged: visible ? model= mainItem.conferenceInfoModel.getAllParticipants() : model = []
|
||||
Connections{
|
||||
target: mainItem.conferenceInfoModel
|
||||
onParticipantsChanged: if(expandedParticipantsList.visible) expandedParticipantsList.model = mainItem.conferenceInfoModel.getAllParticipants()
|
||||
}
|
||||
|
||||
delegate: Row{
|
||||
spacing: 5
|
||||
|
|
|
|||
|
|
@ -10,84 +10,95 @@ import UtilsCpp 1.0
|
|||
// =============================================================================
|
||||
|
||||
Item {
|
||||
id: avatar
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
property alias presenceLevel: presenceLevelIcon.level
|
||||
property color backgroundColor: AvatarStyle.backgroundColor
|
||||
property color foregroundColor: 'transparent'
|
||||
property string username
|
||||
property var image
|
||||
|
||||
property var _initialsRegex: /^\s*([^\s\.]+)(?:[\s\.]+([^\s\.]+))?/
|
||||
|
||||
property bool isPhoneNumber: UtilsCpp.isPhoneNumber(username)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function isLoaded () {
|
||||
return roundedImage.status === Image.Ready
|
||||
}
|
||||
|
||||
function _computeInitials () {
|
||||
var result = username.match(_initialsRegex)
|
||||
if (!result) {
|
||||
return username.length > 0 ? username.charAt(0).toUpperCase() : ''
|
||||
}
|
||||
|
||||
return result[1].charAt(0).toUpperCase() + (
|
||||
result[2] != null
|
||||
? result[2].charAt(0).toUpperCase()
|
||||
: ''
|
||||
)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
RoundedImage {
|
||||
id: roundedImage
|
||||
|
||||
anchors.fill: parent
|
||||
backgroundColor: avatar.backgroundColor
|
||||
foregroundColor: avatar.foregroundColor
|
||||
source: avatar.image || ''
|
||||
Icon{
|
||||
id: avatar
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
property alias presenceLevel: presenceLevelIcon.level
|
||||
property bool isDarkMode: false
|
||||
property color backgroundColor: isDarkMode ? AvatarStyle.backgroundDarkModeColor : AvatarStyle.backgroundColor
|
||||
property color foregroundColor: 'transparent'
|
||||
property string username
|
||||
property var image
|
||||
property bool isOneToOne: true
|
||||
|
||||
property var _initialsRegex: /^\s*([^\s\.]+)(?:[\s\.]+([^\s\.]+))?/
|
||||
|
||||
property bool isPhoneNumber: UtilsCpp.isPhoneNumber(username)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function isLoaded () {
|
||||
return roundedImage.status === Image.Ready
|
||||
}
|
||||
|
||||
function _computeInitials () {
|
||||
var result = username.match(_initialsRegex)
|
||||
if (!result) {
|
||||
return username.length > 0 ? username.charAt(0).toUpperCase() : ''
|
||||
}
|
||||
|
||||
return result[1].charAt(0).toUpperCase() + (
|
||||
result[2] != null
|
||||
? result[2].charAt(0).toUpperCase()
|
||||
: ''
|
||||
)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
RoundedImage {
|
||||
id: roundedImage
|
||||
|
||||
anchors.fill: parent
|
||||
icon: AvatarStyle.personImage
|
||||
visible: parent.source == '' && avatar.isPhoneNumber
|
||||
overwriteColor: AvatarStyle.initials.color
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: initialsText
|
||||
anchors.centerIn: parent
|
||||
color: AvatarStyle.initials.color
|
||||
font.pointSize: {
|
||||
var width
|
||||
|
||||
if (parent.width > 0) {
|
||||
width = parent.width / AvatarStyle.initials.ratio
|
||||
}
|
||||
|
||||
return AvatarStyle.initials.pointSize * (width || 1)
|
||||
}
|
||||
|
||||
text: _computeInitials()
|
||||
visible: roundedImage.status !== Image.Ready && !avatar.isPhoneNumber
|
||||
}
|
||||
|
||||
PresenceLevel {
|
||||
id: presenceLevelIcon
|
||||
visible: level >= 0
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
height: parent.height / 4
|
||||
width: parent.width / 4
|
||||
}
|
||||
backgroundColor: avatar.backgroundColor
|
||||
foregroundColor: avatar.foregroundColor
|
||||
source: avatar.image || ''
|
||||
Icon{
|
||||
anchors.fill: parent
|
||||
icon: AvatarStyle.personImage
|
||||
visible: parent.source == '' && avatar.isPhoneNumber
|
||||
overwriteColor: AvatarStyle.initials.color
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: initialsText
|
||||
anchors.centerIn: parent
|
||||
color: isDarkMode ? AvatarStyle.initials.darkModeColor : AvatarStyle.initials.color
|
||||
font.pointSize: {
|
||||
var width
|
||||
|
||||
if (parent.width > 0) {
|
||||
width = parent.width / AvatarStyle.initials.ratio
|
||||
}
|
||||
|
||||
return AvatarStyle.initials.pointSize * (width || 1)
|
||||
}
|
||||
|
||||
text: _computeInitials()
|
||||
visible: roundedImage.status !== Image.Ready && !avatar.isPhoneNumber && avatar.isOneToOne
|
||||
}
|
||||
|
||||
Icon {
|
||||
anchors.fill: parent
|
||||
icon: ContactStyle.groupChat.icon
|
||||
overwriteColor: isDarkMode ? ContactStyle.groupChat.avatarDarkModeColor : ContactStyle.groupChat.avatarColor
|
||||
iconSize: avatar.width
|
||||
//visible: entry!=undefined && entry.isOneToOne!=undefined && !entry.isOneToOne
|
||||
visible: !avatar.isOneToOne
|
||||
}
|
||||
|
||||
PresenceLevel {
|
||||
id: presenceLevelIcon
|
||||
visible: level >= 0
|
||||
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
}
|
||||
|
||||
height: parent.height / 4
|
||||
width: parent.width / 4
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,9 +21,11 @@ Rectangle {
|
|||
property alias subtitleColor: description.subtitleColor
|
||||
property alias titleColor: description.titleColor
|
||||
property alias statusText : description.statusText
|
||||
property alias isDarkMode: avatar.isDarkMode
|
||||
|
||||
property bool displayUnreadMessageCount: false
|
||||
property bool showSubtitle : true
|
||||
property bool showBusyIndicator: false
|
||||
property string subtitle: ''
|
||||
|
||||
property string subject: (entry && entry.conferenceInfoModel && entry.conferenceInfoModel.subject
|
||||
|
|
@ -75,16 +77,7 @@ Rectangle {
|
|||
? ''
|
||||
: item.username
|
||||
: item.username
|
||||
visible:!groupChat.visible
|
||||
Icon {
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
icon: ContactStyle.groupChat.icon
|
||||
overwriteColor: ContactStyle.groupChat.avatarColor
|
||||
iconSize: ContactStyle.contentHeight
|
||||
visible: entry!=undefined && entry.isOneToOne!=undefined && !entry.isOneToOne
|
||||
}
|
||||
isOneToOne: entry==undefined || entry.isOneToOne==undefined || entry.isOneToOne
|
||||
|
||||
Icon{
|
||||
anchors.top:parent.top
|
||||
|
|
@ -97,25 +90,26 @@ Rectangle {
|
|||
anchors.fill: parent
|
||||
onClicked: item.avatarClicked(mouse)
|
||||
}
|
||||
}
|
||||
Icon {
|
||||
id: groupChat
|
||||
|
||||
Layout.preferredHeight: ContactStyle.contentHeight
|
||||
Layout.preferredWidth: ContactStyle.contentHeight
|
||||
|
||||
icon: ContactStyle.groupChat.icon
|
||||
overwriteColor: ContactStyle.groupChat.color
|
||||
iconSize: ContactStyle.contentHeight
|
||||
visible: false //entry!=undefined && entry.isOneToOne!=undefined && !entry.isOneToOne
|
||||
|
||||
Icon{
|
||||
anchors.right: parent.right
|
||||
anchors.top:parent.top
|
||||
anchors.topMargin: -5
|
||||
visible: entry!=undefined && entry.haveEncryption != undefined && entry.haveEncryption
|
||||
icon: entry?(entry.securityLevel === 2?'secure_level_1': entry.securityLevel===3? 'secure_level_2' : 'secure_level_unsafe'):'secure_level_unsafe'
|
||||
iconSize:15
|
||||
Loader{
|
||||
id: busyLoader
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
|
||||
active: item.showBusyIndicator
|
||||
sourceComponent: Component{
|
||||
BusyIndicator{// Joining spinner
|
||||
id: joiningSpinner
|
||||
running: false
|
||||
Timer{// Delay starting spinner (Qt bug)
|
||||
id: indicatorDelay
|
||||
interval: 100
|
||||
onTriggered: joiningSpinner.running = true
|
||||
}
|
||||
Component.onCompleted: indicatorDelay.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +130,9 @@ Rectangle {
|
|||
? item.organizer
|
||||
? item.organizer
|
||||
: entry.sipAddress || entry.fullPeerAddress || entry.peerAddress || ''
|
||||
: entry.participants.addressesToString
|
||||
: entry.participants
|
||||
? entry.participants.addressesToString
|
||||
: ''
|
||||
: ''
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,14 @@ Rectangle{
|
|||
onVisibleChanged: if(!visible && contentsStack.nViews > 1) {
|
||||
contentsStack.pop()
|
||||
}
|
||||
property bool _activateCamera: false
|
||||
Connections{// Enable camera only when status is ok
|
||||
target: mainItem.callModel
|
||||
onStatusChanged: if( mainItem._activateCamera && (status == LinphoneEnums.CallStatusConnected || status == LinphoneEnums.CallStatusIdle)){
|
||||
camera._activateCamera = false
|
||||
callModel.cameraEnabled = true
|
||||
}
|
||||
}
|
||||
ButtonGroup{id: modeGroup}
|
||||
ColumnLayout{
|
||||
anchors.fill: parent
|
||||
|
|
@ -158,13 +166,16 @@ Rectangle{
|
|||
font.pointSize: IncallMenuStyle.list.pointSize
|
||||
color: IncallMenuStyle.list.color
|
||||
}
|
||||
ActionButton{
|
||||
Icon{
|
||||
Layout.minimumWidth: iconWidth
|
||||
Layout.rightMargin: 10
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
backgroundRadius: width/2
|
||||
isCustom: true
|
||||
colorSet: IncallMenuStyle.buttons.next
|
||||
//backgroundRadius: width/2
|
||||
|
||||
icon: IncallMenuStyle.buttons.next.icon
|
||||
overwriteColor: IncallMenuStyle.buttons.next.backgroundNormalColor
|
||||
iconWidth: IncallMenuStyle.buttons.next.iconSize
|
||||
iconHeight: IncallMenuStyle.buttons.next.iconSize
|
||||
}
|
||||
}
|
||||
MouseArea{
|
||||
|
|
@ -227,6 +238,11 @@ Rectangle{
|
|||
bottomWidth: IncallMenuStyle.list.border.width
|
||||
Layout.preferredHeight: Math.max(layoutIcon.height, radio.contentItem.implicitHeight) + 20
|
||||
Layout.fillWidth: true
|
||||
enabled: mainItem.callModel && !mainItem.callModel.updating
|
||||
MouseArea{
|
||||
anchors.fill: parent
|
||||
onClicked: radio.clicked()
|
||||
}
|
||||
RowLayout{
|
||||
anchors.fill: parent
|
||||
|
||||
|
|
@ -238,37 +254,16 @@ Rectangle{
|
|||
Layout.alignment: Qt.AlignVCenter
|
||||
ButtonGroup.group: modeGroup
|
||||
text: modelData.text
|
||||
|
||||
property bool isInternallyChecked: mainItem.callModel ? (mainItem.callModel.localVideoEnabled && modelData.value == mainItem.callModel.conferenceVideoLayout)
|
||||
|| (!mainItem.callModel.localVideoEnabled && modelData.value == LinphoneEnums.ConferenceLayoutAudioOnly)
|
||||
: false
|
||||
// break bind. Radiobutton checked itself without taking care of custom binding. This workaound works as long as we don't really need the binding.
|
||||
onIsInternallyCheckedChanged: checked = isInternallyChecked
|
||||
Component.onCompleted: checked = isInternallyChecked
|
||||
Timer{
|
||||
id: changingLayoutDelay
|
||||
interval: 100
|
||||
onTriggered: {if(modelData.value == 2) mainItem.callModel.videoEnabled = false
|
||||
else {
|
||||
mainItem.callModel.conferenceVideoLayout = modelData.value
|
||||
mainItem.callModel.videoEnabled = true
|
||||
}
|
||||
mainItem.enabled = true
|
||||
}
|
||||
}
|
||||
onClicked:{
|
||||
// Do changes only if we choose a different layout.
|
||||
if(! ( mainItem.callModel ? (mainItem.callModel.localVideoEnabled && modelData.value == mainItem.callModel.conferenceVideoLayout)
|
||||
|| (!mainItem.callModel.localVideoEnabled && modelData.value == LinphoneEnums.ConferenceLayoutAudioOnly)
|
||||
: false)){
|
||||
mainItem.enabled = false
|
||||
mainItem.layoutChanging(modelData.value)// Let time to clear cameras
|
||||
changingLayoutDelay.start()
|
||||
}
|
||||
}
|
||||
onClicked: mainItem.layoutChanging(modelData.value)
|
||||
}
|
||||
Icon{
|
||||
id: layoutIcon
|
||||
id: layoutIcon
|
||||
Layout.minimumWidth: iconWidth
|
||||
Layout.rightMargin: 10
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
|
|
|||
|
|
@ -101,15 +101,20 @@ Item{
|
|||
color: "#80000000"
|
||||
source: usernameItem
|
||||
}
|
||||
ActionButton{
|
||||
visible: mainItem._showCloseButton && mainItem._isPreview && mainItem._callModel && mainItem._callModel.videoEnabled
|
||||
Loader{
|
||||
id: closeLoader
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 5
|
||||
anchors.topMargin: 5
|
||||
isCustom: true
|
||||
colorSet: DecorationStickerStyle.closePreview
|
||||
onClicked: mainItem.closeRequested()
|
||||
active: mainItem._showCloseButton && mainItem._isPreview && mainItem._callModel && mainItem._callModel.videoEnabled
|
||||
sourceComponent: Component{
|
||||
ActionButton{
|
||||
isCustom: true
|
||||
colorSet: DecorationStickerStyle.closePreview
|
||||
onClicked: mainItem.closeRequested()
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout{
|
||||
anchors.top: parent.top
|
||||
|
|
@ -137,17 +142,24 @@ Item{
|
|||
iconSize: DecorationStickerStyle.isMuted.button.iconSize
|
||||
}
|
||||
}
|
||||
BusyIndicator{// Joining spinner
|
||||
Loader{
|
||||
id: busyLoader
|
||||
|
||||
Layout.preferredHeight: 20
|
||||
Layout.preferredWidth: 20
|
||||
property bool delayed : false
|
||||
visible: delayed && mainItem._currentDevice && (mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateJoining || mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateScheduledForJoining || mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateAlerting)
|
||||
Timer{// Delay starting spinner (Qt bug)
|
||||
id: indicatorDelay
|
||||
interval: 100
|
||||
onTriggered: parent.delayed = true
|
||||
active: mainItem._currentDevice && (mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateJoining || mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateScheduledForJoining || mainItem._currentDevice.state == LinphoneEnums.ParticipantDeviceStateAlerting)
|
||||
sourceComponent: Component{
|
||||
BusyIndicator{// Joining spinner
|
||||
id: joiningSpinner
|
||||
running: false
|
||||
Timer{// Delay starting spinner (Qt bug)
|
||||
id: indicatorDelay
|
||||
interval: 100
|
||||
onTriggered: joiningSpinner.running = true
|
||||
}
|
||||
Component.onCompleted: indicatorDelay.start()
|
||||
}
|
||||
}
|
||||
Component.onCompleted: indicatorDelay.start()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ Item{
|
|||
property alias showActiveSpeakerOverlay: camera.showActiveSpeakerOverlay
|
||||
property alias isCameraFromDevice: camera.isCameraFromDevice
|
||||
property alias deactivateCamera: camera.deactivateCamera
|
||||
property alias isVideoEnabled: camera.isVideoEnabled
|
||||
readonly property alias isVideoEnabled: camera.isVideoEnabled
|
||||
|
||||
property alias image: avatar.image
|
||||
property alias avatarBackgroundColor: avatar.avatarBackgroundColor
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ QtObject {
|
|||
}
|
||||
property QtObject burgerMenu: QtObject {
|
||||
property string name : 'burgerMenu'
|
||||
property string icon : 'burger_menu_custom'
|
||||
property string icon : 'menu_vdots_custom'
|
||||
property int iconSize: 35
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_bg').color
|
||||
|
|
@ -30,7 +30,7 @@ QtObject {
|
|||
}
|
||||
property QtObject selectedBurgerMenu: QtObject {
|
||||
property string name : 'selectedBurgerMenu'
|
||||
property string icon : 'burger_menu_custom'
|
||||
property string icon : 'menu_vdots_custom'
|
||||
property int iconSize: 35
|
||||
property color backgroundNormalColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_n', icon, 'me_n_b_inv_bg').color
|
||||
property color backgroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_bg_h', icon, 'me_h_b_inv_bg').color
|
||||
|
|
@ -39,6 +39,7 @@ QtObject {
|
|||
property color foregroundHoveredColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_h', icon, 'me_h_b_inv_fg').color
|
||||
property color foregroundPressedColor : ColorsList.addImageColor(sectionName+'_'+name+'_fg_p', icon, 'me_p_b_inv_fg').color
|
||||
}
|
||||
|
||||
property QtObject hangup: QtObject {
|
||||
property int iconSize: 35
|
||||
property string icon : 'hangup_custom'
|
||||
|
|
|
|||
|
|
@ -9,11 +9,14 @@ import ColorsList 1.0
|
|||
QtObject {
|
||||
property string sectionName: 'Avatar'
|
||||
property color backgroundColor: ColorsList.add(sectionName+'_bg', 'd').color
|
||||
property color backgroundDarkModeColor: ColorsList.add(sectionName+'_dark_bg', 'q').color
|
||||
|
||||
|
||||
property string personImage : 'contact_custom'
|
||||
|
||||
property QtObject initials: QtObject {
|
||||
property color color: ColorsList.add(sectionName+'_initials', 'q').color
|
||||
property color darkModeColor: ColorsList.add(sectionName+'_dark_initials', 'd').color
|
||||
property int pointSize: Units.dp * 10
|
||||
property int ratio: 30
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,5 +16,6 @@ QtObject {
|
|||
property string icon: 'chat_room_custom'
|
||||
property color color: ColorsList.addImageColor(sectionName+'_groupChat', icon, 'g').color
|
||||
property color avatarColor: ColorsList.addImageColor(sectionName+'_groupChat_onAvatar', icon, 'q').color
|
||||
property color avatarDarkModeColor: ColorsList.addImageColor(sectionName+'_groupChat_dark_onAvatar', icon, 'd').color
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@ QtObject {
|
|||
property color selectedTimerColor: ColorsList.addImageColor(sectionName+'_ephemeralTimer_c', icon, 'q').color
|
||||
}
|
||||
|
||||
property QtObject draft: QtObject{
|
||||
property string icon: 'draft_custom'
|
||||
property int iconSize : 30
|
||||
property color color: ColorsList.addImageColor(sectionName+'_draft', icon, 'ad').color
|
||||
property color selectedColor: ColorsList.addImageColor(sectionName+'_draft_c', icon, 'q').color
|
||||
}
|
||||
|
||||
property QtObject contact: QtObject {
|
||||
property int height: 60
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Item {
|
|||
NumberAnimation { target: optionsView; property: 'x'; to:optionsView.width; duration: 200;}
|
||||
}
|
||||
]
|
||||
enabled: !contactView.showBusyIndicator
|
||||
|
||||
|
||||
Contact {
|
||||
|
|
@ -68,32 +69,20 @@ Item {
|
|||
? TimelineStyle.contact.title.color.selected
|
||||
: TimelineStyle.contact.title.color.normal
|
||||
showSubtitle: mainItem.timelineModel && (mainItem.timelineModel.chatRoomModel && (mainItem.timelineModel.chatRoomModel.isOneToOne || !mainItem.timelineModel.chatRoomModel.isConference))
|
||||
TooltipArea {
|
||||
showBusyIndicator: mainItem.timelineModel && mainItem.timelineModel.updating
|
||||
TooltipArea {
|
||||
id: contactTooltip
|
||||
text: mainItem.timelineModel && UtilsCpp.toDateTimeString(mainItem.timelineModel.chatRoomModel.lastUpdateTime)
|
||||
isClickable: true
|
||||
}
|
||||
|
||||
Icon{
|
||||
id: draft
|
||||
icon: TimelineStyle.draft.icon
|
||||
iconSize: visible ? TimelineStyle.draft.iconSize : 0
|
||||
overwriteColor: mainItem.timelineModel && mainItem.timelineModel.selected ? TimelineStyle.draft.selectedColor : TimelineStyle.draft.color
|
||||
anchors.right:parent.right
|
||||
anchors.bottom:parent.bottom
|
||||
anchors.bottomMargin: 3
|
||||
anchors.rightMargin: 7
|
||||
visible: mainItem.timelineModel && mainItem.timelineModel.chatRoomModel.hasDraft
|
||||
}
|
||||
|
||||
Icon{
|
||||
icon: TimelineStyle.ephemeralTimer.icon
|
||||
iconSize: TimelineStyle.ephemeralTimer.iconSize
|
||||
overwriteColor: mainItem.timelineModel && mainItem.timelineModel.selected ? TimelineStyle.ephemeralTimer.selectedTimerColor : TimelineStyle.ephemeralTimer.timerColor
|
||||
anchors.right:draft.left
|
||||
anchors.right:parent.right
|
||||
anchors.bottom:parent.bottom
|
||||
anchors.bottomMargin: 3
|
||||
anchors.rightMargin: draft.visible ? 0 : 7
|
||||
anchors.bottomMargin: 7
|
||||
anchors.rightMargin: 7
|
||||
visible: mainItem.timelineModel && mainItem.timelineModel.chatRoomModel.ephemeralEnabled
|
||||
}
|
||||
MouseArea {
|
||||
|
|
@ -173,5 +162,4 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ import Linphone.Styles 1.0
|
|||
import Units 1.0
|
||||
import UtilsCpp 1.0
|
||||
|
||||
|
||||
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
|
||||
// =============================================================================
|
||||
|
||||
ColumnLayout {
|
||||
|
|
@ -114,6 +114,9 @@ ColumnLayout {
|
|||
colorSet: ParticipantsListViewStyle.removeParticipant,
|
||||
secure:0,
|
||||
visible:true,
|
||||
visibleHandler: function(entry){
|
||||
return !UtilsCpp.isMe(entry.sipAddress)
|
||||
},
|
||||
//: 'Remove this participant from the list' : Tootltip to explain that the action will lead to remove the participant.
|
||||
tooltipText: qsTr('participantsListRemoveTooltip'),
|
||||
handler: function (entry) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import Linphone 1.0
|
|||
import Linphone.Styles 1.0
|
||||
import Common.Styles 1.0
|
||||
|
||||
import 'qrc:/ui/scripts/Utils/utils.js' as Utils
|
||||
|
||||
// =============================================================================
|
||||
|
||||
ScrollableListView {
|
||||
|
|
@ -120,6 +122,9 @@ ScrollableListView {
|
|||
backgroundRadius: 90
|
||||
colorSet: modelData.colorSet
|
||||
visible: sipAddressesView.actions[index].visible
|
||||
&& (!sipAddressesView.actions[index].visibleHandler || sipAddressesView.actions[index].visibleHandler({
|
||||
sipAddress: sipAddressesView.interpretableSipAddress
|
||||
}))
|
||||
|
||||
onClicked: sipAddressesView.actions[index].handler({
|
||||
sipAddress: sipAddressesView.interpretableSipAddress
|
||||
|
|
@ -253,16 +258,7 @@ ScrollableListView {
|
|||
statusText : showAdminStatus ? getStatus() : ''
|
||||
|
||||
entry: $modelData
|
||||
|
||||
onAvatarClicked: sipAddressesView.entryClicked(parent.entry, index, contactView)
|
||||
|
||||
BusyIndicator{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width:15
|
||||
height:15
|
||||
running: sipAddressesView.showInvitingIndicator && $modelData.inviting
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -289,25 +285,48 @@ ScrollableListView {
|
|||
}
|
||||
|
||||
Repeater {
|
||||
id: actionsRepeater
|
||||
model: sipAddressesView.actions
|
||||
|
||||
ActionButton {
|
||||
isCustom: true
|
||||
backgroundRadius: 90
|
||||
colorSet: modelData.colorSet
|
||||
Item{
|
||||
height: buttonAction.height
|
||||
width: buttonAction.width
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
tooltipText: modelData.tooltipText? modelData.tooltipText:''
|
||||
visible: sipAddressesView.actions[index].visible
|
||||
onClicked: {
|
||||
sipAddressesView.actions[index].handler(contactView.entry)
|
||||
}
|
||||
Icon{
|
||||
visible: modelData.secure>0 &&
|
||||
(sipAddressesView.actions[index].secureIconVisibleHandler ? sipAddressesView.actions[index].secureIconVisibleHandler({sipAddres:$modelData}) : true)
|
||||
icon: modelData.secure === 2?'secure_level_2':'secure_level_1'
|
||||
iconSize: parent.height/2
|
||||
anchors.top:parent.top
|
||||
anchors.horizontalCenter: parent.right
|
||||
ActionButton {
|
||||
id: buttonAction
|
||||
isCustom: true
|
||||
backgroundRadius: 90
|
||||
colorSet: modelData.colorSet
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
tooltipText: modelData.tooltipText? modelData.tooltipText:''
|
||||
visible: sipAddressesView.actions[index].visible && (!sipAddressesView.actions[index].visibleHandler || sipAddressesView.actions[index].visibleHandler(contactView.entry))
|
||||
|
||||
onClicked: {
|
||||
sipAddressesView.actions[index].handler(contactView.entry)
|
||||
}
|
||||
Icon{
|
||||
visible: modelData.secure>0 &&
|
||||
(sipAddressesView.actions[index].secureIconVisibleHandler ? sipAddressesView.actions[index].secureIconVisibleHandler({sipAddres:$modelData}) : true)
|
||||
icon: modelData.secure === 2?'secure_level_2':'secure_level_1'
|
||||
iconSize: parent.height/2
|
||||
anchors.top:parent.top
|
||||
anchors.horizontalCenter: parent.right
|
||||
}
|
||||
Loader{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: parent.height - 2
|
||||
width: height
|
||||
|
||||
active: index == actionsRepeater.count -1 && sipAddressesView.showInvitingIndicator && contactView.entry && contactView.entry.inviting
|
||||
|
||||
sourceComponent: Component{
|
||||
BusyIndicator{
|
||||
color: BusyIndicatorStyle.alternateColor
|
||||
running: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -562,6 +562,24 @@ function buildDate(date, time){
|
|||
dateTime.setSeconds(time.getSeconds())
|
||||
return dateTime
|
||||
}
|
||||
|
||||
function equalDate(date1, date2){
|
||||
return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate()
|
||||
}
|
||||
|
||||
function fromUTC(date){
|
||||
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(),
|
||||
date.getUTCDate(), date.getUTCHours(),
|
||||
date.getUTCMinutes(), date.getUTCSeconds()));
|
||||
}
|
||||
// return EXACTLY what date has been set (not take account of Locale timezones, eg. Date(2000,0,1) will print january and not december if timezone lead there.)
|
||||
// Use this function for toLocaleString/toLocaleDateString or other
|
||||
function exactDate(date) {
|
||||
var timeOffset = date.getTimezoneOffset() * 60000
|
||||
var exactDate = new Date(date.valueOf() - timeOffset)
|
||||
return exactDate
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
function formatSize (size) {
|
||||
|
|
@ -788,4 +806,4 @@ function printObject(o) {
|
|||
out += p + ': ' + o[p] + '\n';
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,11 +140,12 @@ Window {
|
|||
ActionButton {
|
||||
isCustom: true
|
||||
backgroundRadius: 4
|
||||
colorSet: CallsWindowStyle.callsList.newConference
|
||||
colorSet: CallsWindowStyle.callsList.mergeConference
|
||||
visible: SettingsModel.conferenceEnabled
|
||||
enabled: CallsListModel.canMergeCalls
|
||||
|
||||
onClicked: {
|
||||
Logic.openConferenceManager()
|
||||
CallsListModel.mergeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue