mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-18 11:58:11 +00:00
Compare commits
328 commits
6.0.0-Call
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1156bd78c0 | ||
|
|
befa4a2635 | ||
|
|
0cf3938dc3 | ||
|
|
c3b160ec3e | ||
|
|
dc1ec216e8 | ||
|
|
0bfa29dc55 | ||
|
|
0df7065b5e | ||
|
|
6d9b5efcc5 | ||
|
|
50ec67298e | ||
|
|
1bae93aab5 | ||
|
|
d40045d5bb | ||
|
|
13ec790648 | ||
|
|
528dc1e2bd | ||
|
|
31726b46cd | ||
|
|
876fdbe619 | ||
|
|
e849891548 | ||
|
|
c672762b63 | ||
|
|
e23a49fbd3 | ||
|
|
a9a1249ecd | ||
|
|
ed57ec1ea5 | ||
|
|
d4c1387c43 | ||
|
|
88aea7ba25 | ||
|
|
605ffdcdd5 | ||
|
|
21e8e2aaba | ||
|
|
60517741a2 | ||
|
|
5a90959125 | ||
|
|
c8428d6ade | ||
|
|
b2ae9213a2 | ||
|
|
d39a84ca4e | ||
|
|
dfc88b7657 | ||
|
|
f405754e24 | ||
|
|
cca8db9055 | ||
|
|
8ee8058065 | ||
|
|
96b20f42e2 | ||
|
|
5bbffa79d8 | ||
|
|
e3edeb1bcf | ||
|
|
7c2e9f6c12 | ||
|
|
ca4bdd3736 | ||
|
|
251f711250 | ||
|
|
37db390d5c | ||
|
|
04d2744bf2 | ||
|
|
a7ba374b8f | ||
|
|
29691485bf | ||
|
|
735c473b3c | ||
|
|
bba3edd4b6 | ||
|
|
514c337192 | ||
|
|
fea9a1b7be | ||
|
|
afd3514965 | ||
|
|
3f5797f453 | ||
|
|
db5f6dc2af | ||
|
|
d0cf951fe4 | ||
|
|
b802fec33c | ||
|
|
3c264fd3ee | ||
|
|
72e32ec160 | ||
|
|
bfbafab84b | ||
|
|
7a4adbcbb4 | ||
|
|
fa3ef0b1a8 | ||
|
|
2fc4439e16 | ||
|
|
0b9a0ead2a | ||
|
|
3870037905 | ||
|
|
e113058ae9 | ||
|
|
a4b38e4fd1 | ||
|
|
a0850b9967 | ||
|
|
bc5022c8f5 | ||
|
|
ac03de6663 | ||
|
|
58eb93d13b | ||
|
|
11487b3aeb | ||
|
|
ca73193f6c | ||
|
|
f2e49f21b0 | ||
|
|
a7c8e8db90 | ||
|
|
afc03daa22 | ||
|
|
74b2cf299b | ||
|
|
fcdbcdc9c1 | ||
|
|
3dbea1ccb2 | ||
|
|
d741e79e2e | ||
|
|
b3b40d6f99 | ||
|
|
d957fae94e | ||
|
|
e224f24e92 | ||
|
|
cef650fb6a | ||
|
|
9e10d5e9bd | ||
|
|
36c783c9e5 | ||
|
|
0d2e83a60d | ||
|
|
c70426f770 | ||
|
|
0c87a8d94e | ||
|
|
6f4e925766 | ||
|
|
99c2a6ddc6 | ||
|
|
cbd91b868d | ||
|
|
80bf126b23 | ||
|
|
db1f04350a | ||
|
|
08f2292881 | ||
|
|
229fbe1713 | ||
|
|
2d9f568e3d | ||
|
|
d4ce80f8c6 | ||
|
|
eb9fa8aefe | ||
|
|
cb63b1a112 | ||
|
|
b3135ea177 | ||
|
|
c0a150f3e1 | ||
|
|
8e10decd65 | ||
|
|
55a54dc10e | ||
|
|
11c586792d | ||
|
|
95d5345450 | ||
|
|
9d3bd909ca | ||
|
|
300bf3e409 | ||
|
|
a74ef62634 | ||
|
|
b17bc8cc27 | ||
|
|
7825646edd | ||
|
|
4a05b727c6 | ||
|
|
453d16250a | ||
|
|
4e81981c07 | ||
|
|
af373148e3 | ||
|
|
5f292ad545 | ||
|
|
89b9d62297 | ||
|
|
396bd56d50 | ||
|
|
97b1d11adb | ||
|
|
a9a78cb4bf | ||
|
|
1f97112306 | ||
|
|
82679ab997 | ||
|
|
9fd686c2ed | ||
|
|
c4db4d132d | ||
|
|
7e5f037332 | ||
|
|
89122ff92d | ||
|
|
295dbcb4c3 | ||
|
|
8a2e842cd7 | ||
|
|
924224abc5 | ||
|
|
580819df3a | ||
|
|
faa8f73230 | ||
|
|
641a081e60 | ||
|
|
c9d058e6e3 | ||
|
|
013ba607ec | ||
|
|
e901f0046b | ||
|
|
598b45bbf4 | ||
|
|
285e6645f8 | ||
|
|
8452ecbdfd | ||
|
|
5b7dc1bcc8 | ||
|
|
77da7183f4 | ||
|
|
4541ee3079 | ||
|
|
4fca0a4140 | ||
|
|
23234bafc4 | ||
|
|
73358b7a25 | ||
|
|
c007e975aa | ||
|
|
97d8bd621e | ||
|
|
2560691c84 | ||
|
|
5da7a9fd6b | ||
|
|
a819d134fb | ||
|
|
097c48ebba | ||
|
|
452ef79ac0 | ||
|
|
cdb23ce0a4 | ||
|
|
2a57289e18 | ||
|
|
46f20a3dc1 | ||
|
|
08c9b0daaa | ||
|
|
f8119e607d | ||
|
|
a3996fc33c | ||
|
|
3866d7ecdd | ||
|
|
123c9022ec | ||
|
|
6c6cab6661 | ||
|
|
c9065e1f12 | ||
|
|
251f404ced | ||
|
|
bad52def4d | ||
|
|
12e1e51c0c | ||
|
|
1f529f333e | ||
|
|
a457ac2c82 | ||
|
|
cbc9c5e2b9 | ||
|
|
d5841e45ec | ||
|
|
d3d352948b | ||
|
|
f30d8f3d7f | ||
|
|
f974a78fb9 | ||
|
|
13ef034516 | ||
|
|
1a4da6fb18 | ||
|
|
139a3531a4 | ||
|
|
3c85d25dfc | ||
|
|
a406bac4a9 | ||
|
|
2f52844fca | ||
|
|
6ecf1f394e | ||
|
|
e3aebd3c00 | ||
|
|
1ddfae8802 | ||
|
|
d742fa9ea0 | ||
|
|
4b613f1787 | ||
|
|
afe81094ba | ||
|
|
358125dfa6 | ||
|
|
61d62c91ca | ||
|
|
033051066b | ||
|
|
9074914f39 | ||
|
|
e55779d257 | ||
|
|
11f3546ba6 | ||
|
|
e0286fdc42 | ||
|
|
60ebaf73a9 | ||
|
|
e6266dcaf2 | ||
|
|
443bcbf6c6 | ||
|
|
99dd528e55 | ||
|
|
f516505287 | ||
|
|
4203a9c9c0 | ||
|
|
5e09348c3d | ||
|
|
54eac3ddc1 | ||
|
|
d3360cdbf8 | ||
|
|
5911cce057 | ||
|
|
2361f49c1d | ||
|
|
969995283a | ||
|
|
be531b5e9f | ||
|
|
836d0b1da3 | ||
|
|
8566f830d1 | ||
|
|
d42af52ba1 | ||
|
|
80d6a75377 | ||
|
|
c24cfe135a | ||
|
|
90ad29c78e | ||
|
|
93418cb7c9 | ||
|
|
c9e61d1e22 | ||
|
|
9e67c86bc5 | ||
|
|
4b1cb237bf | ||
|
|
a1e2c253bf | ||
|
|
38a47b4680 | ||
|
|
1c820c4041 | ||
|
|
2b328583ec | ||
|
|
a638a7d852 | ||
|
|
206d084bbd | ||
|
|
3a7ec59336 | ||
|
|
e0cb654746 | ||
|
|
da2ea7d114 | ||
|
|
a7f3476568 | ||
|
|
6ccbdf6ef8 | ||
|
|
55ce938d0b | ||
|
|
3f3f29b2ec | ||
|
|
d17a61e6d0 | ||
|
|
ac4b5e60f7 | ||
|
|
8774f63e50 | ||
|
|
785e15d9fd | ||
|
|
98ad40e750 | ||
|
|
4e37fb70f1 | ||
|
|
521240cfd6 | ||
|
|
e90869c781 | ||
|
|
4f494696d9 | ||
|
|
c3d2bd8293 | ||
|
|
24c2c94633 | ||
|
|
aae8e7b63e | ||
|
|
2e0d963bd2 | ||
|
|
3546287649 | ||
|
|
41618bbdaa | ||
|
|
b1005eac5d | ||
|
|
c0f879bd19 | ||
|
|
8eae18512c | ||
|
|
c076a37540 | ||
|
|
46f19d5d64 | ||
|
|
ecf79d530a | ||
|
|
8ac30ed393 | ||
|
|
023b07743a | ||
|
|
5c7741abe3 | ||
|
|
34106a8008 | ||
|
|
98d9179419 | ||
|
|
dce74eb958 | ||
|
|
86bbb41623 | ||
|
|
e8feb1c0dc | ||
|
|
4c08c28bd5 | ||
|
|
a6f228c263 | ||
|
|
1e5ec027bb | ||
|
|
b1ab4224ef | ||
|
|
430e6916bd | ||
|
|
a5851855d9 | ||
|
|
c015375ae9 | ||
|
|
0655672c32 | ||
|
|
e0d864a2d3 | ||
|
|
47e7250b4e | ||
|
|
5c3ce75c02 | ||
|
|
754c116ff1 | ||
|
|
de6d62021a | ||
|
|
a7e39ab276 | ||
|
|
61fecd8c93 | ||
|
|
3edc55800a | ||
|
|
54a3501ddf | ||
|
|
4a1f1a895b | ||
|
|
f82a4db826 | ||
|
|
a02a58ecc9 | ||
|
|
1d7010c381 | ||
|
|
7484962441 | ||
|
|
0470988c32 | ||
|
|
279ac22463 | ||
|
|
4a042392ac | ||
|
|
cbe29c66ee | ||
|
|
f82931d6c6 | ||
|
|
6d4506c5ae | ||
|
|
6aadc2f292 | ||
|
|
6ff3cc0ae7 | ||
|
|
f4e3db8a07 | ||
|
|
ff78a5abf1 | ||
|
|
4ef65219ad | ||
|
|
c56db0f429 | ||
|
|
8e08eb0127 | ||
|
|
f69c5c3703 | ||
|
|
9d5935fb53 | ||
|
|
af2350cd16 | ||
|
|
7617996dc4 | ||
|
|
460c0334c4 | ||
|
|
672ae55ea6 | ||
|
|
0614520e5a | ||
|
|
7abfe4508c | ||
|
|
9daaf523e3 | ||
|
|
30538cf464 | ||
|
|
c766fb0237 | ||
|
|
481f9500c6 | ||
|
|
01a1fdd04b | ||
|
|
9e04968b20 | ||
|
|
f8276ac834 | ||
|
|
ac7164fb0b | ||
|
|
75e71be14d | ||
|
|
5808368b9a | ||
|
|
f3a1b5de62 | ||
|
|
4bb1e5da43 | ||
|
|
e178bd43cf | ||
|
|
096501ee20 | ||
|
|
32e5d5bc1d | ||
|
|
9b67794752 | ||
|
|
c0dbc4b0e5 | ||
|
|
dad3cb084f | ||
|
|
187c6753bd | ||
|
|
478c90b7bb | ||
|
|
09a76935c0 | ||
|
|
03576d48e8 | ||
|
|
73b83771be | ||
|
|
ecd9373df9 | ||
|
|
bdff2bddcd | ||
|
|
179be1bb15 | ||
|
|
305973038d | ||
|
|
3396d6d848 | ||
|
|
d24cef5e17 | ||
|
|
b79b324027 | ||
|
|
8516a3febf | ||
|
|
0fde929da3 | ||
|
|
8fb42c333c | ||
|
|
9b9994b358 | ||
|
|
0f435d32af |
3871 changed files with 175210 additions and 14355 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
|
@ -52,3 +52,12 @@ linphone.spec
|
|||
# VSCode
|
||||
linphone60*.log
|
||||
linphone61*.log
|
||||
linphone62*.log
|
||||
|
||||
# QT Creator
|
||||
*.cflags
|
||||
*.config
|
||||
*.creator
|
||||
*.cxxflags
|
||||
*.files
|
||||
*.includes
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
.factorize_ubuntu2004: &docker_image_platform_and_runner_tag
|
||||
tags: [ "docker" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-20-04-lts:$UBUNTU_2004_IMAGE_VERSION
|
||||
|
||||
ubuntu2004-ninja-gcc:
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_LINUX == null
|
||||
variables:
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CMAKE_OPTIONS: -DENABLE_PQCRYPTO=ON
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
|
||||
#################################################
|
||||
# Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2004-makefile-gcc:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CMAKE_OPTIONS: -DENABLE_PQCRYPTO=ON
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
ubuntu2004-ninja-clang:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
extends: .linux-desktop
|
||||
allow_failure: true
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
ubuntu2004-ninja-clang-small:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_VIDEO=NO -DENABLE_ADVANCED_IM=NO -DENABLE_DB_STORAGE=NO -DENABLE_PQCRYPTO=OFF
|
||||
allow_failure: true
|
||||
extends: ubuntu2004-ninja-clang
|
||||
|
||||
ubuntu2004-makefile-gcc:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $DEPLOY_PLUGINS
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- export Qt6_DIR=${QTLIBDIR}/cmake/Qt6
|
||||
- echo "Using Qt $QT_LINUX_VER at ${QTLIBDIR}"
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
extends: .linux-desktop
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
#################################################
|
||||
# Package - Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2004-makefile-gcc-package:
|
||||
stage: package
|
||||
tags: [ "docker" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-20-04-lts:$UBUNTU_2004_IMAGE_VERSION
|
||||
dependencies: []
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $PACKAGE_LINUX
|
||||
- if: $DEPLOY_LINUX
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$LINUX_PLATFORM/$APP_FOLDER -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
extends: .linux-desktop
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUTABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
artifacts:
|
||||
paths:
|
||||
- build/OUTPUT/*
|
||||
expire_in: 1 week
|
||||
|
||||
#################################################
|
||||
# Deploy - Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2004-makefile-gcc-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2004-makefile-gcc-package
|
||||
only:
|
||||
variables:
|
||||
- $NIGHTLY_MASTER
|
||||
- $DEPLOY_LINUX
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/Packages/*.AppImage $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER
|
||||
- |-
|
||||
if [[ $MAKE_RELEASE_FILE_URL != "" ]]; then
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $MAIN_DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
fi
|
||||
|
||||
|
||||
ubuntu2004-makefile-gcc-plugins-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2004-makefile-gcc
|
||||
only:
|
||||
variables:
|
||||
- $DEPLOY_PLUGINS
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/
|
||||
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
.factorize_ubuntu2204: &docker_image_platform_and_runner_tag
|
||||
tags: [ "docker" ]
|
||||
tags: [ "docker-flat" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
|
||||
|
||||
ubuntu2204-ninja-gcc:
|
||||
|
|
@ -36,7 +36,7 @@ ubuntu2204-ninja-clang:
|
|||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
|
||||
CMAKE_GENERATOR: Ninja
|
||||
CC: clang
|
||||
CXX: clang++
|
||||
|
|
@ -53,41 +53,17 @@ ubuntu2204-ninja-clang-small:
|
|||
allow_failure: true
|
||||
extends: ubuntu2204-ninja-clang
|
||||
|
||||
ubuntu2204-makefile-gcc:
|
||||
ubuntu2204-makefile-gcc-signed:
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $DEPLOY_PLUGINS
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- export Qt6_DIR=${QTLIBDIR}/cmake/Qt6
|
||||
- echo "Using Qt $QT_LINUX_VER at ${QTLIBDIR}"
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
extends: .linux-desktop
|
||||
extends: .linux-sign-build
|
||||
<<: *docker_image_platform_and_runner_tag
|
||||
|
||||
#################################################
|
||||
|
|
@ -95,77 +71,41 @@ ubuntu2204-makefile-gcc:
|
|||
#################################################
|
||||
|
||||
ubuntu2204-makefile-gcc-package:
|
||||
stage: package
|
||||
tags: [ "docker" ]
|
||||
tags: [ "docker-flat" ]
|
||||
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
|
||||
dependencies: []
|
||||
needs: []
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $PACKAGE_LINUX
|
||||
- if: $DEPLOY_LINUX
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$LINUX_PLATFORM/$APP_FOLDER -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_GENERATOR: Unix Makefiles
|
||||
CC: gcc
|
||||
CXX: g++
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
extends: .linux-desktop
|
||||
script:
|
||||
- echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- gpg --import file.key
|
||||
- rm -f file.key
|
||||
- echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
- base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
- rm -f file.key
|
||||
- cmake --version
|
||||
- export CC=$CC
|
||||
- export CXX=$CXX
|
||||
- mkdir -p build/OUTPUT
|
||||
- echo $CI_BUILD_TYPE
|
||||
- echo $CMAKE_GENERATOR
|
||||
- echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
- echo $CMAKE_SANITIZER_OPTIONS
|
||||
- eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
- export PATH=${QTTOOLDIR}:$PATH
|
||||
- cd build
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUTABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
artifacts:
|
||||
paths:
|
||||
- build/OUTPUT/*
|
||||
expire_in: 1 week
|
||||
extends: .linux-sign-package
|
||||
|
||||
#################################################
|
||||
# Deploy - Nightly
|
||||
#################################################
|
||||
|
||||
ubuntu2204-makefile-gcc-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc-package
|
||||
only:
|
||||
extends: .linux-deploy
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc-package
|
||||
only:
|
||||
variables:
|
||||
- $NIGHTLY_MASTER
|
||||
- $DEPLOY_LINUX
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/Packages/*.AppImage $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER
|
||||
- |-
|
||||
if [[ $MAKE_RELEASE_FILE_URL != "" ]]; then
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
rsync -rlv build/OUTPUT/Packages/RELEASE $MAIN_DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
fi
|
||||
|
||||
|
||||
ubuntu2204-makefile-gcc-plugins-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy" ]
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc
|
||||
only:
|
||||
stage: deploy
|
||||
tags: [ "deploy-flat" ]
|
||||
needs:
|
||||
- ubuntu2204-makefile-gcc
|
||||
only:
|
||||
variables:
|
||||
- $DEPLOY_PLUGINS
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/
|
||||
script:
|
||||
- rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# BUILD
|
||||
#################################################
|
||||
|
||||
.build_all_linux_script: &build_all_linux_script |
|
||||
.common_linux: &common_linux |
|
||||
cmake --version
|
||||
export CC=$CC
|
||||
export CXX=$CXX
|
||||
|
|
@ -11,20 +11,68 @@
|
|||
echo $CMAKE_GENERATOR
|
||||
echo $DEFAULT_LINUX_CMAKE_OPTIONS
|
||||
echo $CMAKE_SANITIZER_OPTIONS
|
||||
cd build
|
||||
eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
|
||||
eval "$(qtchooser -qt=$QT_LINUX_VER-${QT_OPEN_SOURCE_DIRECTORY:-proprietary} -print-env)"
|
||||
export PATH=${QTTOOLDIR}:$PATH
|
||||
export Qt6_DIR=${QTLIBDIR}/cmake/Qt6
|
||||
echo "Using Qt $QT_LINUX_VER at ${QTLIBDIR}"
|
||||
cd build
|
||||
|
||||
.build_all_linux_script: &build_all_linux_script |
|
||||
cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
|
||||
|
||||
.common_signed_linux: &common_signed_linux |
|
||||
echo "$GPG_SIGNING_PUB" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
gpg --import file.key
|
||||
rm -f file.key
|
||||
echo "$GPG_SIGNING_KEY" > file.key && sed -i 's/\r /\n/g' file.key && chmod 600 file.key
|
||||
base64 -w 0 file.key | base64 -d | gpg --import --no-tty --batch --yes
|
||||
rm -f file.key
|
||||
|
||||
.deploy_linux: &deploy_linux |
|
||||
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r --ignore-existing build/OUTPUT/Packages/*.AppImage $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER
|
||||
if [[ $MAKE_RELEASE_FILE_URL != "" ]]; then
|
||||
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r build/OUTPUT/Packages/RELEASE $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
rsync -rlv --chmod=Fu=rw,Fg=r,Fo=r build/OUTPUT/Packages/RELEASE $MAIN_DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM
|
||||
fi
|
||||
|
||||
.linux-desktop:
|
||||
stage: build
|
||||
extends: .linux-prepare
|
||||
script:
|
||||
- *common_linux
|
||||
- *build_all_linux_script
|
||||
artifacts:
|
||||
paths:
|
||||
- build/OUTPUT
|
||||
expire_in: 1 week
|
||||
|
||||
.linux-sign-build:
|
||||
extends: .linux-desktop
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
script:
|
||||
- *common_signed_linux
|
||||
- *common_linux
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
|
||||
.linux-sign-package:
|
||||
stage: package
|
||||
extends: .linux-desktop
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DLINPHONE_BUILDER_SIGNING_IDENTITY=$GPG_SIGNING_KEYID -DENABLE_G729=ON -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$LINUX_PLATFORM/$APP_FOLDER -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
|
||||
APPIMAGETOOL_SIGN_PASSPHRASE: $GPG_SIGNING_PASS
|
||||
script:
|
||||
- *common_signed_linux
|
||||
- *common_linux
|
||||
- cmake .. -G "$CMAKE_GENERATOR" -DCMAKE_VERBOSE_MAKEFILE=ON -DLINPHONESDK_PLATFORM=Desktop -DCMAKE_BUILD_TYPE=$CI_BUILD_TYPE -DLINPHONEAPP_APPLICATION_NAME="$APPLICATION_NAME" -DLINPHONEAPP_EXECUTABLE_NAME="$EXECUTABLE_NAME" $DEFAULT_LINUX_CMAKE_OPTIONS $CMAKE_OPTIONS $SCHEDULE_CMAKE_OPTIONS $CMAKE_SANITIZER_OPTIONS
|
||||
- cmake --build . --target install --config $CI_BUILD_TYPE $LBC_NODEBUG_OPTIONS
|
||||
|
||||
|
||||
.linux-deploy:
|
||||
stage: deploy
|
||||
tags: [ "deploy-flat" ]
|
||||
script:
|
||||
- *deploy_linux
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
.macosx-desktop:
|
||||
stage: build
|
||||
tags: [ "macos-min-xcode12.2" ]
|
||||
tags: [ "macmini-m1-xcode15-flat" ]
|
||||
rules:
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
|
||||
|
|
@ -93,8 +93,8 @@ macosx-ninja-novideo:
|
|||
# WAIT for QT6 for arm64
|
||||
macosx-ninja-package:
|
||||
stage: package
|
||||
tags: [ "macos-min-xcode12.2" ]
|
||||
dependencies: []
|
||||
tags: [ "macmini-m1-xcode15-flat" ]
|
||||
needs: []
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
|
||||
|
|
@ -102,7 +102,7 @@ macosx-ninja-package:
|
|||
- if: $PACKAGE_MACOSX
|
||||
- if: $DEPLOY_MACOSX
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=ON -DENABLE_G729=ON
|
||||
CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_G729=ON
|
||||
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$MACOSX_PLATFORM/$APP_FOLDER
|
||||
extends: macosx-ninja
|
||||
script:
|
||||
|
|
@ -117,7 +117,7 @@ macosx-ninja-package:
|
|||
|
||||
macosx-codesigning:
|
||||
stage: signing
|
||||
tags: [ "macos-min-xcode12.2" ]
|
||||
tags: [ "macmini-m1-xcode15-flat" ]
|
||||
needs:
|
||||
- macosx-ninja-package
|
||||
rules:
|
||||
|
|
@ -142,7 +142,7 @@ macosx-codesigning:
|
|||
|
||||
macosx-deploy:
|
||||
stage: deploy
|
||||
tags: [ "macos-min-xcode12.2" ]
|
||||
tags: [ "macmini-m1-xcode15-flat" ]
|
||||
needs:
|
||||
- macosx-codesigning
|
||||
only:
|
||||
|
|
@ -160,7 +160,7 @@ macosx-deploy:
|
|||
|
||||
macosx-makefile-plugins-deploy:
|
||||
stage: deploy
|
||||
tags: [ "macos-min-xcode12.2" ]
|
||||
tags: [ "macmini-m1-xcode15-flat" ]
|
||||
needs:
|
||||
- macosx-makefile
|
||||
only:
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null
|
||||
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
|
||||
LINPHONESDK_PLATFORM: Desktop
|
||||
OUTPUT_ZIP_FOLDER: win64
|
||||
MINGW_TYPE: mingw64
|
||||
|
|
@ -92,11 +92,11 @@
|
|||
|
||||
.windows-vs2022:
|
||||
extends: .windows-vs
|
||||
tags: [ "windows-powershell-vs-17-2022" ]
|
||||
tags: [ "windows-powershell-vs-17-2022-flat" ]
|
||||
|
||||
.windows-codesigning:
|
||||
extends: .prepare
|
||||
tags: [ "windows-powershell-vs-17-2022-apps" ]
|
||||
tags: [ "windows-powershell-vs-17-2022-apps-flat" ]
|
||||
|
||||
.windows-msbuild-variables:
|
||||
variables:
|
||||
|
|
@ -177,7 +177,7 @@ win64-ninja-vs2022-scheduled-windows:
|
|||
|
||||
.vs-win64-package:
|
||||
stage: package
|
||||
dependencies: []
|
||||
needs: []
|
||||
rules:
|
||||
- !reference [.rules-merge-request-manual, rules]
|
||||
- if: $NIGHTLY_MASTER
|
||||
|
|
@ -185,7 +185,7 @@ win64-ninja-vs2022-scheduled-windows:
|
|||
- if: $PACKAGE_WINDOWS
|
||||
- if: $DEPLOY_WINDOWS
|
||||
variables:
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
|
||||
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF
|
||||
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER
|
||||
|
||||
win64-ninja-vs2022-package-windows:
|
||||
|
|
@ -232,15 +232,15 @@ win64-codesigning:
|
|||
|
||||
.win64-upload:
|
||||
stage: deploy
|
||||
tags: [ "windows-powershell" ]
|
||||
tags: [ "windows-powershell-flat" ]
|
||||
rules:
|
||||
- if: $NIGHTLY_MASTER
|
||||
- if: $DEPLOY_WINDOWS
|
||||
|
||||
script:
|
||||
- scp -pr build-desktop/OUTPUT/Packages/*.exe ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/${APP_FOLDER}
|
||||
- if ($MAKE_RELEASE_FILE_URL) { scp -pr build-desktop/OUTPUT/Packages/RELEASE ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
|
||||
- if ($MAKE_RELEASE_FILE_URL) { scp -pr build-desktop/OUTPUT/Packages/RELEASE ${MAIN_DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
|
||||
- rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/*.exe ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/${APP_FOLDER}
|
||||
- if ($MAKE_RELEASE_FILE_URL) { rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/RELEASE ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
|
||||
- if ($MAKE_RELEASE_FILE_URL) { rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/RELEASE ${MAIN_DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
|
||||
|
||||
win64-ninja-vs2022-upload:
|
||||
extends:
|
||||
|
|
@ -250,7 +250,7 @@ win64-ninja-vs2022-upload:
|
|||
|
||||
.win64-plugins-upload:
|
||||
stage: deploy
|
||||
tags: [ "windows" ]
|
||||
tags: [ "windows-flat" ]
|
||||
rules:
|
||||
- if: $DEPLOY_PLUGINS
|
||||
script:
|
||||
|
|
|
|||
|
|
@ -21,13 +21,7 @@ variables:
|
|||
#CMAKE_OPTIONS: -DENABLE_LIME_X3DH=YES
|
||||
|
||||
# Docker image version
|
||||
ARCHLINUX_IMAGE_VERSION: latestupdated
|
||||
CENTOS_7_QT_IMAGE_VERSION: 20211012_add_qtwebview
|
||||
DEBIAN_9_QT_IMAGE_VERSION: 20230417_qtopen_gstreamer
|
||||
DEBIAN_10_IMAGE_VERSION: 20210217_python3
|
||||
UBUNTU_ROLLING_IMAGE_VERSION: 20211012_add_qtwebview
|
||||
UBUNTU_2004_IMAGE_VERSION: 20250226_qt6-8-0
|
||||
UBUNTU_2204_IMAGE_VERSION: 20250512_qt6-9-0
|
||||
UBUNTU_2204_IMAGE_VERSION: 20251106_add_commercial_qt_version_5.15.14_5.15.19_6.8.1_6.8.3_6.9.1_6.10.0
|
||||
|
||||
|
||||
workflow:
|
||||
|
|
@ -51,7 +45,6 @@ include:
|
|||
- '.gitlab-ci-files/rules.yml'
|
||||
- '.gitlab-ci-files/linux-prepare.yml'
|
||||
- '.gitlab-ci-files/linux-desktop.yml'
|
||||
# - '.gitlab-ci-files/linux-desktop-ubuntu-2004.yml'
|
||||
- '.gitlab-ci-files/linux-desktop-ubuntu-2204.yml'
|
||||
- '.gitlab-ci-files/windows-desktop.yml'
|
||||
- '.gitlab-ci-files/macosx-desktop.yml'
|
||||
|
|
|
|||
2
.gitmodules
vendored
2
.gitmodules
vendored
|
|
@ -1,3 +1,3 @@
|
|||
[submodule "linphone-sdk"]
|
||||
path = external/linphone-sdk
|
||||
url = https://gitlab.linphone.org/BC/public/linphone-sdk.git
|
||||
url = https://gitlab.linphone.org/BC/public/linphone-sdk.git
|
||||
|
|
|
|||
|
|
@ -31,3 +31,9 @@ Group changes to describe their impact on the project, as follows:
|
|||
- Default screen (between contacts, call history, conversations & meetings list) will change depending on where you were when the app was paused or killed, and you will return to that last visited screen on the next startup.
|
||||
- Minimum supported Qt version is now 6.5.3
|
||||
- Some settings have changed name and/or section in linphonerc file.
|
||||
|
||||
|
||||
## [6.1.0] - XXXX-XX-XX
|
||||
|
||||
### Changed
|
||||
- Minimum supported Qt version is now 6.10.0
|
||||
|
|
@ -60,7 +60,6 @@ project(linphoneqt)
|
|||
|
||||
include(GNUInstallDirs)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(Linphone/application_info.cmake)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
if(LINPHONEAPP_INSTALL_PREFIX)
|
||||
|
|
@ -72,8 +71,11 @@ endif()
|
|||
|
||||
set(CMAKE_INSTALL_PREFIX "${APPLICATION_OUTPUT_DIR}")
|
||||
|
||||
set(LINPHONEAPP_APPLICATION_NAME "Linphone6" CACHE STRING "Application name" )
|
||||
set(LINPHONEAPP_EXECUTABLE_NAME "linphone6" CACHE STRING "Executable name" )
|
||||
set(LINPHONEAPP_APPLICATION_NAME "Linphone" CACHE STRING "Application name" )
|
||||
set(LINPHONEAPP_EXECUTABLE_NAME "linphone" CACHE STRING "Executable name" )
|
||||
|
||||
# Include application_info.cmake here as the LINPHONEAPP_APPLICATION_NAME variable must be known as it is set to the APPLICATION_NAME variable.
|
||||
include(Linphone/application_info.cmake)
|
||||
|
||||
if( APPLE )
|
||||
set(LINPHONEAPP_MACOS_ARCHS "arm64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]")
|
||||
|
|
@ -163,7 +165,7 @@ add_option(OPTION_LIST ENABLE_FFMPEG "Build mediastreamer2 with ffmpeg video sup
|
|||
add_option(OPTION_LIST ENABLE_LDAP "Enable LDAP support." YES)
|
||||
add_option(OPTION_LIST ENABLE_NON_FREE_CODECS "Enable the use of non free codecs" YES)
|
||||
add_option(OPTION_LIST ENABLE_NON_FREE_FEATURES "Enable the use of non free codecs" ${ENABLE_NON_FREE_CODECS})
|
||||
add_option(OPTION_LIST ENABLE_QT_KEYCHAIN "Build QtKeychain to manage VFS from System key stores." ON)
|
||||
add_option(OPTION_LIST ENABLE_QT_KEYCHAIN "Build QtKeychain to manage VFS from System key stores." OFF)
|
||||
add_option(OPTION_LIST ENABLE_QRCODE "Enable QRCode support" OFF)#Experimental
|
||||
add_option(OPTION_LIST ENABLE_RELATIVE_PREFIX "Set Internal packages relative to the binary" ON)
|
||||
add_option(OPTION_LIST ENABLE_SANITIZER "Enable sanitizer." OFF)
|
||||
|
|
@ -185,9 +187,9 @@ add_option(OPTION_LIST ENABLE_SCREENSHARING "Enable screen sharing." ${ENABLE_VI
|
|||
# QtKeychain
|
||||
add_option(OPTION_LIST LIBSECRET_SUPPORT "Build with libsecret support" OFF) # Need libsecret-devel
|
||||
if(WIN32)
|
||||
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt5Keychain library name for a workaround with windeployqt" "EQt5Keychain")
|
||||
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt6Keychain library name for a workaround with windeployqt" "EQt6Keychain")
|
||||
else()
|
||||
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt5Keychain library name" "Qt5Keychain")
|
||||
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt6Keychain library name" "Qt6Keychain")
|
||||
endif()
|
||||
if(WIN32)
|
||||
add_option(OPTION_LIST ENABLE_OPENSSL_EXPORT "Enable OpenSSL deployment" YES)
|
||||
|
|
@ -206,7 +208,7 @@ set(ENABLE_CSHARP_WRAPPER OFF CACHE BOOL "Build the CSharp wrapper for Liblinpho
|
|||
set(ENABLE_THEORA OFF)
|
||||
set(ENABLE_QT_GL ${ENABLE_VIDEO})
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core Quick Widgets)
|
||||
|
||||
if(NOT Qt6_FOUND)
|
||||
message(FATAL_ERROR "Minimum supported Qt6!")
|
||||
|
|
@ -227,18 +229,11 @@ endif()
|
|||
if(NOT APPLE OR MONO_ARCH)
|
||||
add_custom_target(linphone-deps)
|
||||
if(NOT LINPHONE_QT_ONLY)
|
||||
function(add_external)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here
|
||||
add_subdirectory("external")
|
||||
endfunction()
|
||||
add_external()
|
||||
|
||||
if(ENABLE_QT_KEYCHAIN)
|
||||
function(add_linphone_keychain)
|
||||
#add_subdirectory("external/qtkeychain")
|
||||
endfunction()
|
||||
add_linphone_keychain()
|
||||
endif()
|
||||
function(add_external)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here
|
||||
add_subdirectory("external")
|
||||
endfunction()
|
||||
add_external()
|
||||
endif()
|
||||
function(add_linphone_app)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here
|
||||
|
|
@ -270,4 +265,16 @@ else()
|
|||
include(cmake/TasksMacos.cmake)
|
||||
endif()
|
||||
|
||||
# if (ENABLE_QT_KEYCHAIN)
|
||||
# target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${PROJECT_SOURCE_DIR}/external/qtkeychain)
|
||||
# target_link_libraries(${TARGET_NAME} PUBLIC ${QTKEYCHAIN_TARGET_NAME})
|
||||
# message(STATUS "link libraries: ${TARGET_NAME} ${QTKEYCHAIN_TARGET_NAME}")
|
||||
# message(STATUS "CMAKE_CURRENT_SOURCE_DIR: ${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
# message(STATUS "PROJECT_SOURCE_DIR: ${PROJECT_SOURCE_DIR}")
|
||||
# message(STATUS "Contents of qtkeychain:")
|
||||
# file(GLOB QTKEYCHAIN_HEADERS "${PROJECT_SOURCE_DIR}/external/qtkeychain/qtkeychain/*.h")
|
||||
# message(STATUS "Found headers: ${QTKEYCHAIN_HEADERS}")
|
||||
# endif()
|
||||
|
||||
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/hook/pre-commit" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/")
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(Linphone VERSION 6.0.0 LANGUAGES CXX)
|
||||
project(Linphone VERSION 6.2.0 LANGUAGES CXX)
|
||||
|
||||
################################################################
|
||||
# PACKAGES
|
||||
|
|
@ -19,14 +19,14 @@ endforeach()
|
|||
set(TARGET_NAME Linphone)
|
||||
set(APP_TARGETS ${LinphoneCxx_TARGET}
|
||||
${Mediastreamer2_TARGET}#MediastreamerUtils
|
||||
${LibLinphone_TARGET})#MediastreamerUtils
|
||||
${LibLinphone_TARGET})#Liblinphone
|
||||
|
||||
set(QT_DEFAULT_MAJOR_VERSION 6)
|
||||
set(QT_PACKAGES Core Quick Qml Widgets Svg Multimedia Test NetworkAuth Concurrent)# Search Core at first for initialize Qt scripts for next find_packages.
|
||||
set(QT_PACKAGES Quick Qml Widgets Svg Multimedia Test NetworkAuth Concurrent)# Search Core at first for initialize Qt scripts for next find_packages.
|
||||
if (UNIX AND NOT APPLE)
|
||||
list(APPEND QT_PACKAGES DBus)
|
||||
endif()
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt6 REQUIRED COMPONENTS ${QT_PACKAGES})
|
||||
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
|
||||
|
||||
|
|
@ -98,15 +98,11 @@ endif()
|
|||
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h")
|
||||
|
||||
if(${Qt6_VERSION} VERSION_LESS "6.3.0")
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
else()
|
||||
qt6_standard_project_setup()
|
||||
if(${Qt6_VERSION} VERSION_LESS "6.10.0")
|
||||
message( FATAL_ERROR "Linphone requires Qt 6.10.0 or newer. Exiting CMake." )
|
||||
endif()
|
||||
|
||||
|
||||
qt6_standard_project_setup()
|
||||
|
||||
|
||||
################################################################
|
||||
|
|
@ -127,7 +123,7 @@ add_subdirectory(core)
|
|||
|
||||
set(LANGUAGES_DIRECTORY "data/languages")
|
||||
set(I18N_FILENAME i18n.qrc)
|
||||
set(LANGUAGES en fr_FR de)
|
||||
set(LANGUAGES en fr de)
|
||||
|
||||
# Add languages support.
|
||||
add_subdirectory("${LANGUAGES_DIRECTORY}" "data/languages")
|
||||
|
|
@ -174,6 +170,12 @@ qt6_add_qml_module(Linphone
|
|||
RESOURCES data/fonts.qrc
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
if(MSVC AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
|
||||
install(FILES "$<TARGET_PDB_FILE:${TARGET_NAME}>" DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
qt6_add_resources(Linphone "resources" PREFIX "/" FILES ${_LINPHONEAPP_RC_FILES})
|
||||
set_property(TARGET Linphone PROPERTY POSITION_INDEPENDENT_CODE ON) #Need by Qt
|
||||
|
||||
|
|
@ -199,6 +201,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES
|
|||
if(MSVC)
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES PDB_NAME "${EXECUTABLE_NAME}_app")
|
||||
endif()
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
if(WIN32)
|
||||
if(ENABLE_SCREENSHARING)
|
||||
|
|
@ -214,6 +217,7 @@ foreach(T ${APP_TARGETS})
|
|||
target_link_libraries(${TARGET_NAME} PUBLIC ${T})
|
||||
endforeach()
|
||||
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE Qt6::Core)
|
||||
foreach(T ${QT_PACKAGES})
|
||||
target_link_libraries(${TARGET_NAME} PRIVATE Qt6::${T})
|
||||
endforeach()
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "App.hpp"
|
||||
|
||||
#include <QAction>
|
||||
#include <QCoreApplication>
|
||||
#include <QDirIterator>
|
||||
#include <QFileSelector>
|
||||
|
|
@ -53,9 +52,19 @@
|
|||
#include "core/call/CallList.hpp"
|
||||
#include "core/call/CallProxy.hpp"
|
||||
#include "core/camera/CameraGui.hpp"
|
||||
#include "core/chat/ChatProxy.hpp"
|
||||
#include "core/chat/files/ChatMessageFileProxy.hpp"
|
||||
#include "core/chat/message/ChatMessageGui.hpp"
|
||||
#include "core/chat/message/EventLogGui.hpp"
|
||||
#include "core/chat/message/EventLogList.hpp"
|
||||
#include "core/chat/message/EventLogProxy.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentGui.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentProxy.hpp"
|
||||
#include "core/chat/message/imdn/ImdnStatusProxy.hpp"
|
||||
#include "core/conference/ConferenceGui.hpp"
|
||||
#include "core/conference/ConferenceInfoGui.hpp"
|
||||
#include "core/conference/ConferenceInfoProxy.hpp"
|
||||
#include "core/emoji/EmojiProxy.hpp"
|
||||
#include "core/fps-counter/FPSCounter.hpp"
|
||||
#include "core/friend/FriendCore.hpp"
|
||||
#include "core/friend/FriendGui.hpp"
|
||||
|
|
@ -64,34 +73,50 @@
|
|||
#include "core/notifier/Notifier.hpp"
|
||||
#include "core/participant/ParticipantDeviceProxy.hpp"
|
||||
#include "core/participant/ParticipantGui.hpp"
|
||||
#include "core/participant/ParticipantInfoProxy.hpp"
|
||||
#include "core/participant/ParticipantProxy.hpp"
|
||||
#include "core/payload-type/PayloadTypeCore.hpp"
|
||||
#include "core/payload-type/PayloadTypeGui.hpp"
|
||||
#include "core/payload-type/PayloadTypeProxy.hpp"
|
||||
#include "core/phone-number/PhoneNumber.hpp"
|
||||
#include "core/phone-number/PhoneNumberProxy.hpp"
|
||||
#include "core/recorder/RecorderGui.hpp"
|
||||
#include "core/register/RegisterPage.hpp"
|
||||
#include "core/screen/ScreenList.hpp"
|
||||
#include "core/screen/ScreenProxy.hpp"
|
||||
#include "core/search/MagicSearchProxy.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "core/sound-player/SoundPlayerGui.hpp"
|
||||
#include "core/timezone/TimeZoneProxy.hpp"
|
||||
#include "core/translator/DefaultTranslatorCore.hpp"
|
||||
#include "core/variant/VariantList.hpp"
|
||||
#include "core/videoSource/VideoSourceDescriptorGui.hpp"
|
||||
#include "model/friend/FriendsManager.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/EnumsToString.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/accessibility/AccessibilityHelper.hpp"
|
||||
#include "tool/accessibility/FocusHelper.hpp"
|
||||
#include "tool/accessibility/KeyboardShortcuts.hpp"
|
||||
#include "tool/native/DesktopTools.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include "tool/providers/EmojiProvider.hpp"
|
||||
#include "tool/providers/ImageProvider.hpp"
|
||||
#include "tool/providers/ScreenProvider.hpp"
|
||||
#include "tool/providers/ThumbnailProvider.hpp"
|
||||
#include "tool/request/CallbackHelper.hpp"
|
||||
#include "tool/request/RequestDialog.hpp"
|
||||
#include "tool/thread/Thread.hpp"
|
||||
#include "tool/ui/DashRectangle.hpp"
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
#include "core/event-count-notifier/EventCountNotifierMacOs.hpp"
|
||||
#else
|
||||
#include "core/event-count-notifier/EventCountNotifierSystemTrayIcon.hpp"
|
||||
#endif // if defined(Q_OS_MACOS)
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(App)
|
||||
|
||||
|
|
@ -242,9 +267,7 @@ void App::setAutoStart(bool enabled) {
|
|||
|
||||
void App::setAutoStart(bool enabled) {
|
||||
QSettings settings(AutoStartSettingsFilePath, QSettings::NativeFormat);
|
||||
QString parameters;
|
||||
if (!mSettings->getExitOnClose()) parameters = " --minimized";
|
||||
if (enabled) settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath()) + parameters);
|
||||
if (enabled) settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath()));
|
||||
else settings.remove(EXECUTABLE_NAME);
|
||||
|
||||
mAutoStart = enabled;
|
||||
|
|
@ -259,10 +282,14 @@ void App::setAutoStart(bool enabled) {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
App::App(int &argc, char *argv[])
|
||||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
: SingleApplication(argc, argv, true, Mode::User | Mode::ExcludeAppPath | Mode::ExcludeAppVersion) {
|
||||
// Do not use APPLICATION_NAME here.
|
||||
// The EXECUTABLE_NAME will be used in qt standard paths. It's our goal.
|
||||
QDir::setCurrent(
|
||||
QCoreApplication::applicationDirPath()); // Set working directory as the executable to allow relative paths.
|
||||
QThread::currentThread()->setPriority(QThread::HighPriority);
|
||||
qDebug() << "app thread is" << QThread::currentThread();
|
||||
lDebug() << "Starting app with Qt version" << qVersion();
|
||||
QCoreApplication::setApplicationName(EXECUTABLE_NAME);
|
||||
QApplication::setOrganizationDomain(EXECUTABLE_NAME);
|
||||
QCoreApplication::setApplicationVersion(APPLICATION_SEMVER);
|
||||
|
|
@ -279,7 +306,7 @@ App::App(int &argc, char *argv[])
|
|||
.arg(applicationVersion())
|
||||
.arg(Utils::getOsProduct())
|
||||
.arg(qVersion());
|
||||
|
||||
lInfo() << "at " << QDir().absolutePath();
|
||||
mCurrentDate = QDate::currentDate();
|
||||
mAutoStart = autoStartEnabled();
|
||||
mDateUpdateTimer.setInterval(60000);
|
||||
|
|
@ -291,7 +318,12 @@ App::App(int &argc, char *argv[])
|
|||
emit currentDateChanged();
|
||||
}
|
||||
});
|
||||
mEventCountNotifier = new EventCountNotifier(this);
|
||||
mDateUpdateTimer.start();
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
exportDesktopFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
App::~App() {
|
||||
|
|
@ -305,7 +337,7 @@ void App::setSelf(QSharedPointer<App>(me)) {
|
|||
auto callCore = CallCore::create(call);
|
||||
mCoreModelConnection->invokeToCore([this, callCore] {
|
||||
auto callGui = new CallGui(callCore);
|
||||
auto win = getCallsWindow(QVariant::fromValue(callGui));
|
||||
auto win = getOrCreateCallsWindow(QVariant::fromValue(callGui));
|
||||
Utils::smartShowWindow(win);
|
||||
auto mainwin = getMainWindow();
|
||||
QMetaObject::invokeMethod(mainwin, "callCreated");
|
||||
|
|
@ -349,21 +381,106 @@ void App::setSelf(QSharedPointer<App>(me)) {
|
|||
}
|
||||
});
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::authenticationRequested, &App::onAuthenticationRequested);
|
||||
// Config error message
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::configuringStatus, [this](const std::shared_ptr<linphone::Core> &core,
|
||||
linphone::ConfiguringState status, const std::string &message) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (status == linphone::ConfiguringState::Failed) {
|
||||
mCoreModelConnection->invokeToCore([this, message]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
//: Error
|
||||
Utils::showInformationPopup(
|
||||
tr("info_popup_error_title"),
|
||||
tr("info_popup_configuration_failed_message").arg(Utils::coreStringToAppString(message)),
|
||||
false);
|
||||
});
|
||||
}
|
||||
});
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::accountAdded,
|
||||
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (CoreModel::getInstance()->mConfigStatus == linphone::ConfiguringState::Successful) {
|
||||
bool accountConnected = account && account->getState() == linphone::RegistrationState::Ok;
|
||||
mCoreModelConnection->invokeToCore([this, accountConnected]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
// There is an account added by a remote provisioning, force switching to main page
|
||||
// because the account may not be connected already
|
||||
// if (accountConnected)
|
||||
if (mPossiblyLookForAddedAccount) {
|
||||
QMetaObject::invokeMethod(mMainWindow, "openMainPage", Qt::DirectConnection,
|
||||
Q_ARG(QVariant, accountConnected));
|
||||
}
|
||||
mPossiblyLookForAddedAccount = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Synchronize state for because linphoneCore was ran before any connections.
|
||||
mCoreModelConnection->invokeToModel([this]() {
|
||||
auto state = CoreModel::getInstance()->getCore()->getGlobalState();
|
||||
mCoreModelConnection->invokeToCore([this, state] { setCoreStarted(state == linphone::GlobalState::On); });
|
||||
});
|
||||
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::unreadNotificationsChanged, [this] {
|
||||
int n = mEventCountNotifier->getCurrentEventCount();
|
||||
mCoreModelConnection->invokeToCore([this, n] { mEventCountNotifier->notifyEventCount(n); });
|
||||
});
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, [this] {
|
||||
int n = mEventCountNotifier->getCurrentEventCount();
|
||||
mCoreModelConnection->invokeToCore([this, n] {
|
||||
mEventCountNotifier->notifyEventCount(n);
|
||||
emit defaultAccountChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// Check update
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::versionUpdateCheckResultReceived,
|
||||
[this](const std::shared_ptr<linphone::Core> &core, linphone::VersionUpdateCheckResult result,
|
||||
const std::string &version, const std::string &url, bool checkRequestedByUser) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
mCoreModelConnection->invokeToCore([this, result, version, url, checkRequestedByUser] {
|
||||
switch (result) {
|
||||
case linphone::VersionUpdateCheckResult::Error:
|
||||
Utils::showInformationPopup(tr("info_popup_error_title"),
|
||||
//: An error occured while trying to check update. Please
|
||||
//: try again later or contact support team.
|
||||
tr("info_popup_error_checking_update"), false);
|
||||
break;
|
||||
case linphone::VersionUpdateCheckResult::NewVersionAvailable: {
|
||||
QString downloadLink =
|
||||
QStringLiteral("<a href='%1'><font color='DefaultStyle.main2_600'>%2</a>")
|
||||
.arg(url)
|
||||
//: Download it !
|
||||
.arg(tr("info_popup_new_version_download_label"));
|
||||
Utils::showInformationPopup(
|
||||
//: New version available !
|
||||
tr("info_popup_new_version_available_title"),
|
||||
//: A new version of Linphone (%1) is available. %2
|
||||
tr("info_popup_new_version_available_message").arg(version).arg(downloadLink));
|
||||
break;
|
||||
}
|
||||
case linphone::VersionUpdateCheckResult::UpToDate:
|
||||
if (checkRequestedByUser)
|
||||
//: Up to date
|
||||
Utils::showInformationPopup(tr("info_popup_version_up_to_date_title"),
|
||||
//: Your version is up to date
|
||||
tr("info_popup_version_up_to_date_message"));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
mCliModelConnection = SafeConnection<App, CliModel>::create(me, CliModel::getInstance());
|
||||
mCliModelConnection->makeConnectToCore(&App::receivedMessage, [this](int, const QByteArray &byteArray) {
|
||||
QString command(byteArray);
|
||||
if (command.isEmpty()) {
|
||||
lDebug() << log().arg("Check with CliModel for commands");
|
||||
lInfo() << log().arg("Check with CliModel for commands");
|
||||
mCliModelConnection->invokeToModel([]() { CliModel::getInstance()->runProcess(); });
|
||||
} else {
|
||||
qInfo() << QStringLiteral("Received command from other application: `%1`.").arg(command);
|
||||
lInfo() << log().arg("Received command from other application: `%1`.").arg(command);
|
||||
mCliModelConnection->invokeToModel([command]() { CliModel::getInstance()->executeCommand(command); });
|
||||
}
|
||||
});
|
||||
|
|
@ -376,13 +493,22 @@ App *App::getInstance() {
|
|||
return dynamic_cast<App *>(QApplication::instance());
|
||||
}
|
||||
|
||||
QThread *App::getLinphoneThread() {
|
||||
Thread *App::getLinphoneThread() {
|
||||
return App::getInstance()->mLinphoneThread;
|
||||
}
|
||||
|
||||
Notifier *App::getNotifier() const {
|
||||
return mNotifier;
|
||||
}
|
||||
|
||||
EventCountNotifier *App::getEventCountNotifier() {
|
||||
return mEventCountNotifier;
|
||||
}
|
||||
|
||||
int App::getEventCount() const {
|
||||
return mEventCountNotifier ? mEventCountNotifier->getEventCount() : 0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Initializations
|
||||
//-----------------------------------------------------------
|
||||
|
|
@ -422,10 +548,12 @@ void App::init() {
|
|||
}
|
||||
|
||||
void App::initCore() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
// Core. Manage the logger so it must be instantiate at first.
|
||||
CoreModel::create("", mLinphoneThread);
|
||||
if (mParser->isSet("verbose")) QtLogger::enableVerbose(true);
|
||||
if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true);
|
||||
qDebug() << "linphone thread is" << mLinphoneThread;
|
||||
QMetaObject::invokeMethod(
|
||||
mLinphoneThread->getThreadId(),
|
||||
[this, settings = mSettings]() mutable {
|
||||
|
|
@ -483,10 +611,12 @@ void App::initCore() {
|
|||
|
||||
initCppInterfaces();
|
||||
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
|
||||
mEngine->addImageProvider(EmojiProvider::ProviderId, new EmojiProvider());
|
||||
mEngine->addImageProvider(AvatarProvider::ProviderId, new AvatarProvider());
|
||||
mEngine->addImageProvider(ScreenProvider::ProviderId, new ScreenProvider());
|
||||
mEngine->addImageProvider(WindowProvider::ProviderId, new WindowProvider());
|
||||
mEngine->addImageProvider(WindowIconProvider::ProviderId, new WindowIconProvider());
|
||||
mEngine->addImageProvider(ThumbnailProvider::ProviderId, new ThumbnailProvider());
|
||||
|
||||
// Enable notifications.
|
||||
mNotifier = new Notifier(mEngine);
|
||||
|
|
@ -497,6 +627,14 @@ void App::initCore() {
|
|||
mAccountList->setInitialized(false);
|
||||
mAccountList->lUpdate(true);
|
||||
}
|
||||
// Update global unread Notifications when an account updates his unread Notifications
|
||||
connect(mAccountList.get(), &AccountList::unreadNotificationsChanged, this, [this]() {
|
||||
lDebug() << "unreadNotificationsChanged of AccountList";
|
||||
mCoreModelConnection->invokeToModel([this] {
|
||||
int n = mEventCountNotifier->getCurrentEventCount();
|
||||
mCoreModelConnection->invokeToCore([this, n] { mEventCountNotifier->notifyEventCount(n); });
|
||||
});
|
||||
});
|
||||
if (!mCallList) setCallList(CallList::create());
|
||||
else mCallList->lUpdate();
|
||||
if (!mSettings) {
|
||||
|
|
@ -522,7 +660,7 @@ void App::initCore() {
|
|||
setLocale(settings->getConfigLocale());
|
||||
setAutoStart(settings->getAutoStart());
|
||||
setQuitOnLastWindowClosed(settings->getExitOnClose());
|
||||
}
|
||||
}
|
||||
const QUrl url("qrc:/qt/qml/Linphone/view/Page/Window/Main/MainWindow.qml");
|
||||
QObject::connect(
|
||||
mEngine, &QQmlApplicationEngine::objectCreated, this,
|
||||
|
|
@ -534,18 +672,45 @@ void App::initCore() {
|
|||
}
|
||||
auto window = qobject_cast<QQuickWindow *>(obj);
|
||||
setMainWindow(window);
|
||||
#ifndef __APPLE__
|
||||
#if defined(__APPLE__)
|
||||
setMacOSDockActions();
|
||||
#else
|
||||
// Enable TrayIconSystem.
|
||||
if (!QSystemTrayIcon::isSystemTrayAvailable())
|
||||
qWarning("System tray not found on this system.");
|
||||
else setSysTrayIcon();
|
||||
#endif // ifndef __APPLE__
|
||||
#endif // if defined(__APPLE__)
|
||||
|
||||
static bool firstOpen = true;
|
||||
if (!firstOpen || !mParser->isSet("minimized")) {
|
||||
lDebug() << log().arg("Openning window");
|
||||
window->show();
|
||||
if (window) window->show();
|
||||
} else lInfo() << log().arg("Stay minimized");
|
||||
firstOpen = false;
|
||||
lInfo() << log().arg("Checking remote provisioning");
|
||||
if (mIsRestarting) {
|
||||
if (CoreModel::getInstance()->mConfigStatus == linphone::ConfiguringState::Failed) {
|
||||
QMetaObject::invokeMethod(thread(), [this]() {
|
||||
auto message = CoreModel::getInstance()->mConfigMessage;
|
||||
//: not reachable
|
||||
if (message.isEmpty()) message = tr("configuration_error_detail");
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
//: Error
|
||||
Utils::showInformationPopup(
|
||||
tr("info_popup_error_title"),
|
||||
//: Remote provisioning failed : %1
|
||||
tr("info_popup_configuration_failed_message").arg(message), false);
|
||||
});
|
||||
} else {
|
||||
mPossiblyLookForAddedAccount = true;
|
||||
}
|
||||
}
|
||||
checkForUpdate();
|
||||
mIsRestarting = false;
|
||||
|
||||
//---------------------------------------------------------------------------------------------
|
||||
lDebug() << log().arg("Creating KeyboardShortcuts");
|
||||
KeyboardShortcuts::create(getMainWindow());
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
|
|
@ -557,7 +722,6 @@ void App::initCore() {
|
|||
}
|
||||
|
||||
static inline bool installLocale(App &app, QTranslator &translator, const QLocale &locale) {
|
||||
auto appPath = QStandardPaths::ApplicationsLocation;
|
||||
bool ok = translator.load(locale.name(), Constants::LanguagePath);
|
||||
ok = ok && app.installTranslator(&translator);
|
||||
if (ok) QLocale::setDefault(locale);
|
||||
|
|
@ -565,7 +729,6 @@ static inline bool installLocale(App &app, QTranslator &translator, const QLocal
|
|||
}
|
||||
|
||||
void App::initLocale() {
|
||||
|
||||
// Try to use preferred locale.
|
||||
QString locale;
|
||||
|
||||
|
|
@ -573,28 +736,28 @@ void App::initLocale() {
|
|||
mLocale = QLocale(QLocale::English);
|
||||
if (!installLocale(*this, *mDefaultTranslatorCore, mLocale)) qFatal("Unable to install default translator.");
|
||||
|
||||
// if (installLocale(*this, *mTranslatorCore, getLocale())) {
|
||||
// qDebug() << "installed locale" << getLocale().name();
|
||||
// return;
|
||||
// }
|
||||
// if (installLocale(*this, *mTranslatorCore, getLocale())) {
|
||||
// qDebug() << "installed locale" << getLocale().name();
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Try to use system locale.
|
||||
// #ifdef Q_OS_MACOS
|
||||
// Use this workaround if there is still an issue about detecting wrong language from system on Mac. Qt doesn't use
|
||||
// the current system language on QLocale::system(). So we need to get it from user settings and overwrite its
|
||||
// Locale.
|
||||
// QSettings settings;
|
||||
// QString preferredLanguage = settings.value("AppleLanguages").toStringList().first();
|
||||
// QStringList qtLocale = QLocale::system().name().split('_');
|
||||
// if(qtLocale[0] != preferredLanguage){
|
||||
// qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " <<
|
||||
// preferredLanguage; qtLocale[0] = preferredLanguage;
|
||||
// }
|
||||
// QLocale sysLocale = QLocale(qtLocale.join('_'));
|
||||
// #else
|
||||
QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use the
|
||||
// QLocale::language (aka : translator.language != locale.language) on
|
||||
// Mac. #endif
|
||||
// Try to use system locale.
|
||||
// #ifdef Q_OS_MACOS
|
||||
// Use this workaround if there is still an issue about detecting wrong language from system on Mac. Qt doesn't
|
||||
// use the current system language on QLocale::system(). So we need to get it from user settings and overwrite
|
||||
// its Locale.
|
||||
// QSettings settings;
|
||||
// QString preferredLanguage = settings.value("AppleLanguages").toStringList().first();
|
||||
// QStringList qtLocale = QLocale::system().name().split('_');
|
||||
// if(qtLocale[0] != preferredLanguage){
|
||||
// qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " <<
|
||||
// preferredLanguage; qtLocale[0] = preferredLanguage;
|
||||
// }
|
||||
// QLocale sysLocale = QLocale(qtLocale.join('_'));
|
||||
// #else
|
||||
QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use
|
||||
// the QLocale::language (aka : translator.language !=
|
||||
// locale.language) on Mac. #endif
|
||||
if (installLocale(*this, *mTranslatorCore, sysLocale)) {
|
||||
qDebug() << "installed sys locale" << sysLocale.name();
|
||||
setLocale(sysLocale.name());
|
||||
|
|
@ -632,10 +795,18 @@ void App::initCppInterfaces() {
|
|||
"SettingsCpp", 1, 0, "SettingsCpp",
|
||||
[this](QQmlEngine *engine, QJSEngine *) -> QObject * { return mSettings.get(); });
|
||||
|
||||
qmlRegisterSingletonType<AccessibilityHelper>(
|
||||
"AccessibilityHelperCpp", 1, 0, "AccessibilityHelperCpp",
|
||||
[](QQmlEngine *engine, QJSEngine *) -> QObject * { return new AccessibilityHelper(engine); });
|
||||
|
||||
qmlRegisterType<FocusHelper>("CustomControls", 1, 0, "FocusHelper");
|
||||
|
||||
qmlRegisterType<DashRectangle>(Constants::MainQmlUri, 1, 0, "DashRectangle");
|
||||
qmlRegisterType<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
|
||||
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
|
||||
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
|
||||
|
||||
qmlRegisterType<ParticipantInfoProxy>(Constants::MainQmlUri, 1, 0, "ParticipantInfoProxy");
|
||||
qmlRegisterType<ParticipantProxy>(Constants::MainQmlUri, 1, 0, "ParticipantProxy");
|
||||
qmlRegisterType<ParticipantGui>(Constants::MainQmlUri, 1, 0, "ParticipantGui");
|
||||
qmlRegisterType<ConferenceInfoProxy>(Constants::MainQmlUri, 1, 0, "ConferenceInfoProxy");
|
||||
|
|
@ -652,6 +823,16 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterType<CallHistoryProxy>(Constants::MainQmlUri, 1, 0, "CallHistoryProxy");
|
||||
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
|
||||
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");
|
||||
qmlRegisterType<ChatList>(Constants::MainQmlUri, 1, 0, "ChatList");
|
||||
qmlRegisterType<ChatProxy>(Constants::MainQmlUri, 1, 0, "ChatProxy");
|
||||
qmlRegisterType<ChatGui>(Constants::MainQmlUri, 1, 0, "ChatGui");
|
||||
qmlRegisterType<EventLogGui>(Constants::MainQmlUri, 1, 0, "EventLogGui");
|
||||
qmlRegisterType<ChatMessageGui>(Constants::MainQmlUri, 1, 0, "ChatMessageGui");
|
||||
qmlRegisterType<EventLogList>(Constants::MainQmlUri, 1, 0, "EventLogList");
|
||||
qmlRegisterType<EventLogProxy>(Constants::MainQmlUri, 1, 0, "EventLogProxy");
|
||||
qmlRegisterType<ChatMessageContentProxy>(Constants::MainQmlUri, 1, 0, "ChatMessageContentProxy");
|
||||
qmlRegisterType<ChatMessageFileProxy>(Constants::MainQmlUri, 1, 0, "ChatMessageFileProxy");
|
||||
qmlRegisterType<ChatMessageContentGui>(Constants::MainQmlUri, 1, 0, "ChatMessageContentGui");
|
||||
qmlRegisterUncreatableType<ConferenceCore>(Constants::MainQmlUri, 1, 0, "ConferenceCore",
|
||||
QLatin1String("Uncreatable"));
|
||||
qmlRegisterType<ConferenceGui>(Constants::MainQmlUri, 1, 0, "ConferenceGui");
|
||||
|
|
@ -661,6 +842,11 @@ void App::initCppInterfaces() {
|
|||
qmlRegisterType<MagicSearchList>(Constants::MainQmlUri, 1, 0, "MagicSearchList");
|
||||
qmlRegisterType<CameraGui>(Constants::MainQmlUri, 1, 0, "CameraGui");
|
||||
qmlRegisterType<FPSCounter>(Constants::MainQmlUri, 1, 0, "FPSCounter");
|
||||
qmlRegisterType<EmojiModel>(Constants::MainQmlUri, 1, 0, "EmojiModel");
|
||||
qmlRegisterType<EmojiProxy>(Constants::MainQmlUri, 1, 0, "EmojiProxy");
|
||||
qmlRegisterType<ImdnStatusProxy>(Constants::MainQmlUri, 1, 0, "ImdnStatusProxy");
|
||||
qmlRegisterType<SoundPlayerGui>(Constants::MainQmlUri, 1, 0, "SoundPlayerGui");
|
||||
qmlRegisterType<RecorderGui>(Constants::MainQmlUri, 1, 0, "RecorderGui");
|
||||
|
||||
qmlRegisterType<TimeZoneProxy>(Constants::MainQmlUri, 1, 0, "TimeZoneProxy");
|
||||
|
||||
|
|
@ -701,6 +887,14 @@ void App::initFonts() {
|
|||
allFamilies << QFontDatabase::applicationFontFamilies(id);
|
||||
}
|
||||
}
|
||||
QDirIterator itEmojis(":/emoji/font/", QDirIterator::Subdirectories);
|
||||
while (itEmojis.hasNext()) {
|
||||
QString ttf = itEmojis.next();
|
||||
if (itEmojis.fileInfo().isFile()) {
|
||||
auto id = QFontDatabase::addApplicationFont(ttf);
|
||||
allFamilies << QFontDatabase::applicationFontFamilies(id);
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_LINUX
|
||||
QDirIterator itFonts(":/linux/font/", QDirIterator::Subdirectories);
|
||||
while (itFonts.hasNext()) {
|
||||
|
|
@ -748,8 +942,10 @@ void App::clean() {
|
|||
}
|
||||
void App::restart() {
|
||||
mCoreModelConnection->invokeToModel([this]() {
|
||||
FriendsManager::getInstance()->clearMaps();
|
||||
CoreModel::getInstance()->getCore()->stop();
|
||||
mCoreModelConnection->invokeToCore([this]() {
|
||||
mIsRestarting = true;
|
||||
closeCallsWindow();
|
||||
setMainWindow(nullptr);
|
||||
mEngine->clearComponentCache();
|
||||
|
|
@ -775,34 +971,37 @@ void App::createCommandParser() {
|
|||
//: "A free and open source SIP video-phone."
|
||||
mParser->setApplicationDescription(tr("application_description"));
|
||||
//: "Send an order to the application towards a command line"
|
||||
mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME), "[command]");
|
||||
mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME),
|
||||
"[command]");
|
||||
mParser->addOptions({
|
||||
//: "Show this help"
|
||||
{{"h", "help"}, tr("command_line_option_show_help")},
|
||||
//: "Show this help"
|
||||
{{"h", "help"}, tr("command_line_option_show_help")},
|
||||
|
||||
//{"cli-help", tr("commandLineOptionCliHelp").replace("%1", APPLICATION_NAME)},
|
||||
|
||||
//:"Show app version"
|
||||
{{"v", "version"}, tr("command_line_option_show_app_version")},
|
||||
//:"Show app version"
|
||||
{{"v", "version"}, tr("command_line_option_show_app_version")},
|
||||
|
||||
//{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME), tr("command_line_option_config_arg")},
|
||||
//{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME),
|
||||
// tr("command_line_option_config_arg")},
|
||||
|
||||
{"fetch-config",
|
||||
//: "Specify the linphone configuration file to be fetched. It will be merged with the current configuration."
|
||||
tr("command_line_option_config_to_fetch")
|
||||
.replace("%1", EXECUTABLE_NAME),
|
||||
//: "URL, path or file"
|
||||
tr("command_line_option_config_to_fetch_arg")},
|
||||
//: "Specify the linphone configuration file to be fetched. It will be merged with the current
|
||||
//: configuration."
|
||||
tr("command_line_option_config_to_fetch").replace("%1", EXECUTABLE_NAME),
|
||||
//: "URL, path or file"
|
||||
tr("command_line_option_config_to_fetch_arg")},
|
||||
|
||||
//{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME), tr("command_line_option_call_arg")},
|
||||
//{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME),
|
||||
// tr("command_line_option_call_arg")},
|
||||
|
||||
{"minimized", tr("command_line_option_minimized")},
|
||||
{"minimized", tr("command_line_option_minimized")},
|
||||
|
||||
//: "Log to stdout some debug information while running"
|
||||
{{"V", "verbose"}, tr("command_line_option_log_to_stdout")},
|
||||
//: "Log to stdout some debug information while running"
|
||||
{{"V", "verbose"}, tr("command_line_option_log_to_stdout")},
|
||||
|
||||
//: "Print only logs from the application"
|
||||
{"qt-logs-only", tr("command_line_option_print_app_logs_only")},
|
||||
//: "Print only logs from the application"
|
||||
{"qt-logs-only", tr("command_line_option_print_app_logs_only")},
|
||||
});
|
||||
}
|
||||
// Should be call only at first start
|
||||
|
|
@ -855,9 +1054,9 @@ bool App::notify(QObject *receiver, QEvent *event) {
|
|||
try {
|
||||
done = QApplication::notify(receiver, event);
|
||||
} catch (const std::exception &ex) {
|
||||
lCritical() << log().arg("Exception has been catch in notify: %1").arg(ex.what());
|
||||
lFatal() << log().arg("Exception has been catch in notify: %1").arg(ex.what());
|
||||
} catch (...) {
|
||||
lCritical() << log().arg("Generic exeption has been catch in notify");
|
||||
lFatal() << log().arg("Generic exeption has been catch in notify");
|
||||
}
|
||||
if (event->type() == QEvent::MouseButtonPress) {
|
||||
auto window = findParentWindow(receiver);
|
||||
|
|
@ -871,7 +1070,38 @@ bool App::notify(QObject *receiver, QEvent *event) {
|
|||
return done;
|
||||
}
|
||||
|
||||
QQuickWindow *App::getCallsWindow(QVariant callGui) {
|
||||
void App::handleAppActivity() {
|
||||
auto handle = [this](QSharedPointer<AccountCore> accountCore) {
|
||||
if (!accountCore) return;
|
||||
auto accountPresence = accountCore->getPresence();
|
||||
if ((mMainWindow && mMainWindow->isActive() || (mCallsWindow && mCallsWindow->isActive())) &&
|
||||
accountPresence == LinphoneEnums::Presence::Away)
|
||||
accountCore->lSetPresence(LinphoneEnums::Presence::Online);
|
||||
if (((!mMainWindow || !mMainWindow->isActive()) && (!mCallsWindow || !mCallsWindow->isActive())) &&
|
||||
accountPresence == LinphoneEnums::Presence::Online)
|
||||
accountCore->lSetPresence(LinphoneEnums::Presence::Away);
|
||||
};
|
||||
if (mAccountList) {
|
||||
for (auto &account : mAccountList->getSharedList<AccountCore>())
|
||||
handle(account);
|
||||
} else {
|
||||
connect(
|
||||
this, &App::accountsChanged, this,
|
||||
[this, &handle] {
|
||||
if (mAccountList) {
|
||||
for (auto &account : mAccountList->getSharedList<AccountCore>())
|
||||
handle(account);
|
||||
}
|
||||
},
|
||||
Qt::SingleShotConnection);
|
||||
}
|
||||
}
|
||||
|
||||
QQuickWindow *App::getCallsWindow() {
|
||||
return mCallsWindow;
|
||||
}
|
||||
|
||||
QQuickWindow *App::getOrCreateCallsWindow(QVariant callGui) {
|
||||
mustBeInMainThread(getClassName());
|
||||
if (!mCallsWindow) {
|
||||
const QUrl callUrl("qrc:/qt/qml/Linphone/view/Page/Window/Call/CallsWindow.qml");
|
||||
|
|
@ -906,6 +1136,7 @@ QQuickWindow *App::getCallsWindow(QVariant callGui) {
|
|||
}
|
||||
// window->setParent(mMainWindow);
|
||||
mCallsWindow = window;
|
||||
connect(mCallsWindow, &QQuickWindow::activeChanged, this, &App::handleAppActivity);
|
||||
}
|
||||
if (!callGui.isNull() && callGui.isValid()) mCallsWindow->setProperty("call", callGui);
|
||||
return mCallsWindow;
|
||||
|
|
@ -916,7 +1147,7 @@ void App::setCallsWindowProperty(const char *id, QVariant property) {
|
|||
}
|
||||
|
||||
void App::closeCallsWindow() {
|
||||
if (mCallsWindow) {
|
||||
if (mCallsWindow && mCallList && !mCallList->getHaveCall()) {
|
||||
mCallsWindow->close();
|
||||
mCallsWindow->deleteLater();
|
||||
mCallsWindow = nullptr;
|
||||
|
|
@ -928,8 +1159,11 @@ QQuickWindow *App::getMainWindow() const {
|
|||
}
|
||||
|
||||
void App::setMainWindow(QQuickWindow *data) {
|
||||
if (mMainWindow) disconnect(mMainWindow, &QQuickWindow::activeChanged, this, nullptr);
|
||||
if (mMainWindow != data) {
|
||||
mMainWindow = data;
|
||||
connect(mMainWindow, &QQuickWindow::activeChanged, this, &App::handleAppActivity);
|
||||
handleAppActivity();
|
||||
emit mainWindowChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -1137,6 +1371,16 @@ bool App::event(QEvent *event) {
|
|||
} else if (event->type() == QEvent::ApplicationStateChange) {
|
||||
auto state = static_cast<QApplicationStateChangeEvent *>(event);
|
||||
if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getLastActiveWindow());
|
||||
} else if (event->type() == QEvent::ApplicationActivate) {
|
||||
for (int i = 0; i < getAccountList()->rowCount(); ++i) {
|
||||
auto accountCore = getAccountList()->getAt<AccountCore>(i);
|
||||
emit accountCore->lSetPresence(LinphoneEnums::Presence::Online, false, false);
|
||||
}
|
||||
} else if (event->type() == QEvent::ApplicationDeactivate) {
|
||||
for (int i = 0; i < getAccountList()->rowCount(); ++i) {
|
||||
auto accountCore = getAccountList()->getAt<AccountCore>(i);
|
||||
emit accountCore->lSetPresence(LinphoneEnums::Presence::Away, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
return SingleApplication::event(event);
|
||||
|
|
@ -1149,6 +1393,7 @@ bool App::event(QEvent *event) {
|
|||
//-----------------------------------------------------------
|
||||
|
||||
void App::setSysTrayIcon() {
|
||||
qDebug() << "setSysTrayIcon";
|
||||
QQuickWindow *root = getMainWindow();
|
||||
QSystemTrayIcon *systemTrayIcon =
|
||||
(mSystemTrayIcon ? mSystemTrayIcon
|
||||
|
|
@ -1164,7 +1409,7 @@ void App::setSysTrayIcon() {
|
|||
//: "Afficher"
|
||||
restoreAction->setText(visible ? tr("hide_action") : tr("show_action"));
|
||||
};
|
||||
setRestoreActionText(root->isVisible());
|
||||
setRestoreActionText(root ? root->isVisible() : false);
|
||||
connect(root, &QWindow::visibleChanged, restoreAction, setRestoreActionText);
|
||||
|
||||
root->connect(restoreAction, &QAction::triggered, this, [this, restoreAction](bool checked) {
|
||||
|
|
@ -1180,6 +1425,9 @@ void App::setSysTrayIcon() {
|
|||
QAction *quitAction = new QAction(tr("quit_action"), root);
|
||||
root->connect(quitAction, &QAction::triggered, this, &App::quit);
|
||||
|
||||
//: "Mark all as read"
|
||||
QAction *markAllReadAction = createMarkAsReadAction(root);
|
||||
|
||||
// trayIcon: Left click actions.
|
||||
QMenu *menu = mSystemTrayIcon ? mSystemTrayIcon->contextMenu() : new QMenu();
|
||||
menu->clear();
|
||||
|
|
@ -1189,6 +1437,13 @@ void App::setSysTrayIcon() {
|
|||
menu->addAction(restoreAction);
|
||||
menu->addSeparator();
|
||||
}
|
||||
menu->addAction(markAllReadAction);
|
||||
//: Check for update
|
||||
if (mSettings->isCheckForUpdateAvailable()) {
|
||||
QAction *checkForUpdateAction = new QAction(tr("check_for_update"), root);
|
||||
root->connect(checkForUpdateAction, &QAction::triggered, this, [this] { checkForUpdate(true); });
|
||||
menu->addAction(checkForUpdateAction);
|
||||
}
|
||||
menu->addAction(quitAction);
|
||||
if (!mSystemTrayIcon) {
|
||||
systemTrayIcon->setContextMenu(menu); // This is a Qt bug. We cannot call setContextMenu more than once. So
|
||||
|
|
@ -1208,6 +1463,24 @@ void App::setSysTrayIcon() {
|
|||
if (!QSystemTrayIcon::isSystemTrayAvailable()) qInfo() << "System tray is not available";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// MacOS dock menu actions
|
||||
//-----------------------------------------------------------
|
||||
|
||||
#ifdef __APPLE__
|
||||
/**
|
||||
* Set more actions to the MacOS Dock actions
|
||||
* WARNING: call this function only on macOS
|
||||
*/
|
||||
void App::setMacOSDockActions() {
|
||||
QMenu *menu = new QMenu();
|
||||
QQuickWindow *root = getMainWindow();
|
||||
QAction *markAllReadAction = createMarkAsReadAction(root);
|
||||
menu->addAction(markAllReadAction);
|
||||
menu->setAsDockMenu();
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// Locale TODO - App only in French now.
|
||||
//-----------------------------------------------------------
|
||||
|
|
@ -1249,3 +1522,48 @@ QString App::getSdkVersion() {
|
|||
return tr('unknown');
|
||||
#endif
|
||||
}
|
||||
|
||||
QString App::getQtVersion() const {
|
||||
return qVersion();
|
||||
}
|
||||
|
||||
void App::checkForUpdate(bool requestedByUser) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (CoreModel::getInstance() && mCoreModelConnection) {
|
||||
mCoreModelConnection->invokeToModel([this, requestedByUser] {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
CoreModel::getInstance()->checkForUpdate(Utils::appStringToCoreString(applicationVersion()),
|
||||
requestedByUser);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ChatGui *App::getCurrentChat() const {
|
||||
return mCurrentChat;
|
||||
}
|
||||
|
||||
void App::setCurrentChat(ChatGui *chat) {
|
||||
if (chat != mCurrentChat) {
|
||||
mCurrentChat = chat;
|
||||
emit currentChatChanged();
|
||||
}
|
||||
}
|
||||
|
||||
float App::getScreenRatio() const {
|
||||
return mScreenRatio;
|
||||
}
|
||||
|
||||
void App::setScreenRatio(float ratio) {
|
||||
mScreenRatio = ratio;
|
||||
}
|
||||
|
||||
QAction *App::createMarkAsReadAction(QQuickWindow *window) {
|
||||
QAction *markAllReadAction = new QAction(tr("mark_all_read_action"), window);
|
||||
window->connect(markAllReadAction, &QAction::triggered, this, [this] {
|
||||
lDebug() << "Mark all as read";
|
||||
emit mAccountList->lResetMissedCalls();
|
||||
emit mAccountList->lResetUnreadMessages();
|
||||
mCoreModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
|
||||
});
|
||||
return markAllReadAction;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,12 +18,14 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QAction>
|
||||
#include <QCommandLineParser>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "core/account/AccountProxy.hpp"
|
||||
#include "core/call/CallProxy.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "core/singleapplication/singleapplication.h"
|
||||
#include "model/cli/CliModel.hpp"
|
||||
|
|
@ -31,6 +33,7 @@
|
|||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
class CallGui;
|
||||
class ChatGui;
|
||||
class Thread;
|
||||
class Notifier;
|
||||
class QQuickWindow;
|
||||
|
|
@ -43,17 +46,22 @@ class App : public SingleApplication, public AbstractObject {
|
|||
Q_PROPERTY(AccountList *accounts READ getAccounts NOTIFY accountsChanged)
|
||||
Q_PROPERTY(CallList *calls READ getCalls NOTIFY callsChanged)
|
||||
Q_PROPERTY(QString shortApplicationVersion READ getShortApplicationVersion CONSTANT)
|
||||
Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT)
|
||||
Q_PROPERTY(QString gitBranchName READ getGitBranchName CONSTANT)
|
||||
Q_PROPERTY(QString sdkVersion READ getSdkVersion CONSTANT)
|
||||
Q_PROPERTY(ChatGui *currentChat READ getCurrentChat WRITE setCurrentChat NOTIFY currentChatChanged)
|
||||
|
||||
public:
|
||||
App(int &argc, char *argv[]);
|
||||
~App();
|
||||
void setSelf(QSharedPointer<App>(me));
|
||||
static App *getInstance();
|
||||
static QThread *getLinphoneThread();
|
||||
static Thread *getLinphoneThread();
|
||||
Notifier *getNotifier() const;
|
||||
|
||||
EventCountNotifier *getEventCountNotifier();
|
||||
int getEventCount() const;
|
||||
|
||||
// App::postModelAsync(<lambda>) => run lambda in model thread and continue.
|
||||
// App::postModelSync(<lambda>) => run lambda in current thread and block connection.
|
||||
template <typename Func, typename... Args>
|
||||
|
|
@ -119,6 +127,10 @@ public:
|
|||
void restart();
|
||||
bool autoStartEnabled();
|
||||
void setSysTrayIcon();
|
||||
QSystemTrayIcon *getSystemTrayIcon() const {
|
||||
return mSystemTrayIcon;
|
||||
}
|
||||
void updateSysTrayCount(int n);
|
||||
QLocale getLocale();
|
||||
|
||||
void onLoggerInitialized();
|
||||
|
|
@ -127,7 +139,9 @@ public:
|
|||
bool getCoreStarted() const;
|
||||
void setCoreStarted(bool started);
|
||||
|
||||
QQuickWindow *getCallsWindow(QVariant callGui = QVariant());
|
||||
QQuickWindow *getCallsWindow();
|
||||
Q_INVOKABLE void handleAppActivity();
|
||||
QQuickWindow *getOrCreateCallsWindow(QVariant callGui = QVariant());
|
||||
void setCallsWindowProperty(const char *id, QVariant property);
|
||||
void closeCallsWindow();
|
||||
|
||||
|
|
@ -153,6 +167,14 @@ public:
|
|||
QString getShortApplicationVersion();
|
||||
QString getGitBranchName();
|
||||
QString getSdkVersion();
|
||||
QString getQtVersion() const;
|
||||
|
||||
Q_INVOKABLE void checkForUpdate(bool requestedByUser = false);
|
||||
ChatGui *getCurrentChat() const;
|
||||
void setCurrentChat(ChatGui *chat);
|
||||
|
||||
float getScreenRatio() const;
|
||||
Q_INVOKABLE void setScreenRatio(float ratio);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
Q_INVOKABLE void exportDesktopFile();
|
||||
|
|
@ -172,22 +194,30 @@ signals:
|
|||
void mainWindowChanged();
|
||||
void coreStartedChanged(bool coreStarted);
|
||||
void accountsChanged();
|
||||
void defaultAccountChanged();
|
||||
void callsChanged();
|
||||
void currentDateChanged();
|
||||
void currentChatChanged();
|
||||
// void executeCommand(QString command);
|
||||
|
||||
private:
|
||||
void createCommandParser();
|
||||
QAction *createMarkAsReadAction(QQuickWindow *window);
|
||||
void setMacOSDockActions(); // Should only be called on MacOS
|
||||
void setAutoStart(bool enabled);
|
||||
void setLocale(QString configLocale);
|
||||
|
||||
QCommandLineParser *mParser = nullptr;
|
||||
Thread *mLinphoneThread = nullptr;
|
||||
Notifier *mNotifier = nullptr;
|
||||
EventCountNotifier *mEventCountNotifier = nullptr;
|
||||
QSystemTrayIcon *mSystemTrayIcon = nullptr;
|
||||
QQuickWindow *mMainWindow = nullptr;
|
||||
QQuickWindow *mCallsWindow = nullptr;
|
||||
QQuickWindow *mLastActiveWindow = nullptr;
|
||||
// Holds the current chat displayed in the view
|
||||
// to know if we need to display the notification
|
||||
ChatGui *mCurrentChat = nullptr;
|
||||
QSharedPointer<SettingsCore> mSettings;
|
||||
QSharedPointer<AccountList> mAccountList;
|
||||
QSharedPointer<CallList> mCallList;
|
||||
|
|
@ -195,11 +225,14 @@ private:
|
|||
QSharedPointer<SafeConnection<App, CliModel>> mCliModelConnection;
|
||||
bool mAutoStart = false;
|
||||
bool mCoreStarted = false;
|
||||
bool mIsRestarting = false;
|
||||
bool mPossiblyLookForAddedAccount = false;
|
||||
QLocale mLocale = QLocale::system();
|
||||
DefaultTranslatorCore *mTranslatorCore = nullptr;
|
||||
DefaultTranslatorCore *mDefaultTranslatorCore = nullptr;
|
||||
QTimer mDateUpdateTimer;
|
||||
QDate mCurrentDate;
|
||||
float mScreenRatio = 1;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -19,6 +19,28 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/camera/CameraGui.cpp
|
||||
core/camera/CameraDummy.cpp
|
||||
core/camera/PreviewManager.cpp
|
||||
core/chat/ChatCore.cpp
|
||||
core/chat/ChatGui.cpp
|
||||
core/chat/ChatList.cpp
|
||||
core/chat/ChatProxy.cpp
|
||||
core/chat/message/ChatMessageCore.cpp
|
||||
core/chat/message/ChatMessageGui.cpp
|
||||
core/chat/message/EventLogCore.cpp
|
||||
core/chat/message/EventLogGui.cpp
|
||||
core/chat/message/EventLogList.cpp
|
||||
core/chat/message/EventLogProxy.cpp
|
||||
core/chat/message/content/ChatMessageContentCore.cpp
|
||||
core/chat/message/content/ChatMessageContentGui.cpp
|
||||
core/chat/message/content/ChatMessageContentList.cpp
|
||||
core/chat/message/content/ChatMessageContentProxy.cpp
|
||||
core/chat/files/ChatMessageFileList.cpp
|
||||
core/chat/files/ChatMessageFileProxy.cpp
|
||||
core/chat/message/imdn/ImdnStatusList.cpp
|
||||
core/chat/message/imdn/ImdnStatusProxy.cpp
|
||||
core/emoji/EmojiList.cpp
|
||||
core/emoji/EmojiModel.cpp
|
||||
core/emoji/EmojiProxy.cpp
|
||||
core/event-count-notifier/AbstractEventCountNotifier.cpp
|
||||
core/fps-counter/FPSCounter.cpp
|
||||
core/friend/FriendCore.cpp
|
||||
core/friend/FriendGui.cpp
|
||||
|
|
@ -64,10 +86,18 @@ list(APPEND _LINPHONEAPP_SOURCES
|
|||
core/participant/ParticipantDeviceProxy.cpp
|
||||
core/participant/ParticipantList.cpp
|
||||
core/participant/ParticipantProxy.cpp
|
||||
core/participant/ParticipantInfoList.cpp
|
||||
core/participant/ParticipantInfoProxy.cpp
|
||||
|
||||
core/screen/ScreenList.cpp
|
||||
core/screen/ScreenProxy.cpp
|
||||
|
||||
core/sound-player/SoundPlayerCore.cpp
|
||||
core/sound-player/SoundPlayerGui.cpp
|
||||
|
||||
core/recorder/RecorderCore.cpp
|
||||
core/recorder/RecorderGui.cpp
|
||||
|
||||
core/videoSource/VideoSourceDescriptorCore.cpp
|
||||
core/videoSource/VideoSourceDescriptorGui.cpp
|
||||
|
||||
|
|
@ -99,5 +129,9 @@ else() # Use QDBus for Linux
|
|||
core/singleapplication/SingleApplicationDBusPrivate.hpp
|
||||
core/singleapplication/SingleApplicationDBus.cpp)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
list(APPEND _LINPHONEAPP_SOURCES core/event-count-notifier/EventCountNotifierMacOs.m)
|
||||
else()
|
||||
list(APPEND _LINPHONEAPP_SOURCES core/event-count-notifier/EventCountNotifierSystemTrayIcon.cpp)
|
||||
endif()
|
||||
set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)
|
||||
|
|
|
|||
|
|
@ -43,18 +43,18 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
|
|||
auto address = account->getContactAddress();
|
||||
mContactAddress = address ? Utils::coreStringToAppString(account->getContactAddress()->asStringUriOnly()) : "";
|
||||
auto params = account->getParams()->clone();
|
||||
auto identityAddress = params->getIdentityAddress()->clone();
|
||||
auto identityAddress = params->getIdentityAddress();
|
||||
mIdentityAddress = identityAddress ? Utils::coreStringToAppString(identityAddress->asStringUriOnly()) : "";
|
||||
mPictureUri = Utils::coreStringToAppString(params->getPictureUri());
|
||||
mRegistrationState = LinphoneEnums::fromLinphone(account->getState());
|
||||
mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account;
|
||||
// mUnreadNotifications = account->getUnreadChatMessageCount() + account->getMissedCallsCount(); // TODO
|
||||
mUnreadNotifications = account->getMissedCallsCount();
|
||||
mUnreadNotifications = account->getMissedCallsCount() + account->getUnreadChatMessageCount();
|
||||
mDisplayName = Utils::coreStringToAppString(identityAddress->getDisplayName());
|
||||
if (mDisplayName.isEmpty()) {
|
||||
mDisplayName = ToolModel::getDisplayName(identityAddress);
|
||||
identityAddress->setDisplayName(Utils::appStringToCoreString(mDisplayName));
|
||||
params->setIdentityAddress(identityAddress);
|
||||
auto copyAddress = identityAddress->clone();
|
||||
copyAddress->setDisplayName(Utils::appStringToCoreString(mDisplayName));
|
||||
params->setIdentityAddress(copyAddress);
|
||||
account->setParams(params);
|
||||
}
|
||||
mRegisterEnabled = params->registerEnabled();
|
||||
|
|
@ -65,9 +65,11 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
|
|||
<< "TLS"
|
||||
<< "DTLS";
|
||||
mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(params->getTransport()));
|
||||
mServerAddress =
|
||||
mRegistrarUri =
|
||||
params->getServerAddress() ? Utils::coreStringToAppString(params->getServerAddress()->asString()) : "";
|
||||
mOutboundProxyEnabled = params->outboundProxyEnabled();
|
||||
auto routesAddresses = params->getRoutesAddresses();
|
||||
mOutboundProxyUri =
|
||||
routesAddresses.empty() ? "" : Utils::coreStringToAppString(routesAddresses.front()->asString());
|
||||
auto policy = params->getNatPolicy() ? params->getNatPolicy() : account->getCore()->createNatPolicy();
|
||||
mStunServer = Utils::coreStringToAppString(policy->getStunServer());
|
||||
mIceEnabled = policy->iceEnabled();
|
||||
|
|
@ -82,10 +84,19 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
|
|||
? Utils::coreStringToAppString(params->getAudioVideoConferenceFactoryAddress()->asString())
|
||||
: "";
|
||||
mLimeServerUrl = Utils::coreStringToAppString(params->getLimeServerUrl());
|
||||
mCcmpServerUrl = Utils::coreStringToAppString(params->getCcmpServerUrl());
|
||||
|
||||
// Add listener
|
||||
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK
|
||||
mAccountModel->setSelf(mAccountModel);
|
||||
mExplicitPresence = LinphoneEnums::fromString(
|
||||
Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getConfig()->getString(
|
||||
ToolModel::configAccountSection(account), "explicit_presence", "")));
|
||||
mPresenceNote = Utils::coreStringToAppString(CoreModel::getInstance()->getCore()->getConfig()->getString(
|
||||
ToolModel::configAccountSection(account), "presence_note", ""));
|
||||
mMaxPresenceNoteSize = CoreModel::getInstance()->getCore()->getConfig()->getInt(
|
||||
ToolModel::configAccountSection(account), "max_presence_note_size", 140);
|
||||
mPresence = mAccountModel->getPresence();
|
||||
mNotificationsAllowed = mAccountModel->getNotificationsAllowed();
|
||||
mDialPlan = Utils::createDialPlanVariant("", " ");
|
||||
mDialPlans << mDialPlan;
|
||||
|
|
@ -128,8 +139,8 @@ AccountCore::AccountCore(const AccountCore &accountCore) {
|
|||
mVoicemailAddress = accountCore.mVoicemailAddress;
|
||||
mTransport = accountCore.mTransport;
|
||||
mTransports = accountCore.mTransports;
|
||||
mServerAddress = accountCore.mServerAddress;
|
||||
mOutboundProxyEnabled = accountCore.mOutboundProxyEnabled;
|
||||
mRegistrarUri = accountCore.mRegistrarUri;
|
||||
mOutboundProxyUri = accountCore.mOutboundProxyUri;
|
||||
mStunServer = accountCore.mStunServer;
|
||||
mIceEnabled = accountCore.mIceEnabled;
|
||||
mAvpfEnabled = accountCore.mAvpfEnabled;
|
||||
|
|
@ -138,6 +149,7 @@ AccountCore::AccountCore(const AccountCore &accountCore) {
|
|||
mConferenceFactoryAddress = accountCore.mConferenceFactoryAddress;
|
||||
mAudioVideoConferenceFactoryAddress = accountCore.mAudioVideoConferenceFactoryAddress;
|
||||
mLimeServerUrl = accountCore.mLimeServerUrl;
|
||||
mCcmpServerUrl = accountCore.mCcmpServerUrl;
|
||||
}
|
||||
|
||||
void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
||||
|
|
@ -148,6 +160,12 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->invokeToCore(
|
||||
[this, account, state, message]() { onRegistrationStateChanged(account, state, message); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&AccountModel::conferenceInformationUpdated,
|
||||
[this](const std::shared_ptr<linphone::Account> &account,
|
||||
const std::list<std::shared_ptr<linphone::ConferenceInfo>> &infos) {
|
||||
mAccountModelConnection->invokeToCore([this]() { emit conferenceInformationUpdated(); });
|
||||
});
|
||||
// From Model
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::defaultAccountChanged, [this](bool isDefault) {
|
||||
mAccountModelConnection->invokeToCore([this, isDefault]() { onDefaultAccountChanged(isDefault); });
|
||||
|
|
@ -187,11 +205,11 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->invokeToCore(
|
||||
[this, value]() { onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::serverAddressChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onServerAddressChanged(value); });
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::registrarUriChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onRegistrarUriChanged(value); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyEnabledChanged, [this](bool value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onOutboundProxyEnabledChanged(value); });
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyUriChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onOutboundProxyUriChanged(value); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::stunServerChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onStunServerChanged(value); });
|
||||
|
|
@ -220,9 +238,23 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onLimeServerUrlChanged(value); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::ccmpServerUrlChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { onCcmpServerUrlChanged(value); });
|
||||
});
|
||||
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&AccountModel::removed, [this]() { mAccountModelConnection->invokeToCore([this]() { emit removed(); }); });
|
||||
|
||||
mAccountModelConnection->makeConnectToModel(
|
||||
&AccountModel::presenceChanged, [this](LinphoneEnums::Presence presence, bool userInitiated) {
|
||||
mAccountModelConnection->invokeToCore([this, presence, userInitiated]() {
|
||||
if (userInitiated) mExplicitPresence = presence;
|
||||
else mExplicitPresence = LinphoneEnums::Presence::Undefined;
|
||||
mPresence = presence;
|
||||
emit presenceChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// From GUI
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) {
|
||||
mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); });
|
||||
|
|
@ -233,19 +265,17 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->makeConnectToCore(&AccountCore::lResetMissedCalls, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mAccountModel->resetMissedCallsCount(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::lResetUnreadMessages, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() {
|
||||
auto chatRooms = mAccountModel->getChatRooms();
|
||||
for (auto const &chatRoom : chatRooms) {
|
||||
chatRoom->markAsRead();
|
||||
}
|
||||
});
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::lRefreshNotifications, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { mAccountModel->refreshUnreadNotifications(); });
|
||||
});
|
||||
mCoreModelConnection = SafeConnection<AccountCore, CoreModel>::create(me, CoreModel::getInstance());
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadCallNotificationsChanged, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadMessageNotificationsChanged, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::unreadNotificationsChanged, [this]() {
|
||||
mAccountModelConnection->invokeToModel([this]() { CoreModel::getInstance()->unreadNotificationsChanged(); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetDisplayName, [this](QString displayName) {
|
||||
mAccountModelConnection->invokeToModel([this, displayName]() { mAccountModel->setDisplayName(displayName); });
|
||||
});
|
||||
|
|
@ -260,6 +290,13 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) {
|
||||
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setNotificationsAllowed(value); });
|
||||
});
|
||||
mAccountModelConnection->makeConnectToCore(
|
||||
&AccountCore::lSetPresence, [this](LinphoneEnums::Presence presence, bool userInitiated, bool resetToAuto) {
|
||||
mAccountModelConnection->invokeToModel(
|
||||
[this, presence, userInitiated, resetToAuto, presenceNote = mPresenceNote]() {
|
||||
mAccountModel->setPresence(presence, userInitiated, resetToAuto, presenceNote);
|
||||
});
|
||||
});
|
||||
|
||||
DEFINE_CORE_GET_CONNECT(mAccountModelConnection, AccountCore, AccountModel, mAccountModel, int, voicemailCount,
|
||||
VoicemailCount)
|
||||
|
|
@ -269,6 +306,14 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
|
|||
mAccountModelConnection->makeConnectToModel(&AccountModel::voicemailAddressChanged, [this](QString value) {
|
||||
mAccountModelConnection->invokeToCore([this, value]() { setVoicemailAddress(value); });
|
||||
});
|
||||
|
||||
mCoreModelConnection = SafeConnection<AccountCore, CoreModel>::create(me, CoreModel::getInstance());
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::messageReadInChatRoom,
|
||||
[this] { mAccountModel->refreshUnreadNotifications(); });
|
||||
|
||||
mAccountModelConnection->makeConnectToModel(&AccountModel::setValueFailed, [this](const QString &errorMessage) {
|
||||
mAccountModelConnection->invokeToCore([this, errorMessage]() { emit setValueFailed(errorMessage); });
|
||||
});
|
||||
}
|
||||
|
||||
void AccountCore::reset(const AccountCore &accountCore) {
|
||||
|
|
@ -278,8 +323,8 @@ void AccountCore::reset(const AccountCore &accountCore) {
|
|||
setMwiServerAddress(accountCore.mMwiServerAddress);
|
||||
setVoicemailAddress(accountCore.mVoicemailAddress);
|
||||
setTransport(accountCore.mTransport);
|
||||
setServerAddress(accountCore.mServerAddress);
|
||||
setOutboundProxyEnabled(accountCore.mOutboundProxyEnabled);
|
||||
setRegistrarUri(accountCore.mRegistrarUri);
|
||||
setOutboundProxyUri(accountCore.mOutboundProxyUri);
|
||||
setStunServer(accountCore.mStunServer);
|
||||
setIceEnabled(accountCore.mIceEnabled);
|
||||
setAvpfEnabled(accountCore.mAvpfEnabled);
|
||||
|
|
@ -288,6 +333,7 @@ void AccountCore::reset(const AccountCore &accountCore) {
|
|||
setConferenceFactoryAddress(accountCore.mConferenceFactoryAddress);
|
||||
setAudioVideoConferenceFactoryAddress(accountCore.mAudioVideoConferenceFactoryAddress);
|
||||
setLimeServerUrl(accountCore.mLimeServerUrl);
|
||||
setCcmpServerUrl(accountCore.mCcmpServerUrl);
|
||||
}
|
||||
|
||||
const std::shared_ptr<AccountModel> &AccountCore::getModel() const {
|
||||
|
|
@ -347,8 +393,8 @@ void AccountCore::setUnreadMessageNotifications(int unread) {
|
|||
void AccountCore::onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account,
|
||||
linphone::RegistrationState state,
|
||||
const std::string &message) {
|
||||
lDebug() << log().arg(Q_FUNC_INFO) << (int)state;
|
||||
mRegistrationState = LinphoneEnums::fromLinphone(state);
|
||||
qDebug() << log().arg(Q_FUNC_INFO) << mRegistrationState;
|
||||
emit registrationStateChanged(Utils::coreStringToAppString(message));
|
||||
}
|
||||
|
||||
|
|
@ -423,6 +469,30 @@ QString AccountCore::getHumanReadableRegistrationState() const {
|
|||
}
|
||||
}
|
||||
|
||||
QColor AccountCore::getRegistrationColor() const {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
switch (mRegistrationState) {
|
||||
case LinphoneEnums::RegistrationState::Ok:
|
||||
return Utils::getDefaultStyleColor("success_500_main");
|
||||
case LinphoneEnums::RegistrationState::Refreshing:
|
||||
return Utils::getDefaultStyleColor("main2_500_main");
|
||||
case LinphoneEnums::RegistrationState::Progress:
|
||||
return Utils::getDefaultStyleColor("main2_500_main");
|
||||
case LinphoneEnums::RegistrationState::Failed:
|
||||
return Utils::getDefaultStyleColor("danger_500_main");
|
||||
case LinphoneEnums::RegistrationState::None:
|
||||
case LinphoneEnums::RegistrationState::Cleared:
|
||||
return Utils::getDefaultStyleColor("warning_600");
|
||||
default:
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
|
||||
QUrl AccountCore::getRegistrationIcon() const {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
return Utils::getRegistrationStateIcon(mRegistrationState);
|
||||
}
|
||||
|
||||
QString AccountCore::getHumanReadableRegistrationStateExplained() const {
|
||||
switch (mRegistrationState) {
|
||||
case LinphoneEnums::RegistrationState::Ok:
|
||||
|
|
@ -471,12 +541,12 @@ QString AccountCore::getTransport() {
|
|||
return mTransport;
|
||||
}
|
||||
|
||||
QString AccountCore::getServerAddress() {
|
||||
return mServerAddress;
|
||||
QString AccountCore::getRegistrarUri() {
|
||||
return mRegistrarUri;
|
||||
}
|
||||
|
||||
bool AccountCore::getOutboundProxyEnabled() {
|
||||
return mOutboundProxyEnabled;
|
||||
QString AccountCore::getOutboundProxyUri() {
|
||||
return mOutboundProxyUri;
|
||||
}
|
||||
|
||||
QString AccountCore::getStunServer() {
|
||||
|
|
@ -511,6 +581,10 @@ QString AccountCore::getLimeServerUrl() {
|
|||
return mLimeServerUrl;
|
||||
}
|
||||
|
||||
QString AccountCore::getCcmpServerUrl() {
|
||||
return mCcmpServerUrl;
|
||||
}
|
||||
|
||||
void AccountCore::setMwiServerAddress(QString value) {
|
||||
if (mMwiServerAddress != value) {
|
||||
mMwiServerAddress = value;
|
||||
|
|
@ -529,32 +603,24 @@ void AccountCore::setVoicemailAddress(QString value) {
|
|||
|
||||
void AccountCore::setTransport(QString value) {
|
||||
if (mTransport != value) {
|
||||
mAccountModelConnection->invokeToModel([this, value] {
|
||||
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
|
||||
LinphoneEnums::TransportType transport;
|
||||
LinphoneEnums::fromString(value, &transport);
|
||||
mAccountModel->setTransport(LinphoneEnums::toLinphone(transport), false);
|
||||
});
|
||||
mTransport = value;
|
||||
emit transportChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountCore::setServerAddress(QString value) {
|
||||
if (mServerAddress != value) {
|
||||
mAccountModelConnection->invokeToModel([this, value, transportString = mTransport] {
|
||||
LinphoneEnums::TransportType transport;
|
||||
LinphoneEnums::fromString(transportString, &transport);
|
||||
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
|
||||
mAccountModel->setServerAddress(value, LinphoneEnums::toLinphone(transport), false);
|
||||
});
|
||||
void AccountCore::setRegistrarUri(QString value) {
|
||||
if (mRegistrarUri != value) {
|
||||
mRegistrarUri = value;
|
||||
emit registrarUriChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
void AccountCore::setOutboundProxyEnabled(bool value) {
|
||||
if (mOutboundProxyEnabled != value) {
|
||||
mOutboundProxyEnabled = value;
|
||||
emit outboundProxyEnabledChanged();
|
||||
void AccountCore::setOutboundProxyUri(QString value) {
|
||||
if (mOutboundProxyUri != value) {
|
||||
mOutboundProxyUri = value;
|
||||
emit outboundProxyUriChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -623,6 +689,14 @@ void AccountCore::setLimeServerUrl(QString value) {
|
|||
}
|
||||
}
|
||||
|
||||
void AccountCore::setCcmpServerUrl(QString value) {
|
||||
if (mCcmpServerUrl != value) {
|
||||
mCcmpServerUrl = value;
|
||||
emit ccmpServerUrlChanged();
|
||||
setIsSaved(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool AccountCore::isSaved() const {
|
||||
return mIsSaved;
|
||||
}
|
||||
|
|
@ -662,19 +736,20 @@ void AccountCore::onTransportChanged(QString value) {
|
|||
}
|
||||
}
|
||||
|
||||
void AccountCore::onServerAddressChanged(QString value) {
|
||||
if (value != mServerAddress) {
|
||||
mServerAddress = value;
|
||||
emit serverAddressChanged();
|
||||
void AccountCore::onRegistrarUriChanged(QString value) {
|
||||
if (value != mRegistrarUri) {
|
||||
mRegistrarUri = value;
|
||||
emit registrarUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountCore::onOutboundProxyEnabledChanged(bool value) {
|
||||
if (value != mOutboundProxyEnabled) {
|
||||
mOutboundProxyEnabled = value;
|
||||
emit outboundProxyEnabledChanged();
|
||||
void AccountCore::onOutboundProxyUriChanged(QString value) {
|
||||
if (value != mOutboundProxyUri) {
|
||||
mOutboundProxyUri = value;
|
||||
emit outboundProxyUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountCore::onStunServerChanged(QString value) {
|
||||
if (value != mStunServer) {
|
||||
mStunServer = value;
|
||||
|
|
@ -734,14 +809,21 @@ void AccountCore::onLimeServerUrlChanged(QString value) {
|
|||
}
|
||||
}
|
||||
|
||||
void AccountCore::onCcmpServerUrlChanged(QString value) {
|
||||
if (value != mCcmpServerUrl) {
|
||||
mCcmpServerUrl = value;
|
||||
emit ccmpServerUrlChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
|
||||
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
|
||||
model->setMwiServerAddress(mMwiServerAddress);
|
||||
LinphoneEnums::TransportType transport;
|
||||
LinphoneEnums::fromString(mTransport, &transport);
|
||||
model->setTransport(LinphoneEnums::toLinphone(transport), true);
|
||||
model->setServerAddress(mServerAddress, LinphoneEnums::toLinphone(transport), true);
|
||||
model->setOutboundProxyEnabled(mOutboundProxyEnabled);
|
||||
model->setRegistrarUri(mRegistrarUri);
|
||||
model->setOutboundProxyUri(mOutboundProxyUri);
|
||||
model->setStunServer(mStunServer);
|
||||
model->setIceEnabled(mIceEnabled);
|
||||
model->setAvpfEnabled(mAvpfEnabled);
|
||||
|
|
@ -750,27 +832,28 @@ void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
|
|||
model->setConferenceFactoryAddress(mConferenceFactoryAddress);
|
||||
model->setAudioVideoConferenceFactoryAddress(mAudioVideoConferenceFactoryAddress);
|
||||
model->setLimeServerUrl(mLimeServerUrl);
|
||||
model->setCcmpServerUrl(mCcmpServerUrl);
|
||||
model->setVoicemailAddress(mVoicemailAddress);
|
||||
}
|
||||
|
||||
void AccountCore::writeFromModel(const std::shared_ptr<AccountModel> &model) {
|
||||
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
|
||||
|
||||
mUnreadCallNotifications = model->getMissedCallsCount();
|
||||
mUnreadMessageNotifications = model->getUnreadMessagesCount();
|
||||
mMwiServerAddress = model->getMwiServerAddress();
|
||||
mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(model->getTransport()));
|
||||
mServerAddress = model->getServerAddress();
|
||||
mOutboundProxyEnabled = model->getOutboundProxyEnabled();
|
||||
mStunServer = model->getStunServer();
|
||||
mIceEnabled = model->getIceEnabled();
|
||||
mAvpfEnabled = model->getAvpfEnabled();
|
||||
mBundleModeEnabled = model->getBundleModeEnabled();
|
||||
mExpire = model->getExpire();
|
||||
mConferenceFactoryAddress = model->getConferenceFactoryAddress();
|
||||
mAudioVideoConferenceFactoryAddress = model->getAudioVideoConferenceFactoryAddress();
|
||||
mLimeServerUrl = model->getLimeServerUrl();
|
||||
mVoicemailAddress = model->getVoicemailAddress();
|
||||
setUnreadCallNotifications(model->getMissedCallsCount());
|
||||
setUnreadMessageNotifications(model->getUnreadMessagesCount());
|
||||
onMwiServerAddressChanged(model->getMwiServerAddress());
|
||||
onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(model->getTransport())));
|
||||
onRegistrarUriChanged(model->getRegistrarUri());
|
||||
onOutboundProxyUriChanged(model->getOutboundProxyUri());
|
||||
onStunServerChanged(model->getStunServer());
|
||||
onIceEnabledChanged(model->getIceEnabled());
|
||||
onAvpfEnabledChanged(model->getAvpfEnabled());
|
||||
onBundleModeEnabledChanged(model->getBundleModeEnabled());
|
||||
onExpireChanged(model->getExpire());
|
||||
onConferenceFactoryAddressChanged(model->getConferenceFactoryAddress());
|
||||
onAudioVideoConferenceFactoryAddressChanged(model->getAudioVideoConferenceFactoryAddress());
|
||||
onLimeServerUrlChanged(model->getLimeServerUrl());
|
||||
onCcmpServerUrlChanged(model->getCcmpServerUrl());
|
||||
onVoicemailAddressChanged(model->getVoicemailAddress());
|
||||
}
|
||||
|
||||
void AccountCore::save() {
|
||||
|
|
@ -802,3 +885,38 @@ void AccountCore::undo() {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::Presence AccountCore::getPresence() {
|
||||
return mPresence;
|
||||
}
|
||||
|
||||
QColor AccountCore::getPresenceColor() {
|
||||
return Utils::getPresenceColor(mPresence);
|
||||
}
|
||||
|
||||
QUrl AccountCore::getPresenceIcon() {
|
||||
return Utils::getPresenceIcon(mPresence);
|
||||
}
|
||||
|
||||
QString AccountCore::getPresenceStatus() {
|
||||
return Utils::getPresenceStatus(mPresence);
|
||||
}
|
||||
|
||||
void AccountCore::resetToAutomaticPresence() {
|
||||
emit lSetPresence(LinphoneEnums::Presence::Online, false, true);
|
||||
}
|
||||
|
||||
LinphoneEnums::Presence AccountCore::getExplicitPresence() {
|
||||
return mExplicitPresence;
|
||||
}
|
||||
|
||||
void AccountCore::setPresenceNote(QString presenceNote) {
|
||||
if (presenceNote != mPresenceNote) {
|
||||
mPresenceNote = presenceNote;
|
||||
emit lSetPresence(mPresence, mExplicitPresence != LinphoneEnums::Presence::Undefined, false);
|
||||
}
|
||||
}
|
||||
|
||||
QString AccountCore::getPresenceNote() {
|
||||
return mPresenceNote;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ public:
|
|||
QString mwiServerAddress READ getMwiServerAddress WRITE setMwiServerAddress NOTIFY mwiServerAddressChanged)
|
||||
Q_PROPERTY(QStringList transports READ getTransports CONSTANT)
|
||||
Q_PROPERTY(QString transport READ getTransport WRITE setTransport NOTIFY transportChanged)
|
||||
Q_PROPERTY(QString serverAddress READ getServerAddress WRITE setServerAddress NOTIFY serverAddressChanged)
|
||||
Q_PROPERTY(bool outboundProxyEnabled READ getOutboundProxyEnabled WRITE setOutboundProxyEnabled NOTIFY
|
||||
outboundProxyEnabledChanged)
|
||||
Q_PROPERTY(QString registrarUri READ getRegistrarUri WRITE setRegistrarUri NOTIFY registrarUriChanged)
|
||||
Q_PROPERTY(
|
||||
QString outboundProxyUri READ getOutboundProxyUri WRITE setOutboundProxyUri NOTIFY outboundProxyUriChanged)
|
||||
Q_PROPERTY(QString stunServer READ getStunServer WRITE setStunServer NOTIFY stunServerChanged)
|
||||
Q_PROPERTY(bool iceEnabled READ getIceEnabled WRITE setIceEnabled NOTIFY iceEnabledChanged)
|
||||
Q_PROPERTY(bool avpfEnabled READ getAvpfEnabled WRITE setAvpfEnabled NOTIFY avpfEnabledChanged)
|
||||
|
|
@ -75,6 +75,16 @@ public:
|
|||
Q_PROPERTY(bool isSaved READ isSaved WRITE setIsSaved NOTIFY isSavedChanged)
|
||||
Q_PROPERTY(
|
||||
QString voicemailAddress READ getVoicemailAddress WRITE setVoicemailAddress NOTIFY voicemailAddressChanged)
|
||||
Q_PROPERTY(LinphoneEnums::Presence presence READ getPresence WRITE lSetPresence NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QColor presenceColor READ getPresenceColor NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QUrl presenceIcon READ getPresenceIcon NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QString presenceStatus READ getPresenceStatus NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QColor registrationColor READ getRegistrationColor NOTIFY registrationStateChanged)
|
||||
Q_PROPERTY(QUrl registrationIcon READ getRegistrationIcon NOTIFY registrationStateChanged)
|
||||
Q_PROPERTY(LinphoneEnums::Presence explicitPresence MEMBER mExplicitPresence NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QString presenceNote READ getPresenceNote WRITE setPresenceNote NOTIFY presenceChanged)
|
||||
Q_PROPERTY(int maxPresenceNoteSize MEMBER mMaxPresenceNoteSize CONSTANT)
|
||||
Q_PROPERTY(QString ccmpServerUrl READ getCcmpServerUrl WRITE setCcmpServerUrl NOTIFY ccmpServerUrlChanged)
|
||||
|
||||
DECLARE_CORE_GET(int, voicemailCount, VoicemailCount)
|
||||
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
|
||||
|
|
@ -114,6 +124,8 @@ public:
|
|||
void onDialPlanChanged(QVariantMap internationalPrefix);
|
||||
QString getHumanReadableRegistrationState() const;
|
||||
QString getHumanReadableRegistrationStateExplained() const;
|
||||
QColor getRegistrationColor() const;
|
||||
QUrl getRegistrationIcon() const;
|
||||
bool getRegisterEnabled() const;
|
||||
void onRegisterEnabledChanged(bool enabled);
|
||||
|
||||
|
|
@ -121,8 +133,8 @@ public:
|
|||
QString getMwiServerAddress();
|
||||
QString getTransport();
|
||||
QStringList getTransports();
|
||||
QString getServerAddress();
|
||||
bool getOutboundProxyEnabled();
|
||||
QString getRegistrarUri();
|
||||
QString getOutboundProxyUri();
|
||||
QString getStunServer();
|
||||
bool getIceEnabled();
|
||||
bool getAvpfEnabled();
|
||||
|
|
@ -132,11 +144,12 @@ public:
|
|||
QString getAudioVideoConferenceFactoryAddress();
|
||||
QString getLimeServerUrl();
|
||||
QString getVoicemailAddress();
|
||||
QString getCcmpServerUrl();
|
||||
|
||||
void setMwiServerAddress(QString value);
|
||||
void setTransport(QString value);
|
||||
void setServerAddress(QString value);
|
||||
void setOutboundProxyEnabled(bool value);
|
||||
void setRegistrarUri(QString value);
|
||||
void setOutboundProxyUri(QString value);
|
||||
void setStunServer(QString value);
|
||||
void setIceEnabled(bool value);
|
||||
void setAvpfEnabled(bool value);
|
||||
|
|
@ -146,6 +159,7 @@ public:
|
|||
void setAudioVideoConferenceFactoryAddress(QString value);
|
||||
void setLimeServerUrl(QString value);
|
||||
void setVoicemailAddress(QString value);
|
||||
void setCcmpServerUrl(QString value);
|
||||
|
||||
bool isSaved() const;
|
||||
void setIsSaved(bool saved);
|
||||
|
|
@ -154,8 +168,8 @@ public:
|
|||
void onMwiServerAddressChanged(QString value);
|
||||
void onVoicemailAddressChanged(QString value);
|
||||
void onTransportChanged(QString value);
|
||||
void onServerAddressChanged(QString value);
|
||||
void onOutboundProxyEnabledChanged(bool value);
|
||||
void onRegistrarUriChanged(QString value);
|
||||
void onOutboundProxyUriChanged(QString value);
|
||||
void onStunServerChanged(QString value);
|
||||
void onIceEnabledChanged(bool value);
|
||||
void onAvpfEnabledChanged(bool value);
|
||||
|
|
@ -164,15 +178,26 @@ public:
|
|||
void onConferenceFactoryAddressChanged(QString value);
|
||||
void onAudioVideoConferenceFactoryAddressChanged(QString value);
|
||||
void onLimeServerUrlChanged(QString value);
|
||||
void onCcmpServerUrlChanged(QString value);
|
||||
|
||||
DECLARE_CORE_GET(bool, showMwi, ShowMwi)
|
||||
|
||||
Q_INVOKABLE void save();
|
||||
Q_INVOKABLE void undo();
|
||||
|
||||
QColor getPresenceColor();
|
||||
QUrl getPresenceIcon();
|
||||
QString getPresenceStatus();
|
||||
LinphoneEnums::Presence getPresence();
|
||||
Q_INVOKABLE void resetToAutomaticPresence();
|
||||
LinphoneEnums::Presence getExplicitPresence();
|
||||
void setPresenceNote(QString presenceNote);
|
||||
QString getPresenceNote();
|
||||
|
||||
signals:
|
||||
void pictureUriChanged();
|
||||
void registrationStateChanged(const QString &message);
|
||||
void conferenceInformationUpdated();
|
||||
void defaultAccountChanged(bool isDefault);
|
||||
void unreadNotificationsChanged(int unread);
|
||||
void unreadCallNotificationsChanged(int unread);
|
||||
|
|
@ -185,8 +210,8 @@ signals:
|
|||
void notificationsAllowedChanged();
|
||||
void mwiServerAddressChanged();
|
||||
void transportChanged();
|
||||
void serverAddressChanged();
|
||||
void outboundProxyEnabledChanged();
|
||||
void registrarUriChanged();
|
||||
void outboundProxyUriChanged();
|
||||
void stunServerChanged();
|
||||
void iceEnabledChanged();
|
||||
void avpfEnabledChanged();
|
||||
|
|
@ -198,16 +223,22 @@ signals:
|
|||
void removed();
|
||||
void isSavedChanged();
|
||||
void voicemailAddressChanged();
|
||||
void presenceChanged();
|
||||
void ccmpServerUrlChanged();
|
||||
|
||||
void setValueFailed(const QString &error);
|
||||
|
||||
// Account requests
|
||||
void lSetPictureUri(QString pictureUri);
|
||||
void lSetDefaultAccount();
|
||||
void lResetMissedCalls();
|
||||
void lResetUnreadMessages();
|
||||
void lRefreshNotifications();
|
||||
void lSetDisplayName(QString displayName);
|
||||
void lSetDialPlan(QVariantMap internationalPrefix);
|
||||
void lSetRegisterEnabled(bool enabled);
|
||||
void lSetNotificationsAllowed(bool value);
|
||||
void lSetPresence(LinphoneEnums::Presence presence, bool userInitiated = true, bool resetToAuto = false);
|
||||
|
||||
protected:
|
||||
void writeIntoModel(std::shared_ptr<AccountModel> model) const;
|
||||
|
|
@ -231,8 +262,8 @@ private:
|
|||
QString mMwiServerAddress;
|
||||
QString mTransport;
|
||||
QStringList mTransports;
|
||||
QString mServerAddress;
|
||||
bool mOutboundProxyEnabled;
|
||||
QString mRegistrarUri;
|
||||
QString mOutboundProxyUri;
|
||||
QString mStunServer;
|
||||
bool mIceEnabled;
|
||||
bool mAvpfEnabled;
|
||||
|
|
@ -242,8 +273,14 @@ private:
|
|||
QString mAudioVideoConferenceFactoryAddress;
|
||||
QString mLimeServerUrl;
|
||||
QString mVoicemailAddress;
|
||||
QString mCcmpServerUrl;
|
||||
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
|
||||
LinphoneEnums::Presence mExplicitPresence;
|
||||
QString mPresenceNote;
|
||||
int mMaxPresenceNoteSize;
|
||||
|
||||
bool mIsSaved = true;
|
||||
|
||||
std::shared_ptr<AccountModel> mAccountModel;
|
||||
QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection;
|
||||
QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection;
|
||||
|
|
|
|||
|
|
@ -69,16 +69,14 @@ void AccountDeviceList::setAccount(const QSharedPointer<AccountCore> &accountCor
|
|||
mAccountCore = accountCore;
|
||||
lDebug() << log().arg("Set account model") << mAccountCore.get();
|
||||
// oldConnect.unlock();
|
||||
refreshDevices();
|
||||
if (mAccountCore) refreshDevices();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
void AccountDeviceList::refreshDevices() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
beginResetModel();
|
||||
clearData();
|
||||
endResetModel();
|
||||
resetData();
|
||||
if (mAccountCore) {
|
||||
auto requestDeviceList = [this] {
|
||||
if (!mAccountManagerServicesModelConnection) return;
|
||||
|
|
@ -150,14 +148,14 @@ void AccountDeviceList::setSelf(QSharedPointer<AccountDeviceList> me) {
|
|||
&AccountManagerServicesModel::requestError,
|
||||
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
|
||||
const std::string &errorMessage,
|
||||
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
||||
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
||||
QString message = QString::fromStdString(errorMessage);
|
||||
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
||||
//: "Erreur lors de la récupération des appareils"
|
||||
message = tr("manage_account_no_device_found_error_message");
|
||||
}
|
||||
emit requestError(message);
|
||||
const std::shared_ptr<const linphone::Dictionary> ¶meterErrors) {
|
||||
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
|
||||
QString message = QString::fromStdString(errorMessage);
|
||||
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
|
||||
//: "Erreur lors de la récupération des appareils"
|
||||
message = tr("manage_account_no_device_found_error_message");
|
||||
}
|
||||
emit requestError(message);
|
||||
});
|
||||
mAccountManagerServicesModelConnection->makeConnectToModel(
|
||||
&AccountManagerServicesModel::devicesListFetched,
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@
|
|||
#ifndef ACCOUNT_DEVICE_LIST_H_
|
||||
#define ACCOUNT_DEVICE_LIST_H_
|
||||
|
||||
#include "../proxy/ListProxy.hpp"
|
||||
#include "AccountDeviceCore.hpp"
|
||||
#include "core/account/AccountGui.hpp"
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "model/account/AccountManagerServicesModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
|
|
|||
|
|
@ -61,6 +61,11 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
|
|||
auto model = AccountCore::create(it);
|
||||
if (it == defaultAccount) defaultAccountCore = model;
|
||||
accounts->push_back(model);
|
||||
connect(model.get(), &AccountCore::unreadNotificationsChanged, this,
|
||||
[this] { emit unreadNotificationsChanged(); });
|
||||
connect(model.get(), &AccountCore::removed, this, [this, model]() {
|
||||
disconnect(model.get(), &AccountCore::unreadNotificationsChanged, this, nullptr);
|
||||
});
|
||||
}
|
||||
mModelConnection->invokeToCore([this, accounts, defaultAccountCore, isInitialization]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
|
|
@ -68,8 +73,14 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
|
|||
setHaveAccount(accounts->size() > 0);
|
||||
setDefaultAccount(defaultAccountCore);
|
||||
if (isInitialization) setInitialized(true);
|
||||
for (const QSharedPointer<AccountCore> &accountCore : *accounts) {
|
||||
if (accountCore->getExplicitPresence() != LinphoneEnums::Presence::Undefined)
|
||||
emit accountCore->lSetPresence(accountCore->getExplicitPresence(), true, false);
|
||||
}
|
||||
delete accounts;
|
||||
});
|
||||
// Update notification count at startup
|
||||
if (isInitialization) emit unreadNotificationsChanged();
|
||||
});
|
||||
});
|
||||
mModelConnection->makeConnectToModel(
|
||||
|
|
@ -88,7 +99,8 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
|
|||
// with the open id account
|
||||
mModelConnection->makeConnectToModel(&CoreModel::bearerAccountAdded, [this] {
|
||||
setInitialized(false);
|
||||
emit lUpdate(true); });
|
||||
emit lUpdate(true);
|
||||
});
|
||||
|
||||
mModelConnection->makeConnectToModel(
|
||||
&CoreModel::globalStateChanged,
|
||||
|
|
@ -158,6 +170,18 @@ void AccountList::setInitialized(bool init) {
|
|||
}
|
||||
}
|
||||
|
||||
void AccountList::lResetMissedCalls() {
|
||||
for (auto &accountCore : getSharedList<AccountCore>()) {
|
||||
accountCore->lResetMissedCalls();
|
||||
}
|
||||
}
|
||||
|
||||
void AccountList::lResetUnreadMessages() {
|
||||
for (auto &accountCore : getSharedList<AccountCore>()) {
|
||||
emit accountCore->lResetUnreadMessages();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant AccountList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@ public:
|
|||
|
||||
bool isInitialized() const;
|
||||
void setInitialized(bool init);
|
||||
void lResetMissedCalls(); // Reset missed calls of all accounts
|
||||
void lResetUnreadMessages(); // Reset unread messages of all accounts
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
signals:
|
||||
|
|
@ -58,6 +60,7 @@ signals:
|
|||
void haveAccountChanged();
|
||||
void defaultAccountChanged();
|
||||
void initializedChanged(bool init);
|
||||
void unreadNotificationsChanged();
|
||||
|
||||
private:
|
||||
bool mHaveAccount = false;
|
||||
|
|
|
|||
|
|
@ -73,8 +73,11 @@ void CarddavCore::remove() {
|
|||
|
||||
void CarddavCore::setSelf(QSharedPointer<CarddavCore> me) {
|
||||
mCarddavModelConnection = SafeConnection<CarddavCore, CarddavModel>::create(me, mCarddavModel);
|
||||
mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success) {
|
||||
mCarddavModelConnection->invokeToCore([this, success]() { emit saved(success); });
|
||||
mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success, QString message) {
|
||||
mCarddavModelConnection->invokeToCore([this, success, message]() {
|
||||
if (success) emit App::getInstance() -> getSettings()->cardDAVAddressBookSynchronized();
|
||||
emit saved(success, message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
DECLARE_CORE_MEMBER(bool, storeNewFriendsInIt, StoreNewFriendsInIt)
|
||||
|
||||
signals:
|
||||
void saved(bool success);
|
||||
void saved(bool success, QString message);
|
||||
|
||||
private:
|
||||
std::shared_ptr<CarddavModel> mCarddavModel;
|
||||
|
|
|
|||
|
|
@ -46,8 +46,7 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr<linphone::CallLog> &callL
|
|||
mustBeInLinphoneThread(getClassName());
|
||||
mCallHistoryModel = std::make_shared<CallHistoryModel>(callLog);
|
||||
|
||||
auto addr = callLog->getRemoteAddress()->clone();
|
||||
addr->clean();
|
||||
auto addr = callLog->getRemoteAddress();
|
||||
mStatus = LinphoneEnums::fromLinphone(callLog->getStatus());
|
||||
mDate = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
|
||||
mIsOutgoing = callLog->getDir() == linphone::Call::Dir::Outgoing;
|
||||
|
|
@ -129,14 +128,16 @@ void CallHistoryCore::setSelf(QSharedPointer<CallHistoryCore> me) {
|
|||
mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved, &CallHistoryCore::onRemoved);
|
||||
// Update display name when display name has been requested from magic search cause not found in linphone friends
|
||||
// (required to get the right display name if ldap friends cleared)
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::magicSearchResultReceived, [this, remoteAddress = mRemoteAddress] {
|
||||
auto displayName = ToolModel::getDisplayName(remoteAddress);
|
||||
mCoreModelConnection->invokeToCore([this, displayName]() {
|
||||
mDisplayName = displayName;
|
||||
emit displayNameChanged();
|
||||
});
|
||||
});
|
||||
|
||||
// This replace the display name set by a user by a default one, use the linphone address to
|
||||
// get a correct display name
|
||||
// mCoreModelConnection->makeConnectToModel(&CoreModel::magicSearchResultReceived,
|
||||
// [this, remoteAddress = mRemoteAddress] {
|
||||
// auto displayName = ToolModel::getDisplayName(remoteAddress);
|
||||
// mCoreModelConnection->invokeToCore([this, displayName]() {
|
||||
// mDisplayName = displayName;
|
||||
// emit displayNameChanged();
|
||||
// });
|
||||
// });
|
||||
}
|
||||
|
||||
ConferenceInfoGui *CallHistoryCore::getConferenceInfoGui() const {
|
||||
|
|
|
|||
|
|
@ -57,10 +57,12 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
|
|||
mModelConnection = SafeConnection<CallHistoryList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
|
||||
mModelConnection->makeConnectToCore(&CallHistoryList::lUpdate, [this]() {
|
||||
clearData();
|
||||
emit listAboutToBeReset();
|
||||
mModelConnection->invokeToModel([this]() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
// Avoid copy to lambdas
|
||||
QList<QSharedPointer<CallHistoryCore>> *callLogs = new QList<QSharedPointer<CallHistoryCore>>();
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
std::list<std::shared_ptr<linphone::CallLog>> linphoneCallLogs;
|
||||
if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) {
|
||||
linphoneCallLogs = account->getCallLogs();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ signals:
|
|||
void lUpdate();
|
||||
void lRemoveEntriesForAddress(QString address);
|
||||
void lRemoveAllEntries();
|
||||
void listAboutToBeReset();
|
||||
|
||||
private:
|
||||
// Check the state from CallHistoryCore: sender() must be a CallHistoryCore.
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ DEFINE_ABSTRACT_OBJECT(CallHistoryProxy)
|
|||
|
||||
CallHistoryProxy::CallHistoryProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mHistoryList = CallHistoryList::create();
|
||||
connect(mHistoryList.get(), &CallHistoryList::listAboutToBeReset, this, &CallHistoryProxy::listAboutToBeReset);
|
||||
setSourceModels(new SortFilterList(mHistoryList.get(), Qt::DescendingOrder));
|
||||
connect(App::getInstance(), &App::currentDateChanged, this, [this] { emit mHistoryList->lUpdate(); });
|
||||
}
|
||||
|
|
@ -56,7 +57,7 @@ bool CallHistoryProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QMo
|
|||
QRegularExpression::CaseInsensitiveOption |
|
||||
QRegularExpression::UseUnicodePropertiesOption);
|
||||
auto callLog = getItemAtSource<CallHistoryList, CallHistoryCore>(sourceRow);
|
||||
show = callLog->mDisplayName.contains(search) || callLog->mRemoteAddress.contains(search);
|
||||
show = callLog && (callLog->mDisplayName.contains(search) || callLog->mRemoteAddress.contains(search));
|
||||
}
|
||||
return show;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ public:
|
|||
Q_INVOKABLE void removeEntriesWithFilter(QString filter);
|
||||
Q_INVOKABLE void reload();
|
||||
|
||||
signals:
|
||||
void listAboutToBeReset();
|
||||
|
||||
protected:
|
||||
QSharedPointer<CallHistoryList> mHistoryList;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
* Copyright (c) 2010-2026 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
#include "tool/Utils.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
#include <QQuickWindow>
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(CallCore)
|
||||
|
||||
/***********************************************************************/
|
||||
|
|
@ -107,18 +109,17 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
mCallModel->setSelf(mCallModel);
|
||||
mDuration = call->getDuration();
|
||||
mIsStarted = mDuration > 0;
|
||||
mMicrophoneMuted = call->getMicrophoneMuted();
|
||||
mSpeakerMuted = call->getSpeakerMuted();
|
||||
auto videoDirection = call->getParams()->getVideoDirection();
|
||||
auto callParams = call->getParams();
|
||||
auto videoDirection = callParams->getVideoDirection();
|
||||
mLocalVideoEnabled =
|
||||
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
|
||||
mCameraEnabled = callParams->cameraEnabled();
|
||||
auto remoteParams = call->getRemoteParams();
|
||||
videoDirection = remoteParams ? remoteParams->getVideoDirection() : linphone::MediaDirection::Inactive;
|
||||
mRemoteVideoEnabled =
|
||||
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
|
||||
mState = LinphoneEnums::fromLinphone(call->getState());
|
||||
auto remoteAddress = call->getCallLog()->getRemoteAddress()->clone();
|
||||
remoteAddress->clean();
|
||||
auto remoteAddress = call->getCallLog()->getRemoteAddress();
|
||||
mRemoteAddress = Utils::coreStringToAppString(remoteAddress->asStringUriOnly());
|
||||
mRemoteUsername = Utils::coreStringToAppString(remoteAddress->getUsername());
|
||||
auto linphoneFriend = ToolModel::findFriendByAddress(remoteAddress);
|
||||
|
|
@ -136,7 +137,7 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
mTransferState = LinphoneEnums::fromLinphone(call->getTransferState());
|
||||
mLocalToken = Utils::coreStringToAppString(mCallModel->getLocalAtuhenticationToken());
|
||||
mRemoteTokens = mCallModel->getRemoteAtuhenticationTokens();
|
||||
mEncryption = LinphoneEnums::fromLinphone(call->getParams()->getMediaEncryption());
|
||||
mEncryption = LinphoneEnums::fromLinphone(callParams->getMediaEncryption());
|
||||
auto tokenVerified = call->getAuthenticationTokenVerified();
|
||||
mIsMismatch = call->getZrtpCacheMismatchFlag();
|
||||
mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
|
||||
|
|
@ -158,10 +159,12 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
|
|||
if (mIsConference) {
|
||||
mConference = ConferenceCore::create(conference);
|
||||
}
|
||||
mMicrophoneMuted = conference ? conference->getMicrophoneMuted() : call->getMicrophoneMuted();
|
||||
mSpeakerMuted = call->getSpeakerMuted();
|
||||
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
|
||||
mState == LinphoneEnums::CallState::PausedByRemote;
|
||||
|
||||
mRecording = call->getParams() && call->getParams()->isRecording();
|
||||
mRecording = callParams && callParams->isRecording();
|
||||
mRemoteRecording = call->getRemoteParams() && call->getRemoteParams()->isRecording();
|
||||
auto settingsModel = SettingsModel::getInstance();
|
||||
mMicrophoneVolume = call->getRecordVolume();
|
||||
|
|
@ -194,8 +197,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mCallModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) {
|
||||
mCallModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToCore(&CallCore::lSetLocalVideoEnabled, [this](bool enabled) {
|
||||
mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setLocalVideoEnabled(enabled); });
|
||||
mCallModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) {
|
||||
mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
|
||||
mCallModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
|
||||
|
|
@ -205,14 +208,15 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
});
|
||||
mCallModelConnection->makeConnectToModel(
|
||||
&CallModel::recordingChanged, [this](const std::shared_ptr<linphone::Call> &call, bool recording) {
|
||||
mCallModelConnection->invokeToCore([this, recording]() {
|
||||
auto recordFile = QString::fromStdString(mCallModel->getRecordFile());
|
||||
mCallModelConnection->invokeToCore([this, recording, recordFile]() {
|
||||
setRecording(recording);
|
||||
if (recording == false) {
|
||||
//: "Enregistrement terminé"
|
||||
Utils::showInformationPopup(tr("call_record_end_message"),
|
||||
//: "L'appel a été enregistré dans le fichier : %1"
|
||||
tr("call_record_saved_in_file_message").arg(QString::fromStdString(mCallModel->getRecordFile())),
|
||||
true, App::getInstance()->getCallsWindow());
|
||||
//: "Enregistrement terminé"
|
||||
Utils::showInformationPopup(tr("call_record_end_message"),
|
||||
//: "L'appel a été enregistré dans le fichier : %1"
|
||||
tr("call_record_saved_in_file_message").arg(recordFile), true,
|
||||
App::getInstance()->getOrCreateCallsWindow());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
@ -244,6 +248,9 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
mCallModelConnection->makeConnectToModel(&CallModel::localVideoEnabledChanged, [this](bool enabled) {
|
||||
mCallModelConnection->invokeToCore([this, enabled]() { setLocalVideoEnabled(enabled); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::cameraEnabledChanged, [this](bool enabled) {
|
||||
mCallModelConnection->invokeToCore([this, enabled]() { setCameraEnabled(enabled); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
|
||||
mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
|
||||
});
|
||||
|
|
@ -261,6 +268,7 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
bool isConf = call && call->getConference() != nullptr;
|
||||
auto subject = call->getConference() ? Utils::coreStringToAppString(call->getConference()->getSubject()) : "";
|
||||
mCallModelConnection->invokeToCore([this, state, subject, isConf]() {
|
||||
lDebug() << log().arg("::onStateChanged") << LinphoneEnums::fromLinphone(state);
|
||||
setRecordable(state == linphone::Call::State::StreamsRunning);
|
||||
setPaused(state == linphone::Call::State::Paused || state == linphone::Call::State::PausedByRemote);
|
||||
if (mConference) mConference->setSubject(subject);
|
||||
|
|
@ -308,8 +316,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
[this, call, encryption, tokenVerified, localToken, remoteTokens, isCaseMismatch]() {
|
||||
setLocalToken(localToken);
|
||||
setRemoteTokens(remoteTokens);
|
||||
setIsMismatch(isCaseMismatch);
|
||||
setTokenVerified(tokenVerified);
|
||||
setIsMismatch(isCaseMismatch);
|
||||
setTokenVerified(tokenVerified);
|
||||
setEncryption(encryption);
|
||||
});
|
||||
auto mediaEncryption = call->getParams()->getMediaEncryption();
|
||||
|
|
@ -321,7 +329,7 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
zrtpStats.mHashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo());
|
||||
zrtpStats.mAuthenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo());
|
||||
zrtpStats.mSasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo());
|
||||
zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum();
|
||||
zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum();
|
||||
mCallModelConnection->invokeToCore([this, zrtpStats]() { setZrtpStats(zrtpStats); });
|
||||
}
|
||||
});
|
||||
|
|
@ -343,6 +351,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::conferenceChanged, [this]() {
|
||||
auto conference = mCallModel->getMonitor()->getConference();
|
||||
// Force enable video if in conference to handle screen sharing
|
||||
if (conference && !mCallModel->videoEnabled()) mCallModel->enableVideo(true);
|
||||
QSharedPointer<ConferenceCore> core = conference ? ConferenceCore::create(conference) : nullptr;
|
||||
mCallModelConnection->invokeToCore([this, core]() { setConference(core); });
|
||||
});
|
||||
|
|
@ -388,23 +398,23 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
auto codecType = playloadType ? playloadType->getMimeType() : "";
|
||||
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
|
||||
audioStats.mCodec =
|
||||
//: "Codec: %1 / %2 kHz"
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
//: "Codec: %1 / %2 kHz"
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
auto linAudioStats = call->getAudioStats();
|
||||
if (linAudioStats) {
|
||||
//: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s"
|
||||
audioStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
//: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s"
|
||||
audioStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
.arg("↑")
|
||||
.arg(round(linAudioStats->getUploadBandwidth()))
|
||||
.arg("↓")
|
||||
.arg(round(linAudioStats->getDownloadBandwidth()));
|
||||
//: "Taux de perte: %1% %2%"
|
||||
audioStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
//: "Taux de perte: %1% %2%"
|
||||
audioStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
.arg(linAudioStats->getSenderLossRate())
|
||||
.arg(linAudioStats->getReceiverLossRate());
|
||||
//: "Tampon de gigue: %1 ms"
|
||||
audioStats.mJitterBufferSize =
|
||||
tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs());
|
||||
//: "Tampon de gigue: %1 ms"
|
||||
audioStats.mJitterBufferSize =
|
||||
tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs());
|
||||
}
|
||||
setAudioStats(audioStats);
|
||||
} else if (stats->getType() == linphone::StreamType::Video) {
|
||||
|
|
@ -414,15 +424,15 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
auto codecType = playloadType ? playloadType->getMimeType() : "";
|
||||
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
|
||||
videoStats.mCodec =
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
|
||||
auto linVideoStats = call->getVideoStats();
|
||||
if (stats) {
|
||||
videoStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
videoStats.mBandwidth = tr("call_stats_bandwidth_label")
|
||||
.arg("↑")
|
||||
.arg(round(linVideoStats->getUploadBandwidth()))
|
||||
.arg("↓")
|
||||
.arg(round(linVideoStats->getDownloadBandwidth()));
|
||||
videoStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
videoStats.mLossRate = tr("call_stats_loss_rate_label")
|
||||
.arg(linVideoStats->getSenderLossRate())
|
||||
.arg(linVideoStats->getReceiverLossRate());
|
||||
}
|
||||
|
|
@ -430,17 +440,55 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
|
|||
params->getSentVideoDefinition() ? params->getSentVideoDefinition()->getName() : "";
|
||||
auto receivedResolution =
|
||||
params->getReceivedVideoDefinition() ? params->getReceivedVideoDefinition()->getName() : "";
|
||||
//: "Définition vidéo : %1 %2 %3 %4"
|
||||
videoStats.mResolution = tr("call_stats_resolution_label")
|
||||
//: "Définition vidéo : %1 %2 %3 %4"
|
||||
videoStats.mResolution = tr("call_stats_resolution_label")
|
||||
.arg("↑", Utils::coreStringToAppString(sentResolution), "↓",
|
||||
Utils::coreStringToAppString(receivedResolution));
|
||||
auto sentFps = params->getSentFramerate();
|
||||
auto receivedFps = params->getReceivedFramerate();
|
||||
//: "FPS : %1 %2 %3 %4"
|
||||
videoStats.mFps = tr("call_stats_fps_label").arg("↑").arg(sentFps).arg("↓").arg(receivedFps);
|
||||
//: "FPS : %1 %2 %3 %4"
|
||||
videoStats.mFps = tr("call_stats_fps_label").arg("↑").arg(sentFps).arg("↓").arg(receivedFps);
|
||||
setVideoStats(videoStats);
|
||||
}
|
||||
});
|
||||
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetAnswerCallRequested, [this]() {
|
||||
mCallModelConnection->invokeToCore([this]() {
|
||||
const auto callList = App::getInstance()->getCallList();
|
||||
const auto currentPendingCall = callList->getFirstIncommingPendingCall();
|
||||
if (!currentPendingCall.isNull()) {
|
||||
const auto gui = new CallGui(currentPendingCall);
|
||||
Utils::openCallsWindow(gui);
|
||||
currentPendingCall->lAccept(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetEndCallRequested, [this]() {
|
||||
mCallModelConnection->invokeToCore([this]() {
|
||||
const auto window = Utils::getOrCreateCallsWindow();
|
||||
window->setProperty("callTerminatedByUser", true);
|
||||
lTerminate();
|
||||
});
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetHoldCallRequested, [this]() {
|
||||
mCallModelConnection->invokeToCore([this]() { lSetPaused(true); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetMicrophoneMuteToggled, [this](bool mute) {
|
||||
mCallModelConnection->invokeToCore([this, mute]() { lSetMicrophoneMuted(mute); });
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetRejectCallRequested, [this]() {
|
||||
mCallModelConnection->invokeToCore([this]() {
|
||||
const auto callList = App::getInstance()->getCallList();
|
||||
const auto currentPendingCall = callList->getFirstIncommingPendingCall();
|
||||
if (!currentPendingCall.isNull()) {
|
||||
currentPendingCall->lDecline();
|
||||
}
|
||||
});
|
||||
});
|
||||
mCallModelConnection->makeConnectToModel(&CallModel::headsetResumeCallRequested, [this]() {
|
||||
mCallModelConnection->invokeToCore([this]() { lSetPaused(false); });
|
||||
});
|
||||
|
||||
if (mShouldFindRemoteFriend) findRemoteFriend(me);
|
||||
}
|
||||
|
||||
|
|
@ -557,6 +605,18 @@ void CallCore::setLocalVideoEnabled(bool enabled) {
|
|||
}
|
||||
}
|
||||
|
||||
bool CallCore::getCameraEnabled() const {
|
||||
return mCameraEnabled;
|
||||
}
|
||||
|
||||
void CallCore::setCameraEnabled(bool enabled) {
|
||||
if (mCameraEnabled != enabled) {
|
||||
mCameraEnabled = enabled;
|
||||
lDebug() << "CameraEnabled: " << mCameraEnabled;
|
||||
emit cameraEnabledChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallCore::getPaused() const {
|
||||
return mPaused;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ public:
|
|||
Q_PROPERTY(QStringList remoteTokens WRITE setRemoteTokens MEMBER mRemoteTokens NOTIFY remoteTokensChanged)
|
||||
Q_PROPERTY(
|
||||
bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged)
|
||||
Q_PROPERTY(
|
||||
bool localVideoEnabled READ getLocalVideoEnabled WRITE lSetLocalVideoEnabled NOTIFY localVideoEnabledChanged)
|
||||
Q_PROPERTY(bool localVideoEnabled READ getLocalVideoEnabled NOTIFY localVideoEnabledChanged)
|
||||
Q_PROPERTY(bool cameraEnabled READ getCameraEnabled WRITE lSetCameraEnabled NOTIFY cameraEnabledChanged)
|
||||
Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged)
|
||||
Q_PROPERTY(bool remoteRecording READ getRemoteRecording WRITE setRemoteRecording NOTIFY remoteRecordingChanged)
|
||||
Q_PROPERTY(bool recordable READ getRecordable WRITE setRecordable NOTIFY recordableChanged)
|
||||
|
|
@ -201,6 +201,9 @@ public:
|
|||
bool getLocalVideoEnabled() const;
|
||||
void setLocalVideoEnabled(bool enabled);
|
||||
|
||||
bool getCameraEnabled() const;
|
||||
void setCameraEnabled(bool enabled);
|
||||
|
||||
bool getRecording() const;
|
||||
void setRecording(bool recording);
|
||||
|
||||
|
|
@ -255,6 +258,7 @@ signals:
|
|||
void remoteTokensChanged();
|
||||
void remoteVideoEnabledChanged(bool remoteVideoEnabled);
|
||||
void localVideoEnabledChanged();
|
||||
void cameraEnabledChanged();
|
||||
void recordingChanged();
|
||||
void remoteRecordingChanged();
|
||||
void recordableChanged();
|
||||
|
|
@ -275,7 +279,7 @@ signals:
|
|||
void lTerminateAllCalls(); // Hangup all calls
|
||||
void lSetSpeakerMuted(bool muted);
|
||||
void lSetMicrophoneMuted(bool isMuted);
|
||||
void lSetLocalVideoEnabled(bool enabled);
|
||||
void lSetCameraEnabled(bool enabled);
|
||||
void lSetVideoEnabled(bool enabled);
|
||||
void lSetPaused(bool paused);
|
||||
void lTransferCall(QString address);
|
||||
|
|
@ -331,6 +335,7 @@ private:
|
|||
bool mSpeakerMuted = false;
|
||||
bool mMicrophoneMuted = false;
|
||||
bool mLocalVideoEnabled = false;
|
||||
bool mCameraEnabled = false;
|
||||
bool mVideoEnabled = false;
|
||||
bool mPaused = false;
|
||||
bool mRemoteVideoEnabled = false;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "CallCore.hpp"
|
||||
#include "CallGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
|
|
@ -96,40 +97,32 @@ void CallList::setSelf(QSharedPointer<CallList> me) {
|
|||
bool enablingVideo = false;
|
||||
if (currentCall) enablingVideo = currentCall->getCurrentParams()->videoEnabled();
|
||||
if (!conference) {
|
||||
auto parameters = core->createConferenceParams(conference);
|
||||
auto audioVideoConfFactoryUri =
|
||||
core->getDefaultAccount()->getParams()->getAudioVideoConferenceFactoryAddress();
|
||||
if (audioVideoConfFactoryUri) {
|
||||
parameters->setConferenceFactoryAddress(audioVideoConfFactoryUri);
|
||||
parameters->setSubject("Meeting");
|
||||
QString subject = audioVideoConfFactoryUri
|
||||
//: Remote group call
|
||||
? tr("remote_group_call")
|
||||
//: "Local group call"
|
||||
: tr("local_group_call");
|
||||
auto conference = ToolModel::createConference(subject, nullptr);
|
||||
if (!conference) {
|
||||
lWarning() << log().arg("Failed to merge calls");
|
||||
mModelConnection->invokeToCore([] {
|
||||
Utils::showInformationPopup(tr("info_popup_error_title"),
|
||||
//: Failed to merge calls !
|
||||
tr("info_popup_merge_calls_failed_message"), false);
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
parameters->setSubject("Local meeting");
|
||||
}
|
||||
parameters->enableVideo(enablingVideo);
|
||||
conference = core->createConferenceWithParams(parameters);
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<linphone::Address>> allLinphoneAddresses;
|
||||
std::list<std::shared_ptr<linphone::Address>> newCalls;
|
||||
std::list<std::shared_ptr<linphone::Call>> runningCallsToAdd;
|
||||
|
||||
for (auto call : currentCalls) {
|
||||
if (!call->getConference()) {
|
||||
runningCallsToAdd.push_back(call);
|
||||
conference->addParticipants(currentCalls);
|
||||
}
|
||||
}
|
||||
|
||||
// 1) Add running calls
|
||||
if (runningCallsToAdd.size() > 0) {
|
||||
conference->addParticipants(runningCallsToAdd);
|
||||
}
|
||||
|
||||
// emit lUpdate();
|
||||
});
|
||||
});
|
||||
|
||||
mModelConnection->makeConnectToModel(&CoreModel::firstCallStarted,
|
||||
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
|
||||
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
|
||||
mModelConnection->makeConnectToModel(&CoreModel::lastCallEnded, [this]() {
|
||||
mModelConnection->invokeToCore([this]() {
|
||||
setHaveCall(false);
|
||||
|
|
@ -158,12 +151,8 @@ CallGui *CallList::getCurrentCall() const {
|
|||
else return nullptr;
|
||||
}
|
||||
|
||||
void CallList::setCurrentCall(CallGui* callGui) {
|
||||
auto callCore = callGui ? callGui->mCore : nullptr;
|
||||
if (mCurrentCall != callCore) {
|
||||
mCurrentCall = callCore;
|
||||
emit currentCallChanged();
|
||||
}
|
||||
void CallList::setCurrentCall(CallGui *callGui) {
|
||||
setCurrentCallCore(callGui ? callGui->mCore : nullptr);
|
||||
}
|
||||
|
||||
void CallList::setCurrentCallCore(QSharedPointer<CallCore> call) {
|
||||
|
|
@ -184,16 +173,21 @@ void CallList::setHaveCall(bool haveCall) {
|
|||
}
|
||||
}
|
||||
|
||||
QSharedPointer<CallCore> CallList::getNextCall() const {
|
||||
QSharedPointer<CallCore> call;
|
||||
QSharedPointer<CallCore> CallList::getNextCall() {
|
||||
auto currentCall = getCurrentCallCore();
|
||||
for (auto it = mList.rbegin(); !call && it != mList.rend(); ++it) {
|
||||
if (*it != currentCall) {
|
||||
call = it->objectCast<CallCore>();
|
||||
}
|
||||
for (auto &item : getSharedList<CallCore>()) {
|
||||
if (item != currentCall) return item;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return call;
|
||||
QSharedPointer<CallCore> CallList::getFirstIncommingPendingCall() {
|
||||
auto callList = getSharedList<CallCore>();
|
||||
auto it = std::find_if(callList.begin(), callList.end(), [](const QSharedPointer<CallCore> call) {
|
||||
return call->getState() == LinphoneEnums::CallState::IncomingReceived;
|
||||
});
|
||||
if (it == callList.end()) return nullptr;
|
||||
return *it;
|
||||
}
|
||||
|
||||
void CallList::onStateChanged() {
|
||||
|
|
@ -202,21 +196,26 @@ void CallList::onStateChanged() {
|
|||
case LinphoneEnums::CallState::StreamsRunning:
|
||||
case LinphoneEnums::CallState::Resuming: {
|
||||
auto sharedCall = get(call);
|
||||
setCurrentCallCore(sharedCall.objectCast<CallCore>());
|
||||
setCurrentCallCore(sharedCall ? sharedCall.objectCast<CallCore>() : nullptr);
|
||||
break;
|
||||
}
|
||||
case LinphoneEnums::CallState::Released: {
|
||||
auto sharedCall = get(call);
|
||||
auto currentCall = getCurrentCallCore();
|
||||
// Update current call
|
||||
if (sharedCall == currentCall) {
|
||||
// Unpause the next call. The current call will change on resume.
|
||||
// Assumption: All calls that are not the current are paused.
|
||||
auto nextCall = getNextCall();
|
||||
if (nextCall) nextCall->lSetPaused(false);
|
||||
if (sharedCall) {
|
||||
auto currentCall = getCurrentCallCore();
|
||||
sharedCall->disconnect(this);
|
||||
// Update current call
|
||||
if (currentCall == sharedCall) {
|
||||
auto nextCall = getNextCall();
|
||||
if (nextCall) {
|
||||
// Unpause the next call. The current call will change on resume.
|
||||
// Assumption: All calls that are not the current are paused.
|
||||
nextCall->lSetPaused(false);
|
||||
}
|
||||
setCurrentCallCore(nextCall);
|
||||
}
|
||||
bool removed = remove(sharedCall);
|
||||
}
|
||||
sharedCall->disconnect(this);
|
||||
remove(sharedCall);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class CoreModel;
|
|||
|
||||
class CallList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(CallGui* currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
|
||||
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
|
||||
public:
|
||||
static QSharedPointer<CallList> create();
|
||||
// Create a CallCore and make connections to List.
|
||||
|
|
@ -45,7 +45,7 @@ public:
|
|||
|
||||
CallGui *getCurrentCall() const; // Used for Ui
|
||||
QSharedPointer<CallCore> getCurrentCallCore() const;
|
||||
void setCurrentCall(CallGui* callGui);
|
||||
void setCurrentCall(CallGui *callGui);
|
||||
void setCurrentCallCore(QSharedPointer<CallCore> call);
|
||||
|
||||
bool getHaveCall() const;
|
||||
|
|
@ -53,7 +53,9 @@ public:
|
|||
|
||||
// Get the next call after the current one. Used to switch the current call.
|
||||
// At the moment, it select the last call in the list.
|
||||
QSharedPointer<CallCore> getNextCall() const;
|
||||
QSharedPointer<CallCore> getNextCall();
|
||||
|
||||
QSharedPointer<CallCore> getFirstIncommingPendingCall();
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
signals:
|
||||
|
|
|
|||
|
|
@ -25,20 +25,32 @@
|
|||
|
||||
DEFINE_ABSTRACT_OBJECT(CallProxy)
|
||||
|
||||
CallProxy::CallProxy(QObject *parent) : LimitProxy(parent) {
|
||||
CallProxy::CallProxy() : SortFilterProxy() {
|
||||
mShowCurrentCall = true;
|
||||
}
|
||||
|
||||
CallProxy::~CallProxy() {
|
||||
}
|
||||
|
||||
CallGui *CallProxy::getCurrentCall() {
|
||||
auto model = getListModel<CallList>();
|
||||
auto model = qobject_cast<CallList *>(sourceModel());
|
||||
if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall();
|
||||
return mCurrentCall;
|
||||
}
|
||||
|
||||
void CallProxy::setShowCurrentCall(bool show) {
|
||||
if (mShowCurrentCall != show) {
|
||||
mShowCurrentCall = show;
|
||||
emit showCurrentCallChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool CallProxy::showCurrentCall() const {
|
||||
return mShowCurrentCall;
|
||||
}
|
||||
|
||||
void CallProxy::setCurrentCall(CallGui *call) {
|
||||
getListModel<CallList>()->setCurrentCall(call);
|
||||
qobject_cast<CallList *>(sourceModel())->setCurrentCall(call);
|
||||
}
|
||||
|
||||
// Reset the default account to let UI build its new object if needed.
|
||||
|
|
@ -48,12 +60,12 @@ void CallProxy::resetCurrentCall() {
|
|||
}
|
||||
|
||||
bool CallProxy::getHaveCall() const {
|
||||
auto model = getListModel<CallList>();
|
||||
auto model = qobject_cast<CallList *>(sourceModel());
|
||||
return model ? model->getHaveCall() : false;
|
||||
}
|
||||
|
||||
void CallProxy::setSourceModel(QAbstractItemModel *model) {
|
||||
auto oldCallList = getListModel<CallList>();
|
||||
auto oldCallList = qobject_cast<CallList *>(sourceModel());
|
||||
if (oldCallList) {
|
||||
disconnect(oldCallList);
|
||||
}
|
||||
|
|
@ -63,24 +75,24 @@ void CallProxy::setSourceModel(QAbstractItemModel *model) {
|
|||
connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection);
|
||||
connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll);
|
||||
}
|
||||
setSourceModels(new SortFilterList(model, Qt::AscendingOrder));
|
||||
QSortFilterProxyModel::setSourceModel(model);
|
||||
}
|
||||
|
||||
bool CallProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
bool CallProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
bool show = (mFilterText.isEmpty() || mFilterText == "*");
|
||||
auto callList = qobject_cast<CallList *>(sourceModel());
|
||||
auto call = callList->getAt<CallCore>(sourceRow);
|
||||
if (!mShowCurrentCall && call == callList->getCurrentCallCore()) return false;
|
||||
if (!show) {
|
||||
QRegularExpression search(QRegularExpression::escape(mFilterText),
|
||||
QRegularExpression::CaseInsensitiveOption |
|
||||
QRegularExpression::UseUnicodePropertiesOption);
|
||||
auto call = qobject_cast<CallList *>(sourceModel())->getAt<CallCore>(sourceRow);
|
||||
|
||||
show = call->getRemoteAddress().contains(search);
|
||||
}
|
||||
|
||||
return show;
|
||||
}
|
||||
|
||||
bool CallProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||
bool CallProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||
auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row());
|
||||
auto r = getItemAtSource<CallList, CallCore>(sourceRight.row());
|
||||
|
||||
|
|
|
|||
|
|
@ -28,15 +28,14 @@
|
|||
|
||||
// =============================================================================
|
||||
|
||||
class CallProxy : public LimitProxy, public AbstractObject {
|
||||
class CallProxy : public SortFilterProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
|
||||
Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged)
|
||||
Q_PROPERTY(bool showCurrentCall READ showCurrentCall WRITE setShowCurrentCall NOTIFY showCurrentCallChanged)
|
||||
|
||||
public:
|
||||
DECLARE_SORTFILTER_CLASS()
|
||||
|
||||
CallProxy(QObject *parent = Q_NULLPTR);
|
||||
CallProxy();
|
||||
~CallProxy();
|
||||
|
||||
// Get a new object from List or give the stored one.
|
||||
|
|
@ -48,15 +47,23 @@ public:
|
|||
|
||||
bool getHaveCall() const;
|
||||
|
||||
void setShowCurrentCall(bool show);
|
||||
bool showCurrentCall() const;
|
||||
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
|
||||
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
virtual bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
|
||||
|
||||
signals:
|
||||
void lMergeAll();
|
||||
void currentCallChanged();
|
||||
void haveCallChanged();
|
||||
void showCurrentCallChanged();
|
||||
|
||||
protected:
|
||||
CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List
|
||||
bool mShowCurrentCall = false;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -71,10 +71,12 @@ QQuickFramebufferObject::Renderer *PreviewManager::subscribe(const CameraGui *ca
|
|||
App::postModelBlock([&renderer, isFirst = (itCandidate == mCandidates.begin()),
|
||||
name = itCandidate->first->getQmlName()]() {
|
||||
renderer =
|
||||
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId();
|
||||
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(
|
||||
nullptr);
|
||||
if (!renderer) { // TODO debug
|
||||
renderer =
|
||||
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId();
|
||||
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId(
|
||||
nullptr);
|
||||
}
|
||||
if (isFirst) {
|
||||
lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer;
|
||||
|
|
|
|||
686
Linphone/core/chat/ChatCore.cpp
Normal file
686
Linphone/core/chat/ChatCore.cpp
Normal file
|
|
@ -0,0 +1,686 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentGui.hpp"
|
||||
#include "core/friend/FriendCore.hpp"
|
||||
#include "core/setting/SettingsCore.hpp"
|
||||
#include "model/chat/message/EventLogModel.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/friend/FriendModel.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include <QQuickWindow>
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatCore)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
QSharedPointer<ChatCore> ChatCore::create(const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
|
||||
auto sharedPointer = QSharedPointer<ChatCore>(new ChatCore(chatRoom), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
ChatCore::ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom) : QObject(nullptr) {
|
||||
// lDebug() << "[ChatCore] new" << this;
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
mLastUpdatedTime = QDateTime::fromSecsSinceEpoch(chatRoom->getLastUpdateTime());
|
||||
auto chatRoomAddress = chatRoom->getPeerAddress();
|
||||
mChatRoomAddress = Utils::coreStringToAppString(chatRoomAddress->asStringUriOnly());
|
||||
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Basic)) {
|
||||
mTitle = ToolModel::getDisplayName(chatRoomAddress);
|
||||
mAvatarUri = ToolModel::getDisplayName(chatRoomAddress);
|
||||
mParticipantAddress = Utils::coreStringToAppString(chatRoomAddress->asStringUriOnly());
|
||||
mIsGroupChat = false;
|
||||
mIsBasic = true;
|
||||
mConferenceJoined = true;
|
||||
} else {
|
||||
mIsBasic = false;
|
||||
auto participants = chatRoom->getParticipants();
|
||||
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne)) {
|
||||
if (participants.size() > 0) {
|
||||
auto peer = participants.front();
|
||||
auto peerAddress = peer->getAddress();
|
||||
if (peer) mTitle = ToolModel::getDisplayName(peerAddress);
|
||||
mAvatarUri = ToolModel::getDisplayName(peerAddress);
|
||||
if (participants.size() == 1) {
|
||||
if (peerAddress) mParticipantAddress = Utils::coreStringToAppString(peerAddress->asStringUriOnly());
|
||||
}
|
||||
}
|
||||
mIsGroupChat = false;
|
||||
} else if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference)) {
|
||||
mTitle = Utils::coreStringToAppString(chatRoom->getSubject());
|
||||
mAvatarUri = Utils::coreStringToAppString(chatRoom->getSubject());
|
||||
mIsGroupChat = true;
|
||||
mMeAdmin = chatRoom->getMe() && chatRoom->getMe()->isAdmin();
|
||||
}
|
||||
mConferenceJoined = participants.size() != 0;
|
||||
}
|
||||
mUnreadMessagesCount = chatRoom->getUnreadMessagesCount();
|
||||
connect(this, &ChatCore::unreadMessagesCountChanged, this, [this] {
|
||||
if (mUnreadMessagesCount == 0) emit lMarkAsRead();
|
||||
});
|
||||
mChatModel = Utils::makeQObject_ptr<ChatModel>(chatRoom);
|
||||
mChatModel->setSelf(mChatModel);
|
||||
auto lastMessage = chatRoom->getLastMessageInHistory();
|
||||
mLastMessage = lastMessage ? ChatMessageCore::create(lastMessage) : nullptr;
|
||||
|
||||
int filter = mIsGroupChat ? static_cast<int>(linphone::ChatRoom::HistoryFilter::ChatMessage) |
|
||||
static_cast<int>(linphone::ChatRoom::HistoryFilter::InfoNoDevice)
|
||||
: static_cast<int>(linphone::ChatRoom::HistoryFilter::ChatMessage);
|
||||
|
||||
mIdentifier = Utils::coreStringToAppString(chatRoom->getIdentifier());
|
||||
mChatRoomState = LinphoneEnums::fromLinphone(chatRoom->getState());
|
||||
mIsEncrypted = chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Encrypted);
|
||||
auto localAccount = ToolModel::findAccount(chatRoom->getLocalAddress());
|
||||
mLocalAddress = Utils::coreStringToAppString(chatRoom->getLocalAddress()->asStringUriOnly());
|
||||
bool associatedAccountHasIMEncryptionMandatory =
|
||||
localAccount && localAccount->getParams() &&
|
||||
localAccount->getParams()->getInstantMessagingEncryptionMandatory();
|
||||
mIsReadOnly = chatRoom->isReadOnly() || (!mIsEncrypted && associatedAccountHasIMEncryptionMandatory);
|
||||
|
||||
connect(this, &ChatCore::eventsInserted, this, &ChatCore::lUpdateLastMessage);
|
||||
|
||||
mEphemeralEnabled = chatRoom->ephemeralEnabled();
|
||||
mEphemeralLifetime = chatRoom->ephemeralEnabled() ? chatRoom->getEphemeralLifetime() : 0;
|
||||
mIsMuted = chatRoom->getMuted();
|
||||
mParticipants = buildParticipants(chatRoom);
|
||||
|
||||
connect(this, &ChatCore::participantsChanged, this, [this] {
|
||||
// refresh secured status of the chatroom
|
||||
setIsSecured(computeSecuredStatus());
|
||||
});
|
||||
mIsSecured = computeSecuredStatus();
|
||||
}
|
||||
|
||||
ChatCore::~ChatCore() {
|
||||
lDebug() << "[ChatCore] delete" << this;
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
if (mChatModelConnection) mChatModelConnection->disconnect();
|
||||
emit mChatModel->removeListener();
|
||||
}
|
||||
|
||||
void ChatCore::setSelf(QSharedPointer<ChatCore> me) {
|
||||
mChatModelConnection = SafeConnection<ChatCore, ChatModel>::create(me, mChatModel);
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lDeleteHistory, [this]() {
|
||||
mChatModelConnection->invokeToModel([this]() { mChatModel->deleteHistory(); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lDeleteMessage, [this](ChatMessageGui *message) {
|
||||
mChatModelConnection->invokeToModel([this, core = message ? message->mCore : nullptr]() {
|
||||
auto messageModel = core ? core->getModel() : nullptr;
|
||||
if (messageModel) {
|
||||
mChatModel->deleteMessage(messageModel->getMonitor());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(
|
||||
&ChatCore::lLeave, [this]() { mChatModelConnection->invokeToModel([this]() { mChatModel->leave(); }); });
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::historyDeleted, [this]() {
|
||||
mChatModelConnection->invokeToCore([this]() {
|
||||
emit eventListCleared();
|
||||
//: Deleted
|
||||
Utils::showInformationPopup(tr("info_toast_deleted_title"),
|
||||
//: Message history has been deleted
|
||||
tr("info_toast_deleted_message_history"), true);
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateUnreadCount, [this]() {
|
||||
mChatModelConnection->invokeToModel([this]() {
|
||||
auto count = mChatModel->getUnreadMessagesCount();
|
||||
mChatModelConnection->invokeToCore([this, count] { setUnreadMessagesCount(count); });
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateLastUpdatedTime, [this]() {
|
||||
mChatModelConnection->invokeToModel([this]() {
|
||||
auto time = mChatModel->getLastUpdateTime();
|
||||
mChatModelConnection->invokeToCore([this, time]() { setLastUpdatedTime(time); });
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lDelete, [this]() {
|
||||
mChatModelConnection->invokeToModel([this]() { mChatModel->deleteChatRoom(); });
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::stateChanged,
|
||||
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom, linphone::ChatRoom::State newState) {
|
||||
auto state = LinphoneEnums::fromLinphone(newState);
|
||||
bool isReadOnly = chatRoom->isReadOnly();
|
||||
if (newState == linphone::ChatRoom::State::Deleted) emit deleted();
|
||||
mChatModelConnection->invokeToCore([this, state, isReadOnly]() {
|
||||
setChatRoomState(state);
|
||||
setIsReadOnly(isReadOnly);
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::conferenceJoined, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
auto participants = buildParticipants(chatRoom);
|
||||
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne)) {
|
||||
QString title, avatarUri;
|
||||
auto linParticipants = chatRoom->getParticipants();
|
||||
if (linParticipants.size() > 0) {
|
||||
auto peer = linParticipants.front();
|
||||
if (peer) title = ToolModel::getDisplayName(peer->getAddress());
|
||||
avatarUri = ToolModel::getDisplayName(peer->getAddress());
|
||||
if (linParticipants.size() == 1) {
|
||||
auto peerAddress = peer->getAddress();
|
||||
if (peerAddress)
|
||||
mParticipantAddress = Utils::coreStringToAppString(peerAddress->asStringUriOnly());
|
||||
}
|
||||
}
|
||||
mChatModelConnection->invokeToCore([this, title, avatarUri]() {
|
||||
setTitle(title);
|
||||
setAvatarUri(avatarUri);
|
||||
mConferenceJoined = true;
|
||||
emit conferenceJoined();
|
||||
});
|
||||
}
|
||||
mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
|
||||
});
|
||||
|
||||
// Events (excluding messages)
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::newEvent, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
if (mChatModel->getMonitor() != chatRoom) return;
|
||||
lDebug() << "EVENT LOG RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
||||
auto event = EventLogCore::create(eventLog, chatRoom);
|
||||
if (event->isHandled()) {
|
||||
mChatModelConnection->invokeToCore([this, event]() { emit eventsInserted({event}); });
|
||||
}
|
||||
mChatModelConnection->invokeToCore([this, event]() { emit lUpdateLastUpdatedTime(); });
|
||||
});
|
||||
|
||||
// Chat messages
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::chatMessagesReceived, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::list<std::shared_ptr<linphone::EventLog>> &eventsLog) {
|
||||
if (mChatModel->getMonitor() != chatRoom) return;
|
||||
lDebug() << "CHAT MESSAGE RECEIVED IN CHATROOM" << mChatModel->getTitle();
|
||||
QList<QSharedPointer<EventLogCore>> list;
|
||||
for (auto &e : eventsLog) {
|
||||
auto event = EventLogCore::create(e, chatRoom);
|
||||
list.push_back(event);
|
||||
}
|
||||
mChatModelConnection->invokeToCore([this, list]() {
|
||||
emit eventsInserted(list);
|
||||
emit lUpdateUnreadCount();
|
||||
emit lUpdateLastUpdatedTime();
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lMarkAsRead, [this]() {
|
||||
auto lastActiveWindow = Utils::getLastActiveWindow();
|
||||
if (lastActiveWindow && lastActiveWindow->isActive())
|
||||
mChatModelConnection->invokeToModel([this]() { mChatModel->markAsRead(); });
|
||||
else {
|
||||
connect(lastActiveWindow, &QQuickWindow::activeChanged, this, [this, lastActiveWindow] {
|
||||
if (lastActiveWindow->isActive()) {
|
||||
disconnect(lastActiveWindow, &QQuickWindow::activeChanged, this, nullptr);
|
||||
mChatModelConnection->invokeToModel([this, lastActiveWindow] { mChatModel->markAsRead(); });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::messagesRead, [this]() {
|
||||
auto unread = mChatModel->getUnreadMessagesCount();
|
||||
mChatModelConnection->invokeToCore([this, unread]() { setUnreadMessagesCount(unread); });
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lUpdateLastMessage, [this]() {
|
||||
auto lastMessageModel = mLastMessage ? mLastMessage->getModel() : nullptr;
|
||||
mChatModelConnection->invokeToModel([this, lastMessageModel]() {
|
||||
auto linphoneMessage = mChatModel->getLastChatMessage();
|
||||
if (linphoneMessage && (!lastMessageModel || lastMessageModel->getMonitor() != linphoneMessage)) {
|
||||
auto chatMessageCore = ChatMessageCore::create(linphoneMessage);
|
||||
mChatModelConnection->invokeToCore([this, chatMessageCore]() { setLastMessage(chatMessageCore); });
|
||||
}
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSendTextMessage, [this](QString message) {
|
||||
if (Utils::isEmptyMessage(message)) return;
|
||||
mChatModelConnection->invokeToModel([this, message]() {
|
||||
auto linMessage = mChatModel->createTextMessageFromText(message);
|
||||
linMessage->send();
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSendMessage, [this](QString message, QVariantList files) {
|
||||
if (Utils::isEmptyMessage(message) && files.size() == 0) return;
|
||||
QList<std::shared_ptr<ChatMessageContentModel>> filesContent;
|
||||
for (auto &file : files) {
|
||||
auto contentGui = qvariant_cast<ChatMessageContentGui *>(file);
|
||||
if (contentGui) {
|
||||
auto contentCore = contentGui->mCore;
|
||||
filesContent.append(contentCore->getContentModel());
|
||||
}
|
||||
}
|
||||
mChatModelConnection->invokeToModel([this, message, filesContent]() {
|
||||
auto linMessage = mChatModel->createMessage(message, filesContent);
|
||||
linMessage->send();
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::chatMessageSending, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
auto event = EventLogCore::create(eventLog, chatRoom);
|
||||
mChatModelConnection->invokeToCore([this, event]() { emit eventsInserted({event}); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(
|
||||
&ChatCore::lCompose, [this]() { mChatModelConnection->invokeToModel([this]() { mChatModel->compose(); }); });
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::isComposingReceived,
|
||||
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::Address> &remoteAddress, bool isComposing) {
|
||||
if (mChatModel->getMonitor() != chatRoom) return;
|
||||
QString name = isComposing ? ToolModel::getDisplayName(remoteAddress) : QString();
|
||||
auto remoteAddr = remoteAddress;
|
||||
// remoteAddr->clean();
|
||||
mChatModelConnection->invokeToCore(
|
||||
[this, name, address = Utils::coreStringToAppString(remoteAddr->asStringUriOnly())]() {
|
||||
setComposingName(name);
|
||||
setComposingAddress(address);
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSetMuted, [this](bool muted) {
|
||||
mChatModelConnection->invokeToModel([this, muted]() { mChatModel->setMuted(muted); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::mutedChanged, [this](bool muted) {
|
||||
mChatModelConnection->invokeToCore([this, muted]() {
|
||||
if (mIsMuted != muted) {
|
||||
mIsMuted = muted;
|
||||
emit mutedChanged();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lEnableEphemeral, [this](bool enable) {
|
||||
mChatModelConnection->invokeToModel([this, enable]() { mChatModel->enableEphemeral(enable); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::ephemeralEnableChanged, [this](bool enable) {
|
||||
mChatModelConnection->invokeToCore([this, enable]() {
|
||||
if (mEphemeralEnabled != enable) {
|
||||
mEphemeralEnabled = enable;
|
||||
emit ephemeralEnabledChanged();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSetEphemeralLifetime, [this](int time) {
|
||||
mChatModelConnection->invokeToModel([this, time]() { mChatModel->setEphemeralLifetime(time); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::ephemeralLifetimeChanged, [this](int time) {
|
||||
mChatModelConnection->invokeToCore([this, time]() {
|
||||
if (mEphemeralLifetime != time) {
|
||||
mEphemeralLifetime = time;
|
||||
emit ephemeralLifetimeChanged();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSetSubject, [this](QString subject) {
|
||||
mChatModelConnection->invokeToModel([this, subject]() { mChatModel->setSubject(subject); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::subjectChanged, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
QString subject = Utils::coreStringToAppString(chatRoom->getSubject());
|
||||
mChatModelConnection->invokeToCore([this, subject]() { setTitle(subject); });
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::participantAdded, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
auto participants = buildParticipants(chatRoom);
|
||||
mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(
|
||||
&ChatModel::participantRemoved, [this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
auto participants = buildParticipants(chatRoom);
|
||||
mChatModelConnection->invokeToCore([this, participants]() { setParticipants(participants); });
|
||||
});
|
||||
mChatModelConnection->makeConnectToModel(&ChatModel::participantAdminStatusChanged,
|
||||
[this](const std::shared_ptr<linphone::ChatRoom> &chatRoom,
|
||||
const std::shared_ptr<const linphone::EventLog> &eventLog) {
|
||||
auto participants = buildParticipants(chatRoom);
|
||||
bool meAdmin = chatRoom->getMe()->isAdmin();
|
||||
mChatModelConnection->invokeToCore([this, participants, meAdmin]() {
|
||||
setParticipants(participants);
|
||||
setMeAdmin(meAdmin);
|
||||
});
|
||||
});
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lRemoveParticipantAtIndex, [this](int index) {
|
||||
mChatModelConnection->invokeToModel([this, index]() { mChatModel->removeParticipantAtIndex(index); });
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lSetParticipantsAddresses, [this](QStringList addresses) {
|
||||
mChatModelConnection->invokeToModel([this, addresses]() { mChatModel->setParticipantAddresses(addresses); });
|
||||
});
|
||||
|
||||
mChatModelConnection->makeConnectToCore(&ChatCore::lToggleParticipantAdminStatusAtIndex, [this](int index) {
|
||||
mChatModelConnection->invokeToModel(
|
||||
[this, index]() { mChatModel->toggleParticipantAdminStatusAtIndex(index); });
|
||||
});
|
||||
|
||||
mCoreModelConnection = SafeConnection<ChatCore, CoreModel>::create(me, CoreModel::getInstance());
|
||||
if (!ToolModel::findFriendByAddress(mParticipantAddress))
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::friendCreated,
|
||||
[this](std::shared_ptr<linphone::Friend> f) { updateInfo(f); });
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::friendUpdated,
|
||||
[this](std::shared_ptr<linphone::Friend> f) { updateInfo(f); });
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved,
|
||||
[this](std::shared_ptr<linphone::Friend> f) { updateInfo(f, true); });
|
||||
|
||||
}
|
||||
|
||||
QDateTime ChatCore::getLastUpdatedTime() const {
|
||||
return mLastUpdatedTime;
|
||||
}
|
||||
|
||||
void ChatCore::setLastUpdatedTime(QDateTime time) {
|
||||
if (mLastUpdatedTime != time) {
|
||||
mLastUpdatedTime = time;
|
||||
emit lastUpdatedTimeChanged(time);
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatCore::getTitle() const {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
void ChatCore::setTitle(QString title) {
|
||||
if (mTitle != title) {
|
||||
mTitle = title;
|
||||
emit titleChanged(title);
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatCore::getSendingText() const {
|
||||
return mSendingText;
|
||||
}
|
||||
|
||||
void ChatCore::setSendingText(const QString &text) {
|
||||
if (mSendingText != text) {
|
||||
mSendingText = text;
|
||||
emit sendingTextChanged(text);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatCore::isGroupChat() const {
|
||||
return mIsGroupChat;
|
||||
}
|
||||
|
||||
bool ChatCore::isEncrypted() const {
|
||||
return mIsEncrypted;
|
||||
}
|
||||
|
||||
QString ChatCore::getIdentifier() const {
|
||||
return mIdentifier;
|
||||
}
|
||||
|
||||
QString ChatCore::getParticipantAddress() const {
|
||||
return mParticipantAddress;
|
||||
}
|
||||
|
||||
QString ChatCore::getChatRoomAddress() const {
|
||||
return mChatRoomAddress;
|
||||
}
|
||||
|
||||
QString ChatCore::getAvatarUri() const {
|
||||
return mAvatarUri;
|
||||
}
|
||||
|
||||
void ChatCore::setAvatarUri(QString avatarUri) {
|
||||
if (mAvatarUri != avatarUri) {
|
||||
mAvatarUri = avatarUri;
|
||||
emit avatarUriChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatCore::getLastMessageText() const {
|
||||
return mLastMessage ? mLastMessage->getText() : QString();
|
||||
}
|
||||
|
||||
LinphoneEnums::ChatMessageState ChatCore::getLastMessageState() const {
|
||||
return mLastMessage ? mLastMessage->getMessageState() : LinphoneEnums::ChatMessageState::StateIdle;
|
||||
}
|
||||
|
||||
LinphoneEnums::ChatRoomState ChatCore::getChatRoomState() const {
|
||||
return mChatRoomState;
|
||||
}
|
||||
|
||||
void ChatCore::setChatRoomState(LinphoneEnums::ChatRoomState state) {
|
||||
if (mChatRoomState != state) {
|
||||
mChatRoomState = state;
|
||||
emit chatRoomStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatCore::setIsReadOnly(bool readOnly) {
|
||||
if (mIsReadOnly != readOnly) {
|
||||
mIsReadOnly = readOnly;
|
||||
emit readOnlyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatCore::getIsReadOnly() const {
|
||||
return mIsReadOnly;
|
||||
}
|
||||
|
||||
ChatMessageGui *ChatCore::getLastMessage() const {
|
||||
return mLastMessage ? new ChatMessageGui(mLastMessage) : nullptr;
|
||||
}
|
||||
|
||||
void ChatCore::setLastMessage(QSharedPointer<ChatMessageCore> lastMessage) {
|
||||
if (mLastMessage != lastMessage) {
|
||||
if (mLastMessage) disconnect(mLastMessage.get(), &ChatMessageCore::messageStateChanged, this, nullptr);
|
||||
mLastMessage = lastMessage;
|
||||
connect(mLastMessage.get(), &ChatMessageCore::messageStateChanged, this, &ChatCore::lastMessageChanged);
|
||||
emit lastMessageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int ChatCore::getUnreadMessagesCount() const {
|
||||
return mUnreadMessagesCount;
|
||||
}
|
||||
|
||||
void ChatCore::setUnreadMessagesCount(int count) {
|
||||
if (mUnreadMessagesCount != count) {
|
||||
mUnreadMessagesCount = count;
|
||||
emit unreadMessagesCountChanged(count);
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatCore::getComposingName() const {
|
||||
return mComposingName;
|
||||
}
|
||||
|
||||
void ChatCore::setComposingName(QString composingName) {
|
||||
if (mComposingAddress != composingName) {
|
||||
mComposingName = composingName;
|
||||
emit composingUserChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatCore::setComposingAddress(QString composingAddress) {
|
||||
if (mComposingAddress != composingAddress) {
|
||||
mComposingAddress = composingAddress;
|
||||
emit composingUserChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatCore::getComposingAddress() const {
|
||||
return mComposingAddress;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ChatMessageContentCore>> ChatCore::getFileList() const {
|
||||
return mFileList;
|
||||
}
|
||||
|
||||
void ChatCore::resetFileList(QList<QSharedPointer<ChatMessageContentCore>> list) {
|
||||
mFileList = list;
|
||||
emit fileListChanged();
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatModel> ChatCore::getModel() const {
|
||||
return mChatModel;
|
||||
}
|
||||
|
||||
bool ChatCore::isMuted() const {
|
||||
return mIsMuted;
|
||||
}
|
||||
|
||||
bool ChatCore::isEphemeralEnabled() const {
|
||||
return mEphemeralEnabled;
|
||||
}
|
||||
|
||||
int ChatCore::getEphemeralLifetime() const {
|
||||
return mEphemeralLifetime;
|
||||
}
|
||||
|
||||
void ChatCore::setMeAdmin(bool admin) {
|
||||
if (mMeAdmin != admin) {
|
||||
mMeAdmin = admin;
|
||||
emit meAdminChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatCore::getMeAdmin() const {
|
||||
return mMeAdmin;
|
||||
}
|
||||
|
||||
bool ChatCore::isSecured() const {
|
||||
return mIsSecured;
|
||||
}
|
||||
|
||||
void ChatCore::setIsSecured(bool secured) {
|
||||
if (mIsSecured != secured) {
|
||||
mIsSecured = secured;
|
||||
emit isSecuredChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatCore::computeSecuredStatus() const {
|
||||
if (mParticipants.size() == 0) return false;
|
||||
for (auto &participant : mParticipants) {
|
||||
if (participant->getSecurityLevel() != LinphoneEnums::SecurityLevel::EndToEndEncryptedAndVerified) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QVariantList ChatCore::getParticipantsGui() const {
|
||||
QVariantList result;
|
||||
for (auto participantCore : mParticipants) {
|
||||
auto participantGui = new ParticipantGui(participantCore);
|
||||
result.append(QVariant::fromValue(participantGui));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList ChatCore::getParticipantsAddresses() const {
|
||||
QStringList result;
|
||||
for (auto participantCore : mParticipants) {
|
||||
result.append(participantCore->getSipAddress());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ChatCore::setParticipants(QList<QSharedPointer<ParticipantCore>> participants) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
mParticipants = participants;
|
||||
emit participantsChanged();
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ParticipantCore>>
|
||||
ChatCore::buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
QList<QSharedPointer<ParticipantCore>> result;
|
||||
for (auto participant : chatRoom->getParticipants()) {
|
||||
auto participantCore = ParticipantCore::create(participant);
|
||||
result.append(participantCore);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ParticipantCore>> ChatCore::getParticipants() const {
|
||||
return mParticipants;
|
||||
}
|
||||
|
||||
QString ChatCore::getLocalAddress() const {
|
||||
return mLocalAddress;
|
||||
}
|
||||
|
||||
void ChatCore::updateInfo(const std::shared_ptr<linphone::Friend> &updatedFriend, bool isRemoval) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto fAddress = ToolModel::interpretUrl(mParticipantAddress);
|
||||
bool isThisFriend = mFriendModel && updatedFriend == mFriendModel->getFriend();
|
||||
if (!isThisFriend)
|
||||
for (auto f : updatedFriend->getAddresses()) {
|
||||
if (f->weakEqual(fAddress)) {
|
||||
isThisFriend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isThisFriend) {
|
||||
if (isRemoval) {
|
||||
mFriendModel = nullptr;
|
||||
}
|
||||
int capabilities = mChatModel->getCapabilities();
|
||||
auto chatroom = mChatModel->getMonitor();
|
||||
auto chatRoomAddress = chatroom->getPeerAddress();
|
||||
if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::Basic)) {
|
||||
auto title = ToolModel::getDisplayName(chatRoomAddress);
|
||||
auto avatarUri = ToolModel::getDisplayName(chatRoomAddress);
|
||||
mChatModelConnection->invokeToCore([this, title, avatarUri] {
|
||||
setTitle(title);
|
||||
setAvatarUri(avatarUri);
|
||||
});
|
||||
} else {
|
||||
if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne)) {
|
||||
auto participants = chatroom->getParticipants();
|
||||
if (participants.size() > 0) {
|
||||
auto peer = participants.front();
|
||||
if (peer) {
|
||||
auto title = ToolModel::getDisplayName(peer->getAddress());
|
||||
auto avatarUri = ToolModel::getDisplayName(peer->getAddress());
|
||||
mChatModelConnection->invokeToCore([this, title, avatarUri] {
|
||||
setTitle(title);
|
||||
setAvatarUri(avatarUri);
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (mChatModel->hasCapability((int)linphone::ChatRoom::Capabilities::Conference)) {
|
||||
auto title = Utils::coreStringToAppString(chatroom->getSubject());
|
||||
auto avatarUri = Utils::coreStringToAppString(chatroom->getSubject());
|
||||
mChatModelConnection->invokeToCore([this, title, avatarUri] {
|
||||
setTitle(title);
|
||||
setAvatarUri(avatarUri);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
236
Linphone/core/chat/ChatCore.hpp
Normal file
236
Linphone/core/chat/ChatCore.hpp
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_CORE_H_
|
||||
#define CHAT_CORE_H_
|
||||
|
||||
#include "core/chat/message/EventLogGui.hpp"
|
||||
#include "core/participant/ParticipantCore.hpp"
|
||||
#include "message/ChatMessageGui.hpp"
|
||||
#include "model/chat/ChatModel.hpp"
|
||||
#include "model/search/MagicSearchModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
class EventLogCore;
|
||||
class FriendModel;
|
||||
class AccountCore;
|
||||
|
||||
class ChatCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Q_PROPERTY(QString title READ getTitle WRITE setTitle NOTIFY titleChanged)
|
||||
Q_PROPERTY(QString identifier READ getIdentifier CONSTANT)
|
||||
Q_PROPERTY(QString peerAddress READ getParticipantAddress CONSTANT)
|
||||
Q_PROPERTY(QString chatRoomAddress READ getChatRoomAddress CONSTANT)
|
||||
Q_PROPERTY(QString avatarUri READ getAvatarUri WRITE setAvatarUri NOTIFY avatarUriChanged)
|
||||
Q_PROPERTY(QDateTime lastUpdatedTime READ getLastUpdatedTime WRITE setLastUpdatedTime NOTIFY lastUpdatedTimeChanged)
|
||||
Q_PROPERTY(QString lastMessageText READ getLastMessageText NOTIFY lastMessageChanged)
|
||||
Q_PROPERTY(ChatMessageGui *lastMessage READ getLastMessage NOTIFY lastMessageChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ChatMessageState lastMessageState READ getLastMessageState NOTIFY lastMessageChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ChatRoomState state READ getChatRoomState NOTIFY chatRoomStateChanged)
|
||||
Q_PROPERTY(int unreadMessagesCount READ getUnreadMessagesCount WRITE setUnreadMessagesCount NOTIFY
|
||||
unreadMessagesCountChanged)
|
||||
Q_PROPERTY(QString composingName READ getComposingName WRITE setComposingName NOTIFY composingUserChanged)
|
||||
Q_PROPERTY(QString composingAddress READ getComposingAddress WRITE setComposingAddress NOTIFY composingUserChanged)
|
||||
Q_PROPERTY(bool isGroupChat READ isGroupChat CONSTANT)
|
||||
Q_PROPERTY(bool isEncrypted READ isEncrypted CONSTANT)
|
||||
Q_PROPERTY(bool isReadOnly READ getIsReadOnly WRITE setIsReadOnly NOTIFY readOnlyChanged)
|
||||
Q_PROPERTY(bool isSecured READ isSecured WRITE setIsSecured NOTIFY isSecuredChanged)
|
||||
Q_PROPERTY(bool isBasic MEMBER mIsBasic CONSTANT)
|
||||
Q_PROPERTY(QString sendingText READ getSendingText WRITE setSendingText NOTIFY sendingTextChanged)
|
||||
Q_PROPERTY(bool ephemeralEnabled READ isEphemeralEnabled WRITE lEnableEphemeral NOTIFY ephemeralEnabledChanged)
|
||||
Q_PROPERTY(
|
||||
int ephemeralLifetime READ getEphemeralLifetime WRITE lSetEphemeralLifetime NOTIFY ephemeralLifetimeChanged)
|
||||
Q_PROPERTY(bool muted READ isMuted WRITE lSetMuted NOTIFY mutedChanged)
|
||||
Q_PROPERTY(bool meAdmin READ getMeAdmin WRITE setMeAdmin NOTIFY meAdminChanged)
|
||||
Q_PROPERTY(QVariantList participants READ getParticipantsGui NOTIFY participantsChanged)
|
||||
Q_PROPERTY(QStringList participantsAddresses READ getParticipantsAddresses WRITE lSetParticipantsAddresses NOTIFY
|
||||
participantsChanged)
|
||||
Q_PROPERTY(QList<QSharedPointer<ChatMessageContentCore>> fileList READ getFileList NOTIFY fileListChanged)
|
||||
|
||||
// Should be call from model Thread. Will be automatically in App thread after initialization
|
||||
static QSharedPointer<ChatCore> create(const std::shared_ptr<linphone::ChatRoom> &chatRoom);
|
||||
ChatCore(const std::shared_ptr<linphone::ChatRoom> &chatRoom);
|
||||
~ChatCore();
|
||||
void setSelf(QSharedPointer<ChatCore> me);
|
||||
|
||||
QDateTime getLastUpdatedTime() const;
|
||||
void setLastUpdatedTime(QDateTime time);
|
||||
|
||||
QString getTitle() const;
|
||||
void setTitle(QString title);
|
||||
|
||||
bool isGroupChat() const;
|
||||
|
||||
bool isEncrypted() const;
|
||||
|
||||
bool isMuted() const;
|
||||
|
||||
bool isEphemeralEnabled() const;
|
||||
int getEphemeralLifetime() const;
|
||||
|
||||
QString getIdentifier() const;
|
||||
|
||||
QString getSendingText() const;
|
||||
void setSendingText(const QString &text);
|
||||
|
||||
ChatMessageGui *getLastMessage() const;
|
||||
QString getLastMessageText() const;
|
||||
|
||||
QList<QSharedPointer<ChatMessageContentCore>> getFileList() const;
|
||||
void resetFileList(QList<QSharedPointer<ChatMessageContentCore>> list);
|
||||
|
||||
LinphoneEnums::ChatMessageState getLastMessageState() const;
|
||||
|
||||
LinphoneEnums::ChatRoomState getChatRoomState() const;
|
||||
void setChatRoomState(LinphoneEnums::ChatRoomState state);
|
||||
|
||||
bool getIsReadOnly() const;
|
||||
void setIsReadOnly(bool readOnly);
|
||||
|
||||
QSharedPointer<ChatMessageCore> getLastMessageCore() const;
|
||||
void setLastMessage(QSharedPointer<ChatMessageCore> lastMessage);
|
||||
|
||||
int getUnreadMessagesCount() const;
|
||||
void setUnreadMessagesCount(int count);
|
||||
|
||||
QString getChatRoomAddress() const;
|
||||
QString getParticipantAddress() const;
|
||||
|
||||
bool getMeAdmin() const;
|
||||
void setMeAdmin(bool admin);
|
||||
|
||||
bool isSecured() const;
|
||||
void setIsSecured(bool secured);
|
||||
bool computeSecuredStatus() const;
|
||||
|
||||
// void resetEventLogList(QList<QSharedPointer<EventLogCore>> list);
|
||||
// void appendEventLogToEventLogList(QSharedPointer<EventLogCore> event);
|
||||
// void appendEventLogsToEventLogList(QList<QSharedPointer<EventLogCore>> list);
|
||||
// void removeEventLogsFromEventLogList(QList<QSharedPointer<EventLogCore>> list);
|
||||
// void clearEventLogList();
|
||||
|
||||
QString getAvatarUri() const;
|
||||
void setAvatarUri(QString avatarUri);
|
||||
|
||||
QString getComposingName() const;
|
||||
QString getComposingAddress() const;
|
||||
void setComposingName(QString composingName);
|
||||
void setComposingAddress(QString composingAddress);
|
||||
|
||||
std::shared_ptr<ChatModel> getModel() const;
|
||||
|
||||
void setParticipants(QList<QSharedPointer<ParticipantCore>> participants);
|
||||
QList<QSharedPointer<ParticipantCore>> buildParticipants(const std::shared_ptr<linphone::ChatRoom> &chatRoom) const;
|
||||
QList<QSharedPointer<ParticipantCore>> getParticipants() const;
|
||||
QVariantList getParticipantsGui() const;
|
||||
QStringList getParticipantsAddresses() const;
|
||||
|
||||
QString getLocalAddress() const;
|
||||
|
||||
void updateInfo(const std::shared_ptr<linphone::Friend> &updatedFriend, bool isRemoval = false);
|
||||
|
||||
signals:
|
||||
// used to close all the notifications when one is clicked
|
||||
void messageOpen();
|
||||
void lastUpdatedTimeChanged(QDateTime time);
|
||||
void lastMessageChanged();
|
||||
void titleChanged(QString title);
|
||||
void unreadMessagesCountChanged(int count);
|
||||
void eventListCleared();
|
||||
void eventsInserted(QList<QSharedPointer<EventLogCore>> list);
|
||||
void avatarUriChanged();
|
||||
void deleted();
|
||||
void composingUserChanged();
|
||||
void chatRoomStateChanged();
|
||||
void readOnlyChanged();
|
||||
void sendingTextChanged(QString text);
|
||||
void mutedChanged();
|
||||
void ephemeralEnabledChanged();
|
||||
void ephemeralLifetimeChanged();
|
||||
void meAdminChanged();
|
||||
void participantsChanged();
|
||||
void fileListChanged();
|
||||
void isSecuredChanged();
|
||||
void conferenceJoined();
|
||||
|
||||
void lDeleteMessage(ChatMessageGui *message);
|
||||
void lDelete();
|
||||
void lDeleteHistory();
|
||||
void lMarkAsRead();
|
||||
void lUpdateLastMessage();
|
||||
void lUpdateUnreadCount();
|
||||
void lUpdateLastUpdatedTime();
|
||||
void lSendTextMessage(QString message);
|
||||
void lSendMessage(QString message, QVariantList files);
|
||||
void lSendVoiceMessage();
|
||||
void lCompose();
|
||||
void lLeave();
|
||||
void lSetMuted(bool muted);
|
||||
void lEnableEphemeral(bool enable);
|
||||
void lSetEphemeralLifetime(int time);
|
||||
void lSetSubject(QString subject);
|
||||
void lRemoveParticipantAtIndex(int index);
|
||||
void lSetParticipantsAddresses(QStringList addresses);
|
||||
void lToggleParticipantAdminStatusAtIndex(int index);
|
||||
|
||||
private:
|
||||
QString id;
|
||||
QDateTime mLastUpdatedTime;
|
||||
QString mParticipantAddress;
|
||||
QString mChatRoomAddress;
|
||||
QString mTitle;
|
||||
QString mIdentifier;
|
||||
QString mAvatarUri;
|
||||
QString mSendingText;
|
||||
int mUnreadMessagesCount;
|
||||
QString mComposingName;
|
||||
QString mComposingAddress;
|
||||
QString mLocalAddress;
|
||||
bool mIsGroupChat = false;
|
||||
bool mIsEncrypted = false;
|
||||
bool mIsReadOnly = false;
|
||||
bool mEphemeralEnabled = false;
|
||||
// ChatRoom is secured if all its participants are
|
||||
// EndToEndEncryptedAndVerified friends
|
||||
bool mIsSecured = false;
|
||||
bool mIsBasic = false;
|
||||
int mEphemeralLifetime = 0;
|
||||
QList<QSharedPointer<ChatMessageContentCore>> mFileList;
|
||||
bool mIsMuted = false;
|
||||
bool mMeAdmin = false;
|
||||
bool mConferenceJoined = false;
|
||||
QList<QSharedPointer<ParticipantCore>> mParticipants;
|
||||
LinphoneEnums::ChatRoomState mChatRoomState;
|
||||
std::shared_ptr<ChatModel> mChatModel;
|
||||
QSharedPointer<ChatMessageCore> mLastMessage;
|
||||
std::shared_ptr<FriendModel> mFriendModel;
|
||||
QSharedPointer<SafeConnection<ChatCore, ChatModel>> mChatModelConnection;
|
||||
QSharedPointer<SafeConnection<ChatCore, CoreModel>> mCoreModelConnection;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
Q_DECLARE_METATYPE(ChatCore *)
|
||||
#endif
|
||||
38
Linphone/core/chat/ChatGui.cpp
Normal file
38
Linphone/core/chat/ChatGui.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatGui)
|
||||
|
||||
ChatGui::ChatGui(QSharedPointer<ChatCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
ChatGui::~ChatGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
ChatCore *ChatGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
41
Linphone/core/chat/ChatGui.hpp
Normal file
41
Linphone/core/chat/ChatGui.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_GUI_H_
|
||||
#define CHAT_GUI_H_
|
||||
|
||||
#include "ChatCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class ChatGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ChatCore *core READ getCore CONSTANT)
|
||||
|
||||
public:
|
||||
ChatGui(QSharedPointer<ChatCore> core);
|
||||
~ChatGui();
|
||||
ChatCore *getCore() const;
|
||||
QSharedPointer<ChatCore> mCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
209
Linphone/core/chat/ChatList.cpp
Normal file
209
Linphone/core/chat/ChatList.cpp
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatList.hpp"
|
||||
#include "ChatCore.hpp"
|
||||
#include "ChatGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatList)
|
||||
|
||||
QSharedPointer<ChatList> ChatList::create() {
|
||||
auto model = QSharedPointer<ChatList>(new ChatList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
model->setSelf(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
QSharedPointer<ChatCore> ChatList::createChatCore(const std::shared_ptr<linphone::ChatRoom> &chatroom) {
|
||||
auto chatCore = ChatCore::create(chatroom);
|
||||
return chatCore;
|
||||
}
|
||||
|
||||
ChatList::ChatList(QObject *parent) : ListProxy(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ChatList::~ChatList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
mModelConnection = nullptr;
|
||||
}
|
||||
|
||||
void ChatList::connectItem(QSharedPointer<ChatCore> chat) {
|
||||
connect(
|
||||
chat.get(), &ChatCore::deleted, this,
|
||||
[this, chat] {
|
||||
disconnect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, nullptr);
|
||||
disconnect(chat.get(), &ChatCore::lastUpdatedTimeChanged, this, nullptr);
|
||||
disconnect(chat.get(), &ChatCore::lastMessageChanged, this, nullptr);
|
||||
remove(chat);
|
||||
},
|
||||
Qt::SingleShotConnection);
|
||||
auto dataChange = [this, chat] {
|
||||
int i = -1;
|
||||
get(chat.get(), &i);
|
||||
if (i != -1) {
|
||||
auto modelIndex = index(i);
|
||||
emit dataChanged(modelIndex, modelIndex);
|
||||
}
|
||||
};
|
||||
connect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, [this, dataChange] {
|
||||
dataChange();
|
||||
auto defaultAccount = App::getInstance()->getAccountList()->getDefaultAccountCore();
|
||||
if (defaultAccount) emit defaultAccount->lRefreshNotifications();
|
||||
});
|
||||
connect(chat.get(), &ChatCore::lastUpdatedTimeChanged, this, dataChange);
|
||||
connect(chat.get(), &ChatCore::lastMessageChanged, this, dataChange);
|
||||
}
|
||||
|
||||
void ChatList::setSelf(QSharedPointer<ChatList> me) {
|
||||
mModelConnection = SafeConnection<ChatList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
mModelConnection->makeConnectToCore(&ChatList::lUpdate, [this]() {
|
||||
if (mIsUpdating) {
|
||||
connect(this, &ChatList::isUpdatingChanged, this, [this] {
|
||||
if (!mIsUpdating) {
|
||||
disconnect(this, &ChatList::isUpdatingChanged, this, nullptr);
|
||||
lUpdate();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
setIsUpdating(true);
|
||||
mModelConnection->invokeToModel([this]() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
beginResetModel();
|
||||
// Avoid copy to lambdas
|
||||
QList<QSharedPointer<ChatCore>> *chats = new QList<QSharedPointer<ChatCore>>();
|
||||
auto currentAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (!currentAccount) {
|
||||
setIsUpdating(false);
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
auto linphoneChatRooms = currentAccount->filterChatRooms(Utils::appStringToCoreString(mFilter));
|
||||
for (auto it : linphoneChatRooms) {
|
||||
auto model = createChatCore(it);
|
||||
chats->push_back(model);
|
||||
}
|
||||
mModelConnection->invokeToCore([this, chats]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
for (auto &chat : getSharedList<ChatCore>()) {
|
||||
if (chat) {
|
||||
disconnect(chat.get(), &ChatCore::deleted, this, nullptr);
|
||||
disconnect(chat.get(), &ChatCore::unreadMessagesCountChanged, this, nullptr);
|
||||
disconnect(chat.get(), &ChatCore::lastUpdatedTimeChanged, this, nullptr);
|
||||
disconnect(chat.get(), &ChatCore::lastMessageChanged, this, nullptr);
|
||||
}
|
||||
}
|
||||
mList.clear();
|
||||
for (auto &chat : *chats) {
|
||||
connectItem(chat);
|
||||
}
|
||||
add(*chats);
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
delete chats;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
mModelConnection->makeConnectToModel(
|
||||
&CoreModel::defaultAccountChanged,
|
||||
[this](std::shared_ptr<linphone::Core> core, std::shared_ptr<linphone::Account> account) { lUpdate(); });
|
||||
|
||||
auto addChatToList = [this](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
if (!message) return;
|
||||
if (room->getAccount() != core->getDefaultAccount()) {
|
||||
qWarning() << log().arg("Chat room does not refer to current account, return");
|
||||
return;
|
||||
}
|
||||
auto chatCore = ChatCore::create(room);
|
||||
mModelConnection->invokeToCore([this, chatCore] { addChatInList(chatCore); });
|
||||
};
|
||||
mModelConnection->makeConnectToModel(&CoreModel::messageReceived,
|
||||
[this, addChatToList](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
addChatToList(core, room, message);
|
||||
});
|
||||
mModelConnection->makeConnectToModel(
|
||||
&CoreModel::messagesReceived,
|
||||
[this, addChatToList](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages) {
|
||||
addChatToList(core, room, messages.front());
|
||||
});
|
||||
mModelConnection->makeConnectToModel(
|
||||
&CoreModel::newMessageReaction,
|
||||
[this, addChatToList](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) {
|
||||
addChatToList(core, room, message);
|
||||
});
|
||||
|
||||
connect(this, &ChatList::filterChanged, [this](QString filter) {
|
||||
mFilter = filter;
|
||||
lUpdate();
|
||||
});
|
||||
lUpdate();
|
||||
}
|
||||
|
||||
int ChatList::findChatIndex(ChatGui *chatGui) {
|
||||
if (!chatGui) return -1;
|
||||
auto core = chatGui->mCore;
|
||||
auto chatList = getSharedList<ChatCore>();
|
||||
auto it = std::find_if(chatList.begin(), chatList.end(), [core](const QSharedPointer<ChatCore> item) {
|
||||
return item->getIdentifier() == core->getIdentifier();
|
||||
});
|
||||
return it == chatList.end() ? -1 : std::distance(chatList.begin(), it);
|
||||
}
|
||||
|
||||
bool ChatList::addChatInList(QSharedPointer<ChatCore> chatCore) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
auto chatList = getSharedList<ChatCore>();
|
||||
auto it = std::find_if(chatList.begin(), chatList.end(), [chatCore](const QSharedPointer<ChatCore> item) {
|
||||
return item && chatCore && item->getIdentifier() == chatCore->getIdentifier();
|
||||
});
|
||||
if (it == chatList.end()) {
|
||||
connectItem(chatCore);
|
||||
add(chatCore);
|
||||
emit chatAdded();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant ChatList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole) return QVariant::fromValue(new ChatGui(mList[row].objectCast<ChatCore>()));
|
||||
return QVariant();
|
||||
}
|
||||
60
Linphone/core/chat/ChatList.hpp
Normal file
60
Linphone/core/chat/ChatList.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_LIST_H_
|
||||
#define CHAT_LIST_H_
|
||||
|
||||
#include "../proxy/ListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
class ChatGui;
|
||||
class ChatCore;
|
||||
// =============================================================================
|
||||
|
||||
class ChatList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<ChatList> create();
|
||||
// Create a ChatCore and make connections to List.
|
||||
QSharedPointer<ChatCore> createChatCore(const std::shared_ptr<linphone::ChatRoom> &chatroom);
|
||||
ChatList(QObject *parent = Q_NULLPTR);
|
||||
~ChatList();
|
||||
void setSelf(QSharedPointer<ChatList> me);
|
||||
void connectItem(QSharedPointer<ChatCore> chat);
|
||||
|
||||
int findChatIndex(ChatGui *chat);
|
||||
bool addChatInList(QSharedPointer<ChatCore> chatCore);
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void lUpdate();
|
||||
void filterChanged(QString filter);
|
||||
void chatAdded();
|
||||
void chatUpdated();
|
||||
|
||||
private:
|
||||
QString mFilter;
|
||||
QSharedPointer<SafeConnection<ChatList, CoreModel>> mModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
81
Linphone/core/chat/ChatProxy.cpp
Normal file
81
Linphone/core/chat/ChatProxy.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatProxy.hpp"
|
||||
#include "ChatGui.hpp"
|
||||
#include "ChatList.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatProxy)
|
||||
|
||||
ChatProxy::ChatProxy(QObject *parent) {
|
||||
mList = ChatList::create();
|
||||
setSourceModel(mList.get());
|
||||
setDynamicSortFilter(true);
|
||||
}
|
||||
|
||||
ChatProxy::~ChatProxy() {
|
||||
}
|
||||
|
||||
void ChatProxy::setSourceModel(QAbstractItemModel *model) {
|
||||
auto oldChatList = dynamic_cast<ChatList *>(sourceModel());
|
||||
if (oldChatList) {
|
||||
disconnect(this, &ChatProxy::filterTextChanged, oldChatList, nullptr);
|
||||
disconnect(oldChatList, &ChatList::chatAdded, this, nullptr);
|
||||
disconnect(oldChatList, &ChatList::dataChanged, this, nullptr);
|
||||
}
|
||||
auto newChatList = dynamic_cast<ChatList *>(model);
|
||||
if (newChatList) {
|
||||
connect(this, &ChatProxy::filterTextChanged, newChatList,
|
||||
[this, newChatList] { emit newChatList->filterChanged(getFilterText()); });
|
||||
connect(newChatList, &ChatList::chatAdded, this, [this] { invalidate(); });
|
||||
connect(newChatList, &ChatList::dataChanged, this, [this] { invalidate(); });
|
||||
}
|
||||
QSortFilterProxyModel::setSourceModel(newChatList);
|
||||
sort(0);
|
||||
}
|
||||
|
||||
int ChatProxy::findChatIndex(ChatGui *chatGui) {
|
||||
auto chatList = dynamic_cast<ChatList *>(sourceModel());
|
||||
if (chatList) {
|
||||
auto listIndex = chatList->findChatIndex(chatGui);
|
||||
if (listIndex != -1) {
|
||||
listIndex = mapFromSource(chatList->index(listIndex, 0)).row();
|
||||
return listIndex;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ChatProxy::addChatInList(ChatGui *chatGui) {
|
||||
auto chatList = dynamic_cast<ChatList *>(sourceModel());
|
||||
if (chatList && chatGui) {
|
||||
return chatList->addChatInList(chatGui->mCore);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||
if (!mFilterText.isEmpty()) return false;
|
||||
auto l = getItemAtSource<ChatList, ChatCore>(sourceLeft.row());
|
||||
auto r = getItemAtSource<ChatList, ChatCore>(sourceRight.row());
|
||||
if (l && r) return l->getLastUpdatedTime() > r->getLastUpdatedTime();
|
||||
return false;
|
||||
}
|
||||
50
Linphone/core/chat/ChatProxy.hpp
Normal file
50
Linphone/core/chat/ChatProxy.hpp
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_PROXY_H_
|
||||
#define CHAT_PROXY_H_
|
||||
|
||||
#include "../proxy/SortFilterProxy.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
#include "core/chat/ChatList.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ChatProxy : public SortFilterProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatProxy(QObject *parent = Q_NULLPTR);
|
||||
~ChatProxy();
|
||||
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
|
||||
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
|
||||
|
||||
Q_INVOKABLE int findChatIndex(ChatGui *chatGui);
|
||||
Q_INVOKABLE bool addChatInList(ChatGui *chatGui);
|
||||
|
||||
protected:
|
||||
QSharedPointer<ChatList> mList;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
127
Linphone/core/chat/files/ChatMessageFileList.cpp
Normal file
127
Linphone/core/chat/files/ChatMessageFileList.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageFileList.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentCore.hpp"
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageFileList)
|
||||
|
||||
QSharedPointer<ChatMessageFileList> ChatMessageFileList::create() {
|
||||
auto model = QSharedPointer<ChatMessageFileList>(new ChatMessageFileList(), &QObject::deleteLater);
|
||||
model->setSelf(model);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
return model;
|
||||
}
|
||||
|
||||
ChatMessageFileList::ChatMessageFileList(QObject *parent) : ListProxy(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ChatMessageFileList::~ChatMessageFileList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
void ChatMessageFileList::setSelf(QSharedPointer<ChatMessageFileList> me) {
|
||||
mCoreModelConnection = SafeConnection<ChatMessageFileList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
mCoreModelConnection->makeConnectToCore(&ChatMessageFileList::lUpdate, [this]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
beginResetModel();
|
||||
mList.clear();
|
||||
if (!mChat) {
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
auto chatModel = mChat->getModel();
|
||||
if (!chatModel) {
|
||||
endResetModel();
|
||||
return;
|
||||
}
|
||||
mCoreModelConnection->invokeToModel([this, chatModel]() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
std::list<std::shared_ptr<linphone::Content>> medias;
|
||||
std::list<std::shared_ptr<linphone::Content>> docs;
|
||||
QList<QSharedPointer<ChatMessageContentCore>> *contents =
|
||||
new QList<QSharedPointer<ChatMessageContentCore>>();
|
||||
if (mFilterType == (int)FilterContentType::Medias) {
|
||||
medias = chatModel->getSharedMedias();
|
||||
} else if (mFilterType == (int)FilterContentType::Documents) {
|
||||
docs = chatModel->getSharedDocuments();
|
||||
} else {
|
||||
medias = chatModel->getSharedMedias();
|
||||
docs = chatModel->getSharedDocuments();
|
||||
}
|
||||
for (auto it : medias) {
|
||||
auto model = ChatMessageContentCore::create(it, nullptr);
|
||||
contents->push_back(model);
|
||||
}
|
||||
for (auto it : docs) {
|
||||
auto model = ChatMessageContentCore::create(it, nullptr);
|
||||
contents->push_back(model);
|
||||
}
|
||||
mCoreModelConnection->invokeToCore([this, contents] {
|
||||
for (auto i : *contents)
|
||||
mList << i.template objectCast<QObject>();
|
||||
endResetModel();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QSharedPointer<ChatCore> ChatMessageFileList::getChatCore() const {
|
||||
return mChat;
|
||||
}
|
||||
|
||||
void ChatMessageFileList::setChatCore(QSharedPointer<ChatCore> chatCore) {
|
||||
if (mChat != chatCore) {
|
||||
// if (mChat) disconnect(mChat.get());
|
||||
mChat = chatCore;
|
||||
// if (mChat) connect(mChat.get(), &ChatCore::fileListChanged, this, lUpdate);
|
||||
lUpdate();
|
||||
emit chatChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int ChatMessageFileList::getFilterType() const {
|
||||
return mFilterType;
|
||||
}
|
||||
|
||||
void ChatMessageFileList::setFilterType(int filterType) {
|
||||
if (mFilterType != filterType) {
|
||||
mFilterType = filterType;
|
||||
lUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ChatMessageFileList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole)
|
||||
return QVariant::fromValue(new ChatMessageContentGui(mList[row].objectCast<ChatMessageContentCore>()));
|
||||
return QVariant();
|
||||
}
|
||||
61
Linphone/core/chat/files/ChatMessageFileList.hpp
Normal file
61
Linphone/core/chat/files/ChatMessageFileList.hpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_FILE_LIST_H_
|
||||
#define CHAT_MESSAGE_FILE_LIST_H_
|
||||
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ChatMessageFileList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class FilterContentType { All = 0, Medias = 1, Documents = 2 };
|
||||
static QSharedPointer<ChatMessageFileList> create();
|
||||
ChatMessageFileList(QObject *parent = Q_NULLPTR);
|
||||
~ChatMessageFileList();
|
||||
|
||||
void setSelf(QSharedPointer<ChatMessageFileList> me);
|
||||
|
||||
QSharedPointer<ChatCore> getChatCore() const;
|
||||
void setChatCore(QSharedPointer<ChatCore> chatCore);
|
||||
int getFilterType() const;
|
||||
void setFilterType(int filterType);
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void chatChanged();
|
||||
void lUpdate();
|
||||
void filterTypeChanged();
|
||||
|
||||
private:
|
||||
int mFilterType;
|
||||
QSharedPointer<ChatCore> mChat;
|
||||
QSharedPointer<SafeConnection<ChatMessageFileList, CoreModel>> mCoreModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
65
Linphone/core/chat/files/ChatMessageFileProxy.cpp
Normal file
65
Linphone/core/chat/files/ChatMessageFileProxy.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageFileProxy.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageFileProxy)
|
||||
|
||||
ChatMessageFileProxy::ChatMessageFileProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mList = ChatMessageFileList::create();
|
||||
connect(mList.get(), &ChatMessageFileList::chatChanged, this, &ChatMessageFileProxy::chatGuiChanged);
|
||||
connect(this, &ChatMessageFileProxy::filterTypeChanged, this, [this] { invalidate(); });
|
||||
setSourceModels(new SortFilterList(mList.get()));
|
||||
}
|
||||
|
||||
ChatMessageFileProxy::~ChatMessageFileProxy() {
|
||||
}
|
||||
|
||||
ChatGui *ChatMessageFileProxy::getChatGui() const {
|
||||
return mList && mList->getChatCore() ? new ChatGui(mList->getChatCore()) : nullptr;
|
||||
}
|
||||
|
||||
void ChatMessageFileProxy::setChatGui(ChatGui *chat) const {
|
||||
if (mList) mList->setChatCore(chat ? chat->mCore : nullptr);
|
||||
}
|
||||
|
||||
bool ChatMessageFileProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
if (getFilterType() == (int)FilterContentType::All) return true;
|
||||
else {
|
||||
auto contentCore = getItemAtSource<ChatMessageFileList, ChatMessageContentCore>(sourceRow);
|
||||
if (!contentCore) return false;
|
||||
bool isMedia = Utils::isVideo(contentCore->getFilePath()) || Utils::isImage(contentCore->getFilePath()) ||
|
||||
Utils::isAnimatedImage(contentCore->getFilePath());
|
||||
if (getFilterType() == (int)FilterContentType::Medias) {
|
||||
return isMedia;
|
||||
} else {
|
||||
return !isMedia;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageFileProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
|
||||
const QModelIndex &sourceRight) const {
|
||||
return true;
|
||||
}
|
||||
56
Linphone/core/chat/files/ChatMessageFileProxy.hpp
Normal file
56
Linphone/core/chat/files/ChatMessageFileProxy.hpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_FILE_PROXY_H_
|
||||
#define CHAT_MESSAGE_FILE_PROXY_H_
|
||||
|
||||
#include "ChatMessageFileList.hpp"
|
||||
#include "core/chat/message/ChatMessageCore.hpp"
|
||||
#include "core/proxy/LimitProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ChatMessageFileProxy : public LimitProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ChatGui *chat READ getChatGui WRITE setChatGui NOTIFY chatGuiChanged)
|
||||
|
||||
public:
|
||||
enum class FilterContentType { All = 0, Medias = 1, Documents = 2 };
|
||||
Q_ENUM(FilterContentType)
|
||||
|
||||
DECLARE_SORTFILTER_CLASS()
|
||||
ChatMessageFileProxy(QObject *parent = Q_NULLPTR);
|
||||
~ChatMessageFileProxy();
|
||||
|
||||
ChatGui *getChatGui() const;
|
||||
void setChatGui(ChatGui *chat) const;
|
||||
|
||||
signals:
|
||||
void chatGuiChanged();
|
||||
void filterChanged();
|
||||
|
||||
protected:
|
||||
QSharedPointer<ChatMessageFileList> mList;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
694
Linphone/core/chat/message/ChatMessageCore.cpp
Normal file
694
Linphone/core/chat/message/ChatMessageCore.cpp
Normal file
|
|
@ -0,0 +1,694 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
#include <QQuickWindow>
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageCore)
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
ImdnStatus ImdnStatus::operator=(ImdnStatus r) {
|
||||
mAddress = r.mAddress;
|
||||
mState = r.mState;
|
||||
mLastUpdatedTime = r.mLastUpdatedTime;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ImdnStatus::operator==(const ImdnStatus &r) const {
|
||||
return r.mState == mState && r.mAddress == mAddress && r.mLastUpdatedTime == mLastUpdatedTime;
|
||||
}
|
||||
|
||||
bool ImdnStatus::operator!=(ImdnStatus r) {
|
||||
return r.mState != mState || r.mAddress != mAddress || r.mLastUpdatedTime != mLastUpdatedTime;
|
||||
}
|
||||
|
||||
ImdnStatus::ImdnStatus() {
|
||||
}
|
||||
|
||||
ImdnStatus::ImdnStatus(const QString &address,
|
||||
const LinphoneEnums::ChatMessageState &state,
|
||||
QDateTime lastUpdatedTime) {
|
||||
mState = state;
|
||||
mAddress = address;
|
||||
mLastUpdatedTime = lastUpdatedTime;
|
||||
}
|
||||
|
||||
ImdnStatus ImdnStatus::createMessageImdnStatusVariant(const QString &address,
|
||||
const LinphoneEnums::ChatMessageState &state,
|
||||
QDateTime lastUpdatedTime) {
|
||||
ImdnStatus s;
|
||||
s.mState = state;
|
||||
s.mAddress = address;
|
||||
s.mLastUpdatedTime = lastUpdatedTime;
|
||||
return s;
|
||||
}
|
||||
|
||||
QVariant createImdnStatusSingletonVariant(const LinphoneEnums::ChatMessageState &state, int count = 1) {
|
||||
QVariantMap map;
|
||||
map.insert("state", QVariant::fromValue(state));
|
||||
map.insert("count", count);
|
||||
return map;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
Reaction Reaction::operator=(Reaction r) {
|
||||
mAddress = r.mAddress;
|
||||
mBody = r.mBody;
|
||||
return *this;
|
||||
}
|
||||
bool Reaction::operator==(const Reaction &r) const {
|
||||
return r.mBody == mBody && r.mAddress == mAddress;
|
||||
}
|
||||
bool Reaction::operator!=(Reaction r) {
|
||||
return r.mBody != mBody || r.mAddress != mAddress;
|
||||
}
|
||||
|
||||
Reaction Reaction::createMessageReactionVariant(const QString &body, const QString &address) {
|
||||
Reaction r;
|
||||
r.mBody = body;
|
||||
r.mAddress = address;
|
||||
return r;
|
||||
}
|
||||
|
||||
QVariant createReactionSingletonVariant(const QString &body, int count = 1) {
|
||||
QVariantMap map;
|
||||
map.insert("body", body);
|
||||
map.insert("count", count);
|
||||
return map;
|
||||
}
|
||||
|
||||
/***********************************************************************/
|
||||
|
||||
QSharedPointer<ChatMessageCore> ChatMessageCore::create(const std::shared_ptr<linphone::ChatMessage> &chatmessage) {
|
||||
auto sharedPointer = QSharedPointer<ChatMessageCore>(new ChatMessageCore(chatmessage), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
ChatMessageCore::ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &chatmessage) {
|
||||
// lDebug() << "[ChatMessageCore] new" << this;
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
if (chatmessage) {
|
||||
mChatMessageModel = Utils::makeQObject_ptr<ChatMessageModel>(chatmessage);
|
||||
mChatMessageModel->setSelf(mChatMessageModel);
|
||||
mText = ToolModel::getMessageFromMessage(chatmessage);
|
||||
mUtf8Text = mChatMessageModel->getUtf8Text();
|
||||
mHasTextContent = mChatMessageModel->getHasTextContent();
|
||||
mTimestamp = QDateTime::fromSecsSinceEpoch(chatmessage->getTime());
|
||||
mIsOutgoing = chatmessage->isOutgoing();
|
||||
mIsRetractable =
|
||||
chatmessage->isOutgoing() && chatmessage->isRetractable() && !chatmessage->getChatRoom()->isReadOnly();
|
||||
mIsRetracted = chatmessage->isRetracted();
|
||||
mIsEditable =
|
||||
chatmessage->isOutgoing() && chatmessage->isEditable() && !chatmessage->getChatRoom()->isReadOnly();
|
||||
mIsEdited = chatmessage->isEdited();
|
||||
mIsRemoteMessage = !chatmessage->isOutgoing();
|
||||
mPeerAddress = Utils::coreStringToAppString(chatmessage->getPeerAddress()->asStringUriOnly());
|
||||
mPeerName = ToolModel::getDisplayName(chatmessage->getPeerAddress());
|
||||
auto fromAddress = chatmessage->getFromAddress();
|
||||
// fromAddress->clean();
|
||||
mFromAddress = Utils::coreStringToAppString(fromAddress->asStringUriOnly());
|
||||
mFromName = ToolModel::getDisplayName(chatmessage->getFromAddress());
|
||||
mToName = ToolModel::getDisplayName(chatmessage->getToAddress());
|
||||
auto chatroom = chatmessage->getChatRoom();
|
||||
mIsFromChatGroup = chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference) &&
|
||||
!chatroom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne);
|
||||
mIsRead = chatmessage->isRead();
|
||||
mMessageState = LinphoneEnums::fromLinphone(chatmessage->getState());
|
||||
mIsEphemeral = chatmessage->isEphemeral();
|
||||
|
||||
if (mIsEphemeral) {
|
||||
auto now = QDateTime::currentDateTime();
|
||||
mEphemeralDuration = chatmessage->getEphemeralExpireTime() == 0
|
||||
? chatmessage->getEphemeralLifetime()
|
||||
: now.secsTo(QDateTime::fromSecsSinceEpoch(chatmessage->getEphemeralExpireTime()));
|
||||
}
|
||||
mMessageId = Utils::coreStringToAppString(chatmessage->getMessageId());
|
||||
for (auto content : chatmessage->getContents()) {
|
||||
auto contentCore = ChatMessageContentCore::create(content, mChatMessageModel);
|
||||
mChatMessageContentList.push_back(contentCore);
|
||||
if ((content->isFile() || content->isFileTransfer()) && !content->isVoiceRecording())
|
||||
mHasFileContent = true;
|
||||
if (content->isIcalendar()) mIsCalendarInvite = true;
|
||||
if (content->isVoiceRecording()) {
|
||||
mIsVoiceRecording = true;
|
||||
mVoiceRecordingContent = contentCore;
|
||||
}
|
||||
}
|
||||
//: "Reactions": all reactions for one message label
|
||||
mTotalReactionsLabel = tr("all_reactions_label");
|
||||
auto reac = chatmessage->getOwnReaction();
|
||||
mOwnReaction = reac ? Utils::coreStringToAppString(reac->getBody()) : QString();
|
||||
for (auto &reaction : chatmessage->getReactions()) {
|
||||
if (reaction) {
|
||||
auto fromAddr = reaction->getFromAddress()->clone();
|
||||
fromAddr->clean();
|
||||
auto reac =
|
||||
Reaction::createMessageReactionVariant(Utils::coreStringToAppString(reaction->getBody()),
|
||||
Utils::coreStringToAppString(fromAddr->asStringUriOnly()));
|
||||
mReactions.append(reac);
|
||||
|
||||
auto it = std::find_if(mReactionsSingletonMap.begin(), mReactionsSingletonMap.end(),
|
||||
[body = reac.mBody](QVariant data) {
|
||||
auto dataBody = data.toMap()["body"].toString();
|
||||
return body == dataBody;
|
||||
});
|
||||
if (it == mReactionsSingletonMap.end())
|
||||
mReactionsSingletonMap.push_back(createReactionSingletonVariant(reac.mBody, 1));
|
||||
else {
|
||||
auto map = it->toMap();
|
||||
auto count = map["count"].toInt();
|
||||
++count;
|
||||
map.remove("count");
|
||||
map.insert("count", count);
|
||||
mReactionsSingletonMap.erase(it);
|
||||
mReactionsSingletonMap.push_back(map);
|
||||
}
|
||||
}
|
||||
}
|
||||
connect(this, &ChatMessageCore::messageReactionChanged, this, &ChatMessageCore::resetReactionsSingleton);
|
||||
|
||||
mIsForward = chatmessage->isForward();
|
||||
mIsReply = chatmessage->isReply();
|
||||
if (mIsReply) {
|
||||
auto replymessage = chatmessage->getReplyMessage();
|
||||
if (replymessage) {
|
||||
mReplyText = ToolModel::getMessageFromMessage(replymessage);
|
||||
if (mIsFromChatGroup) mRepliedToName = ToolModel::getDisplayName(replymessage->getFromAddress());
|
||||
}
|
||||
}
|
||||
mImdnStatusList = computeDeliveryStatus(chatmessage);
|
||||
}
|
||||
}
|
||||
|
||||
ChatMessageCore::~ChatMessageCore() {
|
||||
}
|
||||
|
||||
void ChatMessageCore::setSelf(QSharedPointer<ChatMessageCore> me) {
|
||||
mChatMessageModelConnection = SafeConnection<ChatMessageCore, ChatMessageModel>::create(me, mChatMessageModel);
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lDelete, [this] {
|
||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->deleteMessageFromChatRoom(true); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lRetract, [this] {
|
||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->retractMessageFromChatRoom(); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageDeleted, [this](bool deletedByUser) {
|
||||
mChatMessageModelConnection->invokeToCore([this, deletedByUser] {
|
||||
//: Deleted
|
||||
if (deletedByUser)
|
||||
Utils::showInformationPopup(tr("info_toast_deleted_title"),
|
||||
//: The message has been deleted
|
||||
tr("info_toast_deleted_message"), true);
|
||||
emit deleted();
|
||||
});
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lMarkAsRead, [this] {
|
||||
auto mainWindow = Utils::getMainWindow();
|
||||
if (mainWindow->isActive())
|
||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->markAsRead(); });
|
||||
else {
|
||||
connect(mainWindow, &QQuickWindow::activeChanged, this, [this, mainWindow] {
|
||||
if (mainWindow->isActive()) {
|
||||
disconnect(mainWindow, &QQuickWindow::activeChanged, this, nullptr);
|
||||
mChatMessageModelConnection->invokeToModel([this, mainWindow] { mChatMessageModel->markAsRead(); });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::messageRead, [this]() {
|
||||
mChatMessageModelConnection->invokeToCore([this] { setIsRead(true); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lSendReaction, [this](const QString &reaction) {
|
||||
mChatMessageModelConnection->invokeToModel([this, reaction] { mChatMessageModel->sendReaction(reaction); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lRemoveReaction, [this]() {
|
||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->removeReaction(); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToCore(&ChatMessageCore::lSend, [this]() {
|
||||
mChatMessageModelConnection->invokeToModel([this] { mChatMessageModel->send(); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::newMessageReaction,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::ChatMessageReaction> &reaction) {
|
||||
auto ownReac = message->getOwnReaction();
|
||||
auto own = ownReac ? Utils::coreStringToAppString(message->getOwnReaction()->getBody()) : QString();
|
||||
// We must reset all the reactions each time cause reactionRemoved is not emitted
|
||||
// when someone change its current reaction
|
||||
QList<Reaction> reactions;
|
||||
for (auto &reaction : message->getReactions()) {
|
||||
if (reaction) {
|
||||
auto fromAddr = reaction->getFromAddress()->clone();
|
||||
fromAddr->clean();
|
||||
reactions.append(Reaction::createMessageReactionVariant(
|
||||
Utils::coreStringToAppString(reaction->getBody()),
|
||||
Utils::coreStringToAppString(fromAddr->asStringUriOnly())));
|
||||
}
|
||||
}
|
||||
mChatMessageModelConnection->invokeToCore([this, own, reactions] {
|
||||
setOwnReaction(own);
|
||||
setReactions(reactions);
|
||||
});
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::reactionRemoved, [this](const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::Address> &address) {
|
||||
auto reac = message->getOwnReaction();
|
||||
auto own = reac ? Utils::coreStringToAppString(message->getOwnReaction()->getBody()) : QString();
|
||||
auto addr = address->clone();
|
||||
addr->clean();
|
||||
QString addressString = Utils::coreStringToAppString(addr->asStringUriOnly());
|
||||
mChatMessageModelConnection->invokeToCore([this, own, addressString] {
|
||||
removeReaction(addressString);
|
||||
setOwnReaction(own);
|
||||
});
|
||||
});
|
||||
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::msgStateChanged,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, linphone::ChatMessage::State state) {
|
||||
auto imdnStatusList = computeDeliveryStatus(message);
|
||||
auto msgState = LinphoneEnums::fromLinphone(state);
|
||||
mChatMessageModelConnection->invokeToCore([this, msgState, imdnStatusList] {
|
||||
setImdnStatusList(imdnStatusList);
|
||||
setMessageState(msgState);
|
||||
});
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::fileTransferProgressIndication,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &content,
|
||||
size_t offset, size_t total) {
|
||||
mChatMessageModelConnection->invokeToCore([this, content, offset, total] {
|
||||
auto it =
|
||||
std::find_if(mChatMessageContentList.begin(), mChatMessageContentList.end(),
|
||||
[content](QSharedPointer<ChatMessageContentCore> item) {
|
||||
return item->getContentModel()->getContent()->getName() == content->getName();
|
||||
});
|
||||
if (it != mChatMessageContentList.end()) {
|
||||
auto contentCore = mChatMessageContentList.at(std::distance(mChatMessageContentList.begin(), it));
|
||||
assert(contentCore);
|
||||
contentCore->setFileOffset(offset);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::fileTransferTerminated, [this](const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<linphone::Content> &content) {
|
||||
mChatMessageModelConnection->invokeToCore([this, content] {
|
||||
auto it =
|
||||
std::find_if(mChatMessageContentList.begin(), mChatMessageContentList.end(),
|
||||
[content](QSharedPointer<ChatMessageContentCore> item) {
|
||||
return item->getContentModel()->getContent()->getName() == content->getName();
|
||||
});
|
||||
if (it != mChatMessageContentList.end()) {
|
||||
auto contentCore = mChatMessageContentList.at(std::distance(mChatMessageContentList.begin(), it));
|
||||
assert(contentCore);
|
||||
contentCore->setWasDownloaded(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::fileTransferRecv,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &content,
|
||||
const std::shared_ptr<const linphone::Buffer> &buffer) { lInfo() << log().arg("transfer received"); });
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::fileTransferSend,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &content,
|
||||
size_t offset, size_t size) { lInfo() << log().arg("transfer send"); });
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::fileTransferSendChunk,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, const std::shared_ptr<linphone::Content> &content,
|
||||
size_t offset, size_t size,
|
||||
const std::shared_ptr<linphone::Buffer> &buffer) { lInfo() << log().arg("transfer send chunk"); });
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::participantImdnStateChanged,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message,
|
||||
const std::shared_ptr<const linphone::ParticipantImdnState> &state) {
|
||||
auto imdnStatusList = computeDeliveryStatus(message);
|
||||
mChatMessageModelConnection->invokeToCore([this, imdnStatusList] { setImdnStatusList(imdnStatusList); });
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(
|
||||
&ChatMessageModel::ephemeralMessageTimeUpdated,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message, int expireTime) {
|
||||
auto now = QDateTime::currentDateTime();
|
||||
int duration = now.secsTo(QDateTime::fromSecsSinceEpoch(expireTime));
|
||||
mChatMessageModelConnection->invokeToCore([this, duration] { setEphemeralDuration(duration); });
|
||||
});
|
||||
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::retracted,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
QString text = ToolModel::getMessageFromMessage(message);
|
||||
mChatMessageModelConnection->invokeToCore([this, text] {
|
||||
setText(text);
|
||||
setRetracted();
|
||||
});
|
||||
});
|
||||
mChatMessageModelConnection->makeConnectToModel(&ChatMessageModel::contentEdited,
|
||||
[this](const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
mChatMessageModelConnection->invokeToCore([this] {
|
||||
mIsEdited = true;
|
||||
emit edited();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
QList<ImdnStatus> ChatMessageCore::computeDeliveryStatus(const std::shared_ptr<linphone::ChatMessage> &message) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
QList<ImdnStatus> imdnStatusList;
|
||||
auto createImdnStatus = [this](std::shared_ptr<linphone::ParticipantImdnState> participant,
|
||||
linphone::ChatMessage::State state) -> ImdnStatus {
|
||||
auto address = participant->getParticipant() ? participant->getParticipant()->getAddress()->clone() : nullptr;
|
||||
auto lastUpdated = QDateTime::fromSecsSinceEpoch(participant->getStateChangeTime());
|
||||
if (address) {
|
||||
address->clean();
|
||||
auto addrString = Utils::coreStringToAppString(address->asStringUriOnly());
|
||||
auto imdn =
|
||||
ImdnStatus::createMessageImdnStatusVariant(addrString, LinphoneEnums::fromLinphone(state), lastUpdated);
|
||||
return imdn;
|
||||
}
|
||||
return ImdnStatus();
|
||||
};
|
||||
|
||||
// Read
|
||||
for (auto &participant : message->getParticipantsByImdnState(linphone::ChatMessage::State::Displayed)) {
|
||||
auto imdn = createImdnStatus(participant, linphone::ChatMessage::State::Displayed);
|
||||
imdnStatusList.append(imdn);
|
||||
}
|
||||
// Received
|
||||
for (auto &participant : message->getParticipantsByImdnState(linphone::ChatMessage::State::DeliveredToUser)) {
|
||||
auto imdn = createImdnStatus(participant, linphone::ChatMessage::State::DeliveredToUser);
|
||||
imdnStatusList.append(imdn);
|
||||
}
|
||||
// Sent
|
||||
for (auto &participant : message->getParticipantsByImdnState(linphone::ChatMessage::State::Delivered)) {
|
||||
auto imdn = createImdnStatus(participant, linphone::ChatMessage::State::Delivered);
|
||||
imdnStatusList.append(imdn);
|
||||
}
|
||||
// Error
|
||||
for (auto &participant : message->getParticipantsByImdnState(linphone::ChatMessage::State::NotDelivered)) {
|
||||
auto imdn = createImdnStatus(participant, linphone::ChatMessage::State::NotDelivered);
|
||||
imdnStatusList.append(imdn);
|
||||
}
|
||||
return imdnStatusList;
|
||||
}
|
||||
|
||||
QDateTime ChatMessageCore::getTimestamp() const {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getText() const {
|
||||
return mText;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setText(QString text) {
|
||||
if (mText != text) {
|
||||
mText = text;
|
||||
emit textChanged(text);
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getPeerAddress() const {
|
||||
return mPeerAddress;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getPeerName() const {
|
||||
return mPeerName;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getFromAddress() const {
|
||||
return mFromAddress;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getFromName() const {
|
||||
return mFromName;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getToAddress() const {
|
||||
return mToAddress;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getToName() const {
|
||||
return mToName;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getMessageId() const {
|
||||
return mMessageId;
|
||||
}
|
||||
bool ChatMessageCore::isRemoteMessage() const {
|
||||
return mIsRemoteMessage;
|
||||
}
|
||||
|
||||
bool ChatMessageCore::isFromChatGroup() const {
|
||||
return mIsFromChatGroup;
|
||||
}
|
||||
|
||||
bool ChatMessageCore::isEphemeral() const {
|
||||
return mIsEphemeral;
|
||||
}
|
||||
|
||||
int ChatMessageCore::getEphemeralDuration() const {
|
||||
return mEphemeralDuration;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setEphemeralDuration(int duration) {
|
||||
if (mEphemeralDuration != duration) {
|
||||
mEphemeralDuration = duration;
|
||||
emit ephemeralDurationChanged(duration);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageCore::hasFileContent() const {
|
||||
return mHasFileContent;
|
||||
}
|
||||
|
||||
bool ChatMessageCore::isRead() const {
|
||||
return mIsRead;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setIsRead(bool read) {
|
||||
if (mIsRead != read) {
|
||||
mIsRead = read;
|
||||
emit isReadChanged(read);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageCore::setRetracted() {
|
||||
if (!mIsRetracted) {
|
||||
mIsRetracted = true;
|
||||
emit isRetractedChanged();
|
||||
emit messageStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageCore::isRetracted() const {
|
||||
return mIsRetracted;
|
||||
}
|
||||
|
||||
bool ChatMessageCore::isEdited() const {
|
||||
return mIsEdited;
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getOwnReaction() const {
|
||||
return mOwnReaction;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setOwnReaction(const QString &reaction) {
|
||||
if (mOwnReaction != reaction) {
|
||||
mOwnReaction = reaction;
|
||||
emit messageReactionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatMessageCore::getTotalReactionsLabel() const {
|
||||
return mTotalReactionsLabel;
|
||||
}
|
||||
|
||||
QList<Reaction> ChatMessageCore::getReactions() const {
|
||||
return mReactions;
|
||||
}
|
||||
|
||||
QList<QVariant> ChatMessageCore::getReactionsSingleton() const {
|
||||
return mReactionsSingletonMap;
|
||||
}
|
||||
|
||||
QStringList ChatMessageCore::getReactionsSingletonAsStrings() const {
|
||||
QStringList reacStringList;
|
||||
int totalCount = 0;
|
||||
for (auto &reac : mReactionsSingletonMap) {
|
||||
auto map = reac.toMap();
|
||||
auto count = map["count"].toInt();
|
||||
totalCount += count;
|
||||
reacStringList.append(QString("%1 %2").arg(map["body"].toString()).arg(count));
|
||||
}
|
||||
reacStringList.prepend(QString("%1 %2").arg(mTotalReactionsLabel).arg(totalCount));
|
||||
return reacStringList;
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ChatMessageContentCore>> ChatMessageCore::getChatMessageContentList() const {
|
||||
return mChatMessageContentList;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setReactions(const QList<Reaction> &reactions) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
mReactions = reactions;
|
||||
emit messageReactionChanged();
|
||||
}
|
||||
|
||||
void ChatMessageCore::resetReactionsSingleton() {
|
||||
mReactionsSingletonMap.clear();
|
||||
for (auto &reac : mReactions) {
|
||||
auto it = std::find_if(mReactionsSingletonMap.begin(), mReactionsSingletonMap.end(),
|
||||
[body = reac.mBody](QVariant data) {
|
||||
auto dataBody = data.toMap()["body"].toString();
|
||||
return body == dataBody;
|
||||
});
|
||||
if (it == mReactionsSingletonMap.end())
|
||||
mReactionsSingletonMap.push_back(createReactionSingletonVariant(reac.mBody, 1));
|
||||
else {
|
||||
auto map = it->toMap();
|
||||
auto count = map["count"].toInt();
|
||||
++count;
|
||||
map.remove("count");
|
||||
map.insert("count", count);
|
||||
mReactionsSingletonMap.erase(it);
|
||||
mReactionsSingletonMap.push_back(map);
|
||||
}
|
||||
}
|
||||
emit singletonReactionMapChanged();
|
||||
}
|
||||
|
||||
void ChatMessageCore::removeReaction(const Reaction &reaction) {
|
||||
int i = 0;
|
||||
for (const auto &r : mReactions) {
|
||||
if (reaction == r) {
|
||||
mReactions.removeAt(i);
|
||||
emit messageReactionChanged();
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageCore::removeOneReactionFromSingletonMap(const QString &body) {
|
||||
auto it = std::find_if(mReactionsSingletonMap.begin(), mReactionsSingletonMap.end(), [body](QVariant data) {
|
||||
auto dataBody = data.toMap()["body"].toString();
|
||||
return body == dataBody;
|
||||
});
|
||||
if (it != mReactionsSingletonMap.end()) {
|
||||
auto map = it->toMap();
|
||||
auto count = map["count"].toInt();
|
||||
if (count <= 1) mReactionsSingletonMap.erase(it);
|
||||
else {
|
||||
--count;
|
||||
map.remove("count");
|
||||
map.insert("count", count);
|
||||
}
|
||||
emit messageReactionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageCore::removeReaction(const QString &address) {
|
||||
int n = mReactions.removeIf([address, this](Reaction r) {
|
||||
if (r.mAddress == address) {
|
||||
removeOneReactionFromSingletonMap(r.mBody);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (n > 0) emit messageReactionChanged();
|
||||
}
|
||||
|
||||
LinphoneEnums::ChatMessageState ChatMessageCore::getMessageState() const {
|
||||
return mMessageState;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setMessageState(LinphoneEnums::ChatMessageState state) {
|
||||
if (mMessageState != state) {
|
||||
mMessageState = state;
|
||||
emit messageStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QList<ImdnStatus> ChatMessageCore::getImdnStatusList() const {
|
||||
return mImdnStatusList;
|
||||
}
|
||||
|
||||
void ChatMessageCore::setImdnStatusList(QList<ImdnStatus> status) {
|
||||
mImdnStatusList = status;
|
||||
emit imdnStatusListChanged();
|
||||
}
|
||||
|
||||
QStringList ChatMessageCore::getImdnStatusListLabels() const {
|
||||
QStringList statusList;
|
||||
int count = 0;
|
||||
auto imdnSingletons = getImdnStatusAsSingletons();
|
||||
for (auto &status : imdnSingletons) {
|
||||
auto map = status.toMap();
|
||||
auto val = map["state"].value<LinphoneEnums::ChatMessageState>();
|
||||
auto count = map["count"].toInt();
|
||||
statusList.append(QString("%1 %2").arg(LinphoneEnums::toString(val)).arg(count));
|
||||
}
|
||||
return statusList;
|
||||
}
|
||||
|
||||
QVariantList ChatMessageCore::getImdnStatusAsSingletons() const {
|
||||
QVariantList statusSingletons;
|
||||
statusSingletons.append(createImdnStatusSingletonVariant(LinphoneEnums::ChatMessageState::StateDisplayed, 0));
|
||||
statusSingletons.append(createImdnStatusSingletonVariant(LinphoneEnums::ChatMessageState::StateDeliveredToUser, 0));
|
||||
statusSingletons.append(createImdnStatusSingletonVariant(LinphoneEnums::ChatMessageState::StateDelivered, 0));
|
||||
statusSingletons.append(createImdnStatusSingletonVariant(LinphoneEnums::ChatMessageState::StateNotDelivered, 0));
|
||||
for (auto &stat : mImdnStatusList) {
|
||||
auto it = std::find_if(statusSingletons.begin(), statusSingletons.end(), [state = stat.mState](QVariant data) {
|
||||
auto dataState = data.toMap()["state"].value<LinphoneEnums::ChatMessageState>();
|
||||
return state == dataState;
|
||||
});
|
||||
if (it == statusSingletons.end()) {
|
||||
if (!stat.mAddress.isEmpty()) statusSingletons.append(createImdnStatusSingletonVariant(stat.mState, 1));
|
||||
} else {
|
||||
auto map = it->toMap();
|
||||
auto count = map["count"].toInt();
|
||||
++count;
|
||||
map.remove("count");
|
||||
map.insert("count", count);
|
||||
int index = std::distance(statusSingletons.begin(), it);
|
||||
statusSingletons.replace(index, map);
|
||||
}
|
||||
}
|
||||
return statusSingletons;
|
||||
}
|
||||
|
||||
std::shared_ptr<ChatMessageModel> ChatMessageCore::getModel() const {
|
||||
return mChatMessageModel;
|
||||
}
|
||||
|
||||
// ConferenceInfoGui *ChatMessageCore::getConferenceInfoGui() const {
|
||||
// return mConferenceInfo ? new ConferenceInfoGui(mConferenceInfo) : nullptr;
|
||||
// }
|
||||
|
||||
ChatMessageContentGui *ChatMessageCore::getVoiceRecordingContent() const {
|
||||
return new ChatMessageContentGui(mVoiceRecordingContent);
|
||||
}
|
||||
246
Linphone/core/chat/message/ChatMessageCore.hpp
Normal file
246
Linphone/core/chat/message/ChatMessageCore.hpp
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_CORE_H_
|
||||
#define CHAT_MESSAGE_CORE_H_
|
||||
|
||||
#include "EventLogCore.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentGui.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentProxy.hpp"
|
||||
#include "core/conference/ConferenceInfoCore.hpp"
|
||||
#include "core/conference/ConferenceInfoGui.hpp"
|
||||
#include "model/chat/message/ChatMessageModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
struct ImdnStatus {
|
||||
Q_GADGET
|
||||
|
||||
Q_PROPERTY(QString address MEMBER mAddress)
|
||||
Q_PROPERTY(LinphoneEnums::ChatMessageState state MEMBER mState)
|
||||
Q_PROPERTY(QDateTime lastUpdatedTime MEMBER mLastUpdatedTime)
|
||||
|
||||
public:
|
||||
QString mAddress;
|
||||
LinphoneEnums::ChatMessageState mState;
|
||||
QDateTime mLastUpdatedTime;
|
||||
|
||||
ImdnStatus(const QString &address, const LinphoneEnums::ChatMessageState &state, QDateTime mLastUpdatedTime);
|
||||
ImdnStatus();
|
||||
ImdnStatus operator=(ImdnStatus r);
|
||||
bool operator==(const ImdnStatus &r) const;
|
||||
bool operator!=(ImdnStatus r);
|
||||
static ImdnStatus createMessageImdnStatusVariant(const QString &address,
|
||||
const LinphoneEnums::ChatMessageState &state,
|
||||
QDateTime mLastUpdatedTime);
|
||||
};
|
||||
|
||||
struct Reaction {
|
||||
Q_GADGET
|
||||
|
||||
Q_PROPERTY(QString body MEMBER mBody)
|
||||
Q_PROPERTY(QString address MEMBER mAddress)
|
||||
|
||||
public:
|
||||
QString mBody;
|
||||
QString mAddress;
|
||||
|
||||
Reaction operator=(Reaction r);
|
||||
bool operator==(const Reaction &r) const;
|
||||
bool operator!=(Reaction r);
|
||||
static Reaction createMessageReactionVariant(const QString &body, const QString &address);
|
||||
};
|
||||
|
||||
class ChatCore;
|
||||
class EventLogCore;
|
||||
|
||||
class ChatMessageCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QDateTime timestamp READ getTimestamp CONSTANT)
|
||||
Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged)
|
||||
Q_PROPERTY(QString utf8Text MEMBER mUtf8Text CONSTANT)
|
||||
Q_PROPERTY(bool hasTextContent MEMBER mHasTextContent CONSTANT)
|
||||
Q_PROPERTY(QString peerAddress READ getPeerAddress CONSTANT)
|
||||
Q_PROPERTY(QString fromAddress READ getFromAddress CONSTANT)
|
||||
Q_PROPERTY(QString toAddress READ getToAddress CONSTANT)
|
||||
Q_PROPERTY(QString peerName READ getPeerName CONSTANT)
|
||||
Q_PROPERTY(QString fromName READ getFromName CONSTANT)
|
||||
Q_PROPERTY(QString totalReactionsLabel READ getTotalReactionsLabel CONSTANT)
|
||||
Q_PROPERTY(LinphoneEnums::ChatMessageState messageState READ getMessageState WRITE setMessageState NOTIFY
|
||||
messageStateChanged)
|
||||
Q_PROPERTY(bool isRemoteMessage READ isRemoteMessage CONSTANT)
|
||||
Q_PROPERTY(bool isFromChatGroup READ isFromChatGroup CONSTANT)
|
||||
Q_PROPERTY(bool isEphemeral READ isEphemeral CONSTANT)
|
||||
Q_PROPERTY(
|
||||
int ephemeralDuration READ getEphemeralDuration WRITE setEphemeralDuration NOTIFY ephemeralDurationChanged)
|
||||
Q_PROPERTY(bool isRead READ isRead WRITE setIsRead NOTIFY isReadChanged)
|
||||
Q_PROPERTY(QString ownReaction READ getOwnReaction WRITE setOwnReaction NOTIFY messageReactionChanged)
|
||||
Q_PROPERTY(QStringList imdnStatusListAsString READ getImdnStatusListLabels NOTIFY imdnStatusListChanged)
|
||||
Q_PROPERTY(QList<ImdnStatus> imdnStatusList READ getImdnStatusList NOTIFY imdnStatusListChanged)
|
||||
Q_PROPERTY(QVariantList imdnStatusAsSingletons READ getImdnStatusAsSingletons NOTIFY imdnStatusListChanged)
|
||||
Q_PROPERTY(QList<Reaction> reactions READ getReactions WRITE setReactions NOTIFY messageReactionChanged)
|
||||
Q_PROPERTY(QList<QVariant> reactionsSingleton READ getReactionsSingleton NOTIFY singletonReactionMapChanged)
|
||||
Q_PROPERTY(
|
||||
QStringList reactionsSingletonAsStrings READ getReactionsSingletonAsStrings NOTIFY singletonReactionMapChanged)
|
||||
Q_PROPERTY(bool isForward MEMBER mIsForward CONSTANT)
|
||||
Q_PROPERTY(bool isReply MEMBER mIsReply CONSTANT)
|
||||
Q_PROPERTY(QString replyText MEMBER mReplyText CONSTANT)
|
||||
Q_PROPERTY(QString repliedToName MEMBER mRepliedToName CONSTANT)
|
||||
Q_PROPERTY(bool hasFileContent MEMBER mHasFileContent CONSTANT)
|
||||
Q_PROPERTY(bool isVoiceRecording MEMBER mIsVoiceRecording CONSTANT)
|
||||
Q_PROPERTY(bool isCalendarInvite MEMBER mIsCalendarInvite CONSTANT)
|
||||
Q_PROPERTY(bool isOutgoing MEMBER mIsOutgoing CONSTANT)
|
||||
Q_PROPERTY(bool isRetractable MEMBER mIsRetractable CONSTANT)
|
||||
Q_PROPERTY(bool isRetracted READ isRetracted NOTIFY isRetractedChanged)
|
||||
Q_PROPERTY(bool isEditable MEMBER mIsEditable CONSTANT)
|
||||
Q_PROPERTY(bool isEdited READ isEdited NOTIFY edited)
|
||||
|
||||
public:
|
||||
static QSharedPointer<ChatMessageCore> create(const std::shared_ptr<linphone::ChatMessage> &chatmessage);
|
||||
ChatMessageCore(const std::shared_ptr<linphone::ChatMessage> &chatmessage);
|
||||
~ChatMessageCore();
|
||||
void setSelf(QSharedPointer<ChatMessageCore> me);
|
||||
|
||||
QList<ImdnStatus> computeDeliveryStatus(const std::shared_ptr<linphone::ChatMessage> &message);
|
||||
|
||||
QString getText() const;
|
||||
void setText(QString text);
|
||||
|
||||
QString getPeerAddress() const;
|
||||
QString getPeerName() const;
|
||||
QString getFromAddress() const;
|
||||
QString getFromName() const;
|
||||
QString getToAddress() const;
|
||||
QString getToName() const;
|
||||
QString getMessageId() const;
|
||||
|
||||
bool isRemoteMessage() const;
|
||||
bool isFromChatGroup() const;
|
||||
bool isEphemeral() const;
|
||||
int getEphemeralDuration() const;
|
||||
void setEphemeralDuration(int duration);
|
||||
QDateTime getTimestamp() const;
|
||||
|
||||
bool hasFileContent() const;
|
||||
|
||||
bool isRead() const;
|
||||
void setIsRead(bool read);
|
||||
|
||||
bool isRetracted() const;
|
||||
void setRetracted();
|
||||
bool isEdited() const;
|
||||
|
||||
QString getOwnReaction() const;
|
||||
void setOwnReaction(const QString &reaction);
|
||||
QString getTotalReactionsLabel() const;
|
||||
QList<Reaction> getReactions() const;
|
||||
QList<QVariant> getReactionsSingleton() const;
|
||||
QStringList getReactionsSingletonAsStrings() const;
|
||||
QList<QSharedPointer<ChatMessageContentCore>> getChatMessageContentList() const;
|
||||
void removeOneReactionFromSingletonMap(const QString &body);
|
||||
void resetReactionsSingleton();
|
||||
void setReactions(const QList<Reaction> &reactions);
|
||||
void removeReaction(const Reaction &reaction);
|
||||
void removeReaction(const QString &address);
|
||||
|
||||
LinphoneEnums::ChatMessageState getMessageState() const;
|
||||
void setMessageState(LinphoneEnums::ChatMessageState state);
|
||||
QList<ImdnStatus> getImdnStatusList() const;
|
||||
void setImdnStatusList(QList<ImdnStatus> status);
|
||||
QVariantList getImdnStatusAsSingletons() const;
|
||||
QStringList getImdnStatusListLabels() const;
|
||||
|
||||
std::shared_ptr<ChatMessageModel> getModel() const;
|
||||
Q_INVOKABLE ChatMessageContentGui *getVoiceRecordingContent() const;
|
||||
|
||||
signals:
|
||||
void textChanged(QString text);
|
||||
void utf8TextChanged(QString text);
|
||||
void isReadChanged(bool read);
|
||||
void isRemoteMessageChanged(bool isRemote);
|
||||
void messageStateChanged();
|
||||
void imdnStatusListChanged();
|
||||
void messageReactionChanged();
|
||||
void singletonReactionMapChanged();
|
||||
void ephemeralDurationChanged(int duration);
|
||||
void isRetractedChanged();
|
||||
void edited();
|
||||
|
||||
void lDelete();
|
||||
void deleted();
|
||||
void lRetract();
|
||||
void lMarkAsRead();
|
||||
void readChanged();
|
||||
void lSendReaction(const QString &reaction);
|
||||
void lRemoveReaction();
|
||||
void lSend();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
QString mText;
|
||||
QString mUtf8Text;
|
||||
bool mHasTextContent;
|
||||
QString mPeerAddress;
|
||||
QString mFromAddress;
|
||||
QString mToAddress;
|
||||
QString mFromName;
|
||||
QString mToName;
|
||||
QString mPeerName;
|
||||
QString mMessageId;
|
||||
QString mOwnReaction;
|
||||
QList<Reaction> mReactions;
|
||||
QList<ImdnStatus> mImdnStatusList;
|
||||
QList<QVariant> mReactionsSingletonMap;
|
||||
QDateTime mTimestamp;
|
||||
bool mIsRemoteMessage = false;
|
||||
bool mIsFromChatGroup = false;
|
||||
bool mIsRead = false;
|
||||
bool mIsForward = false;
|
||||
bool mIsReply = false;
|
||||
QString mReplyText;
|
||||
QString mRepliedToName;
|
||||
bool mHasFileContent = false;
|
||||
bool mIsCalendarInvite = false;
|
||||
bool mIsVoiceRecording = false;
|
||||
bool mIsEphemeral = false;
|
||||
int mEphemeralDuration = 0;
|
||||
bool mIsRetractable = false;
|
||||
bool mIsRetracted = false;
|
||||
bool mIsEditable = false;
|
||||
bool mIsEdited = false;
|
||||
|
||||
bool mIsOutgoing = false;
|
||||
QString mTotalReactionsLabel;
|
||||
LinphoneEnums::ChatMessageState mMessageState;
|
||||
QList<QSharedPointer<ChatMessageContentCore>> mChatMessageContentList;
|
||||
// for voice recording creation message
|
||||
QSharedPointer<ChatMessageContentCore> mVoiceRecordingContent;
|
||||
// QSharedPointer<ConferenceInfoCore> mConferenceInfo = nullptr;
|
||||
|
||||
std::shared_ptr<ChatMessageModel> mChatMessageModel;
|
||||
QSharedPointer<SafeConnection<ChatMessageCore, ChatMessageModel>> mChatMessageModelConnection;
|
||||
};
|
||||
|
||||
#endif // CHAT_MESSAGE_CORE_H_
|
||||
39
Linphone/core/chat/message/ChatMessageGui.cpp
Normal file
39
Linphone/core/chat/message/ChatMessageGui.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageGui.hpp"
|
||||
#include "ChatMessageCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageGui)
|
||||
|
||||
ChatMessageGui::ChatMessageGui(QSharedPointer<ChatMessageCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
ChatMessageGui::~ChatMessageGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
ChatMessageCore *ChatMessageGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
41
Linphone/core/chat/message/ChatMessageGui.hpp
Normal file
41
Linphone/core/chat/message/ChatMessageGui.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_GUI_H_
|
||||
#define CHAT_MESSAGE_GUI_H_
|
||||
|
||||
#include "ChatMessageCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class ChatMessageGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ChatMessageCore *core READ getCore CONSTANT)
|
||||
|
||||
public:
|
||||
ChatMessageGui(QSharedPointer<ChatMessageCore> core);
|
||||
~ChatMessageGui();
|
||||
ChatMessageCore *getCore() const;
|
||||
QSharedPointer<ChatMessageCore> mCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
173
Linphone/core/chat/message/EventLogCore.cpp
Normal file
173
Linphone/core/chat/message/EventLogCore.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "EventLogCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "model/chat/message/EventLogModel.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventLogCore)
|
||||
|
||||
QSharedPointer<EventLogCore> EventLogCore::create(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
|
||||
auto sharedPointer = QSharedPointer<EventLogCore>(new EventLogCore(eventLog, chatRoom), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
EventLogCore::EventLogCore(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
mEventLogType = LinphoneEnums::fromLinphone(eventLog->getType());
|
||||
mEventLogModel = Utils::makeQObject_ptr<EventLogModel>(eventLog);
|
||||
mTimestamp = QDateTime::fromMSecsSinceEpoch(eventLog->getCreationTime() * 1000);
|
||||
auto chatmessage = eventLog->getChatMessage();
|
||||
if (chatmessage) {
|
||||
mChatMessageCore = ChatMessageCore::create(chatmessage);
|
||||
mEventId = Utils::coreStringToAppString(chatmessage->getMessageId());
|
||||
mTimestamp = QDateTime::fromSecsSinceEpoch(chatmessage->getTime());
|
||||
} else if (eventLog->getCallLog()) {
|
||||
mCallHistoryCore = CallHistoryCore::create(eventLog->getCallLog());
|
||||
mEventId = Utils::coreStringToAppString(eventLog->getCallLog()->getCallId());
|
||||
}
|
||||
if (mEventId.isEmpty()) { // getNotifyId
|
||||
QString type = QString::fromLatin1(
|
||||
QMetaEnum::fromType<LinphoneEnums::EventLogType>().valueToKey(static_cast<int>(mEventLogType)));
|
||||
mEventId = type + QString::number(static_cast<qint64>(eventLog->getCreationTime()));
|
||||
computeEvent(eventLog, chatRoom);
|
||||
}
|
||||
}
|
||||
|
||||
EventLogCore::~EventLogCore() {
|
||||
}
|
||||
|
||||
void EventLogCore::setSelf(QSharedPointer<EventLogCore> me) {
|
||||
}
|
||||
|
||||
QString EventLogCore::getEventLogId() {
|
||||
return mEventId;
|
||||
}
|
||||
|
||||
QSharedPointer<ChatMessageCore> EventLogCore::getChatMessageCore() {
|
||||
return mChatMessageCore;
|
||||
}
|
||||
ChatMessageGui *EventLogCore::getChatMessageGui() {
|
||||
return mChatMessageCore ? new ChatMessageGui(mChatMessageCore) : nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<CallHistoryCore> EventLogCore::getCallHistoryCore() {
|
||||
return mCallHistoryCore;
|
||||
}
|
||||
|
||||
ChatMessageCore *EventLogCore::getChatMessageCorePointer() {
|
||||
return mChatMessageCore.get();
|
||||
}
|
||||
CallHistoryCore *EventLogCore::getCallHistoryCorePointer() {
|
||||
return mCallHistoryCore.get();
|
||||
}
|
||||
|
||||
QDateTime EventLogCore::getTimestamp() const {
|
||||
return mTimestamp;
|
||||
}
|
||||
|
||||
std::shared_ptr<EventLogModel> EventLogCore::getModel() const {
|
||||
return mEventLogModel;
|
||||
}
|
||||
|
||||
// Events (other than ChatMessage and CallLog which are handled in their respective Core)
|
||||
|
||||
void EventLogCore::computeEvent(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom) {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
mHandled = true;
|
||||
mImportant = false;
|
||||
mEphemeralRelated = false;
|
||||
|
||||
auto participantAddress = eventLog->getParticipantAddress() ? eventLog->getParticipantAddress() : nullptr;
|
||||
|
||||
switch (eventLog->getType()) {
|
||||
case linphone::EventLog::Type::ConferenceCreated:
|
||||
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne) &&
|
||||
!chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference))
|
||||
mHandled = false;
|
||||
mEventDetails = tr("conference_created_event");
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceTerminated:
|
||||
if (chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::OneToOne) &&
|
||||
!chatRoom->hasCapability((int)linphone::ChatRoom::Capabilities::Conference))
|
||||
mHandled = false;
|
||||
mEventDetails = tr("conference_created_terminated");
|
||||
mImportant = true;
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceParticipantAdded:
|
||||
mEventDetails = tr("conference_participant_added_event").arg(ToolModel::getDisplayName(participantAddress));
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceParticipantRemoved:
|
||||
mEventDetails =
|
||||
tr("conference_participant_removed_event").arg(ToolModel::getDisplayName(participantAddress));
|
||||
mImportant = true;
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceSecurityEvent: {
|
||||
if (eventLog->getSecurityEventType() == linphone::EventLog::SecurityEventType::SecurityLevelDowngraded) {
|
||||
auto faultyParticipant = eventLog->getSecurityEventFaultyDeviceAddress()
|
||||
? eventLog->getSecurityEventFaultyDeviceAddress()
|
||||
: nullptr;
|
||||
if (faultyParticipant)
|
||||
mEventDetails = tr("conference_security_event").arg(ToolModel::getDisplayName(faultyParticipant));
|
||||
else if (participantAddress)
|
||||
mEventDetails = tr("conference_security_event").arg(ToolModel::getDisplayName(participantAddress));
|
||||
mImportant = true;
|
||||
} else mHandled = false;
|
||||
break;
|
||||
}
|
||||
case linphone::EventLog::Type::ConferenceEphemeralMessageEnabled:
|
||||
mEphemeralRelated = true;
|
||||
mEventDetails = tr("conference_ephemeral_message_enabled_event")
|
||||
.arg(Utils::getEphemeralFormatedTime(eventLog->getEphemeralMessageLifetime()));
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceEphemeralMessageLifetimeChanged:
|
||||
mEphemeralRelated = true;
|
||||
mHandled = eventLog->getEphemeralMessageLifetime() != 0; // Disabled is sent in case of 0.
|
||||
mEventDetails = tr("conference_ephemeral_message_lifetime_changed_event")
|
||||
.arg(Utils::getEphemeralFormatedTime(eventLog->getEphemeralMessageLifetime()));
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceEphemeralMessageDisabled:
|
||||
mEphemeralRelated = true;
|
||||
mEventDetails = tr("conference_ephemeral_message_disabled_event");
|
||||
mImportant = true;
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceSubjectChanged:
|
||||
mEventDetails = tr("conference_subject_changed_event").arg(QString::fromStdString(eventLog->getSubject()));
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceParticipantSetAdmin:
|
||||
mEventDetails =
|
||||
tr("conference_participant_set_admin_event").arg(ToolModel::getDisplayName(participantAddress));
|
||||
break;
|
||||
case linphone::EventLog::Type::ConferenceParticipantUnsetAdmin:
|
||||
mEventDetails =
|
||||
tr("conference_participant_unset_admin_event").arg(ToolModel::getDisplayName(participantAddress));
|
||||
break;
|
||||
default:
|
||||
mHandled = false;
|
||||
}
|
||||
}
|
||||
96
Linphone/core/chat/message/EventLogCore.hpp
Normal file
96
Linphone/core/chat/message/EventLogCore.hpp
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_LOG_CORE_H_
|
||||
#define EVENT_LOG_CORE_H_
|
||||
|
||||
#include "ChatMessageCore.hpp"
|
||||
#include "core/call-history/CallHistoryCore.hpp"
|
||||
#include "core/conference/ConferenceInfoCore.hpp"
|
||||
#include "core/conference/ConferenceInfoGui.hpp"
|
||||
#include "model/chat/message/ChatMessageModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
class ChatMessageCore;
|
||||
class ChatMessageGui;
|
||||
class EventLogModel;
|
||||
|
||||
class EventLogCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(LinphoneEnums::EventLogType type MEMBER mEventLogType CONSTANT)
|
||||
Q_PROPERTY(ChatMessageGui *chatMessageGui READ getChatMessageGui CONSTANT)
|
||||
// Q_PROPERTY(NotifyCore *notification MEMBER mNotifyCore CONSTANT)
|
||||
Q_PROPERTY(CallHistoryCore *callLog READ getCallHistoryCorePointer CONSTANT)
|
||||
Q_PROPERTY(bool important MEMBER mImportant CONSTANT)
|
||||
Q_PROPERTY(bool handled MEMBER mHandled CONSTANT)
|
||||
Q_PROPERTY(QString eventDetails MEMBER mEventDetails CONSTANT)
|
||||
Q_PROPERTY(QDateTime timestamp READ getTimestamp CONSTANT)
|
||||
|
||||
public:
|
||||
static QSharedPointer<EventLogCore> create(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom);
|
||||
EventLogCore(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom);
|
||||
~EventLogCore();
|
||||
void setSelf(QSharedPointer<EventLogCore> me);
|
||||
QString getEventLogId();
|
||||
QSharedPointer<ChatMessageCore> getChatMessageCore();
|
||||
ChatMessageGui *getChatMessageGui();
|
||||
QSharedPointer<CallHistoryCore> getCallHistoryCore();
|
||||
|
||||
QDateTime getTimestamp() const;
|
||||
|
||||
bool isHandled() const {
|
||||
return mHandled;
|
||||
}
|
||||
bool isEphemeralRelated() const {
|
||||
return mEphemeralRelated;
|
||||
}
|
||||
|
||||
std::shared_ptr<EventLogModel> getModel() const;
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
QString mEventId;
|
||||
|
||||
QSharedPointer<ChatMessageCore> mChatMessageCore = nullptr;
|
||||
QSharedPointer<CallHistoryCore> mCallHistoryCore = nullptr;
|
||||
LinphoneEnums::EventLogType mEventLogType;
|
||||
bool mHandled = false;
|
||||
bool mImportant;
|
||||
bool mEphemeralRelated;
|
||||
QString mEventDetails;
|
||||
QDateTime mTimestamp;
|
||||
|
||||
ChatMessageCore *getChatMessageCorePointer();
|
||||
CallHistoryCore *getCallHistoryCorePointer();
|
||||
std::shared_ptr<EventLogModel> mEventLogModel;
|
||||
void computeEvent(const std::shared_ptr<const linphone::EventLog> &eventLog,
|
||||
const std::shared_ptr<linphone::ChatRoom> &chatRoom);
|
||||
};
|
||||
|
||||
#endif // EventLogCore_H_
|
||||
38
Linphone/core/chat/message/EventLogGui.cpp
Normal file
38
Linphone/core/chat/message/EventLogGui.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "EventLogGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventLogGui)
|
||||
|
||||
EventLogGui::EventLogGui(QSharedPointer<EventLogCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
EventLogGui::~EventLogGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
EventLogCore *EventLogGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
41
Linphone/core/chat/message/EventLogGui.hpp
Normal file
41
Linphone/core/chat/message/EventLogGui.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_LOG_GUI_H_
|
||||
#define EVENT_LOG_GUI_H_
|
||||
|
||||
#include "EventLogCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class EventLogGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(EventLogCore *core READ getCore CONSTANT)
|
||||
|
||||
public:
|
||||
EventLogGui(QSharedPointer<EventLogCore> core);
|
||||
~EventLogGui();
|
||||
EventLogCore *getCore() const;
|
||||
QSharedPointer<EventLogCore> mCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
391
Linphone/core/chat/message/EventLogList.cpp
Normal file
391
Linphone/core/chat/message/EventLogList.cpp
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "EventLogList.hpp"
|
||||
#include "ChatMessageCore.hpp"
|
||||
#include "ChatMessageGui.hpp"
|
||||
#include "EventLogGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/call-history/CallHistoryGui.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
#include "model/chat/message/EventLogModel.hpp"
|
||||
#include <QSharedPointer>
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventLogList)
|
||||
|
||||
QSharedPointer<EventLogList> EventLogList::create() {
|
||||
auto model = QSharedPointer<EventLogList>(new EventLogList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
model->setSelf(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
EventLogList::EventLogList(QObject *parent) : ListProxy(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
EventLogList::~EventLogList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
ChatGui *EventLogList::getChat() const {
|
||||
if (mChatCore) return new ChatGui(mChatCore);
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<ChatCore> EventLogList::getChatCore() const {
|
||||
return mChatCore;
|
||||
}
|
||||
|
||||
void EventLogList::disconnectItem(const QSharedPointer<EventLogCore> &item) {
|
||||
auto message = item->getChatMessageCore();
|
||||
if (message) {
|
||||
disconnect(message.get(), &ChatMessageCore::isReadChanged, this, nullptr);
|
||||
disconnect(message.get(), &ChatMessageCore::deleted, this, nullptr);
|
||||
disconnect(message.get(), &ChatMessageCore::edited, this, nullptr);
|
||||
disconnect(message.get(), &ChatMessageCore::isRetractedChanged, this, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::connectItem(const QSharedPointer<EventLogCore> &item) {
|
||||
auto message = item->getChatMessageCore();
|
||||
if (message) {
|
||||
connect(message.get(), &ChatMessageCore::isReadChanged, this, [this] {
|
||||
if (mChatCore) emit mChatCore->lUpdateUnreadCount();
|
||||
});
|
||||
connect(message.get(), &ChatMessageCore::deleted, this, [this, item] {
|
||||
if (mChatCore) emit mChatCore->lUpdateLastMessage();
|
||||
remove(item);
|
||||
});
|
||||
connect(message.get(), &ChatMessageCore::isRetractedChanged, this, [this, item] {
|
||||
if (mChatCore) emit mChatCore->lUpdateUnreadCount();
|
||||
});
|
||||
connect(message.get(), &ChatMessageCore::edited, this, [this, item] {
|
||||
auto eventLogModel = item->getModel();
|
||||
mCoreModelConnection->invokeToModel([this, eventLogModel, item]() {
|
||||
auto chatRoom = mChatCore->getModel()->getMonitor();
|
||||
auto newEventLog = EventLogCore::create(eventLogModel->getEventLog(), chatRoom);
|
||||
bool wasLastMessage =
|
||||
mChatCore->getModel()->getLastChatMessage() == eventLogModel->getEventLog()->getChatMessage();
|
||||
mCoreModelConnection->invokeToCore([this, newEventLog, wasLastMessage, item] {
|
||||
connectItem(newEventLog);
|
||||
replace(item, newEventLog);
|
||||
if (wasLastMessage) mChatCore->setLastMessage(newEventLog->getChatMessageCore());
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::setChatCore(QSharedPointer<ChatCore> core) {
|
||||
if (mChatCore != core) {
|
||||
if (mChatCore) {
|
||||
disconnect(mChatCore.get(), &ChatCore::eventsInserted, this, nullptr);
|
||||
disconnect(mChatCore.get(), &ChatCore::eventListCleared, this, nullptr);
|
||||
}
|
||||
mChatCore = core;
|
||||
if (mChatCore) {
|
||||
connect(mChatCore.get(), &ChatCore::eventListCleared, this, [this] { resetData(); });
|
||||
connect(mChatCore.get(), &ChatCore::eventsInserted, this, [this](QList<QSharedPointer<EventLogCore>> list) {
|
||||
auto eventsList = getSharedList<EventLogCore>();
|
||||
for (auto &event : list) {
|
||||
auto it = std::find_if(eventsList.begin(), eventsList.end(),
|
||||
[event](const QSharedPointer<EventLogCore> item) { return item == event; });
|
||||
if (it == eventsList.end()) {
|
||||
connectItem(event);
|
||||
prepend(event);
|
||||
int index;
|
||||
get(event.get(), &index);
|
||||
if (event->getChatMessageCore() && !event->getChatMessageCore()->isRemoteMessage()) {
|
||||
emit eventInsertedByUser(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
lUpdate();
|
||||
// setIsUpdating(false);
|
||||
emit chatGuiChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::setChatGui(ChatGui *chat) {
|
||||
auto chatCore = chat ? chat->mCore : nullptr;
|
||||
setChatCore(chatCore);
|
||||
}
|
||||
|
||||
void EventLogList::setDisplayItemsStep(int displayItemsStep) {
|
||||
if (mDisplayItemsStep != displayItemsStep) {
|
||||
mDisplayItemsStep = displayItemsStep;
|
||||
emit displayItemsStepChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::markIndexAsRead(int index) {
|
||||
if (index < mList.count()) {
|
||||
auto eventLog = mList[index].objectCast<EventLogCore>();
|
||||
if (eventLog && eventLog->getChatMessageCore()) eventLog->getChatMessageCore()->lMarkAsRead();
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::displayMore() {
|
||||
auto loadMoreItems = [this] {
|
||||
if (!mChatCore) return;
|
||||
auto chatModel = mChatCore->getModel();
|
||||
if (!chatModel) return;
|
||||
mCoreModelConnection->invokeToModel([this, chatModel]() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
int maxSize = chatModel->getHistorySizeEvents();
|
||||
int totalItemsCount = mList.count();
|
||||
auto newCount = std::min(totalItemsCount + mDisplayItemsStep, maxSize);
|
||||
if (newCount <= totalItemsCount) {
|
||||
return;
|
||||
}
|
||||
auto linphoneLogs = chatModel->getHistoryRange(totalItemsCount, newCount);
|
||||
QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>();
|
||||
for (auto it : linphoneLogs) {
|
||||
auto model = EventLogCore::create(it, chatModel->getMonitor());
|
||||
if (it->getChatMessage() || model->isHandled()) events->push_front(model);
|
||||
}
|
||||
mCoreModelConnection->invokeToCore([this, events] {
|
||||
int currentCount = mList.count();
|
||||
if (!events->isEmpty()) {
|
||||
for (int i = events->size() - 1; i >= 0; --i) {
|
||||
const auto &ev = events->at(i);
|
||||
connectItem(ev);
|
||||
}
|
||||
add(*events);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
if (mIsUpdating) {
|
||||
connect(this, &EventLogList::isUpdatingChanged, this, [this, loadMoreItems] {
|
||||
if (!mIsUpdating) {
|
||||
disconnect(this, &EventLogList::isUpdatingChanged, this, nullptr);
|
||||
loadMoreItems();
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else loadMoreItems();
|
||||
}
|
||||
|
||||
void EventLogList::loadMessagesUpTo(std::shared_ptr<linphone::EventLog> event) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto oldestEventLoaded = mList.count() > 0 ? getAt<EventLogCore>(mList.count() - 1) : nullptr;
|
||||
auto linOldest = oldestEventLoaded
|
||||
? std::const_pointer_cast<linphone::EventLog>(oldestEventLoaded->getModel()->getEventLog())
|
||||
: nullptr;
|
||||
auto chatModel = mChatCore->getModel();
|
||||
assert(chatModel);
|
||||
if (!chatModel) return;
|
||||
int filters = static_cast<int>(linphone::ChatRoom::HistoryFilter::ChatMessage) |
|
||||
static_cast<int>(linphone::ChatRoom::HistoryFilter::InfoNoDevice);
|
||||
auto beforeEvents = chatModel->getHistoryRangeNear(mItemsToLoadBeforeSearchResult, 0, event, filters);
|
||||
auto linphoneLogs = chatModel->getHistoryRangeBetween(event, linOldest, filters);
|
||||
QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>();
|
||||
const auto &linChatRoom = chatModel->getMonitor();
|
||||
for (const auto &it : beforeEvents) {
|
||||
auto model = EventLogCore::create(it, linChatRoom);
|
||||
if (it->getChatMessage() || model->isHandled()) events->push_front(model);
|
||||
}
|
||||
for (const auto &it : linphoneLogs) {
|
||||
auto model = EventLogCore::create(it, linChatRoom);
|
||||
if (it->getChatMessage() || model->isHandled()) events->push_front(model);
|
||||
}
|
||||
mCoreModelConnection->invokeToCore([this, events, event] {
|
||||
for (const auto &e : *events) {
|
||||
connectItem(e);
|
||||
}
|
||||
add(*events);
|
||||
emit messagesLoadedUpTo(event);
|
||||
});
|
||||
}
|
||||
|
||||
int EventLogList::findFirstUnreadIndex() {
|
||||
auto eventList = getSharedList<EventLogCore>();
|
||||
auto it = std::find_if(eventList.rbegin(), eventList.rend(), [](const QSharedPointer<EventLogCore> item) {
|
||||
auto chatmessage = item->getChatMessageCore();
|
||||
return chatmessage && !chatmessage->isRead();
|
||||
});
|
||||
return it == eventList.rend() ? -1 : std::distance(it, eventList.rend()) - 1;
|
||||
}
|
||||
|
||||
void EventLogList::findChatMessageWithFilter(QString filter, int startIndex, bool forward, bool isFirstResearch) {
|
||||
if (mChatCore) {
|
||||
if (isFirstResearch) mLastFoundResult.reset();
|
||||
auto chatModel = mChatCore->getModel();
|
||||
auto startEvent =
|
||||
startIndex >= 0 && startIndex < mList.count() ? mList[startIndex].objectCast<EventLogCore>() : nullptr;
|
||||
lInfo() << log().arg("searching event starting from index") << startIndex << "| event :"
|
||||
<< (startEvent && startEvent->getChatMessageCore() ? startEvent->getChatMessageCore()->getText()
|
||||
: "null")
|
||||
<< "| filter :" << filter;
|
||||
auto startEventModel = startEvent ? startEvent->getModel() : nullptr;
|
||||
mCoreModelConnection->invokeToModel([this, chatModel, startEventModel, filter, forward, isFirstResearch] {
|
||||
auto linStartEvent = startEventModel ? startEventModel->getEventLog() : nullptr;
|
||||
auto eventLog = chatModel->searchMessageByText(filter, linStartEvent, forward);
|
||||
if (!eventLog) {
|
||||
// event not found, search in the entire history
|
||||
lInfo() << log().arg("not found, search in entire history");
|
||||
auto eventLog = chatModel->searchMessageByText(filter, nullptr, forward);
|
||||
}
|
||||
int index = -1;
|
||||
if (eventLog) {
|
||||
lInfo() << log().arg("event with filter found") << eventLog.get();
|
||||
auto eventList = getSharedList<EventLogCore>();
|
||||
auto it = std::find_if(eventList.begin(), eventList.end(),
|
||||
[eventLog](const QSharedPointer<EventLogCore> item) {
|
||||
return item->getModel()->getEventLog() == eventLog;
|
||||
});
|
||||
if (it != eventList.end()) {
|
||||
int index = std::distance(eventList.begin(), it);
|
||||
if (mLastFoundResult && mLastFoundResult == *it) index = -1;
|
||||
mLastFoundResult = *it;
|
||||
mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); });
|
||||
} else {
|
||||
connect(this, &EventLogList::messagesLoadedUpTo, this,
|
||||
[this](std::shared_ptr<linphone::EventLog> event) {
|
||||
auto eventList = getSharedList<EventLogCore>();
|
||||
auto it = std::find_if(eventList.begin(), eventList.end(),
|
||||
[event](const QSharedPointer<EventLogCore> item) {
|
||||
return item->getModel()->getEventLog() == event;
|
||||
});
|
||||
int index = it != eventList.end() ? std::distance(eventList.begin(), it) : -1;
|
||||
if (mLastFoundResult && mLastFoundResult == *it) index = -1;
|
||||
mLastFoundResult = *it;
|
||||
mCoreModelConnection->invokeToCore(
|
||||
[this, index] { emit messageWithFilterFound(index); });
|
||||
});
|
||||
loadMessagesUpTo(eventLog);
|
||||
}
|
||||
} else {
|
||||
lInfo() << log().arg("event not found at all in history");
|
||||
mCoreModelConnection->invokeToCore([this, index] { emit messageWithFilterFound(index); });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogList::setSelf(QSharedPointer<EventLogList> me) {
|
||||
mCoreModelConnection = SafeConnection<EventLogList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
|
||||
mCoreModelConnection->makeConnectToCore(&EventLogList::lUpdate, [this]() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mIsUpdating) {
|
||||
connect(this, &EventLogList::isUpdatingChanged, this, [this] {
|
||||
if (!mIsUpdating) {
|
||||
disconnect(this, &EventLogList::isUpdatingChanged, this, nullptr);
|
||||
lUpdate();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
setIsUpdating(true);
|
||||
beginResetModel();
|
||||
for (auto &event : getSharedList<EventLogCore>()) {
|
||||
disconnectItem(event);
|
||||
}
|
||||
mList.clear();
|
||||
if (!mChatCore) {
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
return;
|
||||
}
|
||||
auto chatModel = mChatCore->getModel();
|
||||
if (!chatModel) {
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
return;
|
||||
}
|
||||
mCoreModelConnection->invokeToModel([this, chatModel]() {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto linphoneLogs = chatModel->getHistoryRange(0, mDisplayItemsStep);
|
||||
QList<QSharedPointer<EventLogCore>> *events = new QList<QSharedPointer<EventLogCore>>();
|
||||
for (auto it : linphoneLogs) {
|
||||
auto model = EventLogCore::create(it, chatModel->getMonitor());
|
||||
if (it->getChatMessage() || model->isHandled()) events->push_front(model);
|
||||
}
|
||||
mCoreModelConnection->invokeToCore([this, events] {
|
||||
for (auto &event : *events) {
|
||||
connectItem(event);
|
||||
mList.append(event);
|
||||
}
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
connect(this, &EventLogList::filterChanged, [this](QString filter) {
|
||||
mFilter = filter;
|
||||
lUpdate();
|
||||
});
|
||||
lUpdate();
|
||||
}
|
||||
|
||||
QVariant EventLogList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
|
||||
auto core = mList[row].objectCast<EventLogCore>();
|
||||
if (core->getChatMessageCore()) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QVariant::fromValue(new EventLogGui(core));
|
||||
case Qt::DisplayRole + 1:
|
||||
return "chatMessage";
|
||||
}
|
||||
} else if (core->getCallHistoryCore()) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QVariant::fromValue(new EventLogGui(core));
|
||||
case Qt::DisplayRole + 1:
|
||||
return "callLog";
|
||||
}
|
||||
} else if (core->isEphemeralRelated()) {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QVariant::fromValue(new EventLogGui(core));
|
||||
case Qt::DisplayRole + 1:
|
||||
return "ephemeralEvent";
|
||||
}
|
||||
} else {
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return QVariant::fromValue(new EventLogGui(core));
|
||||
case Qt::DisplayRole + 1:
|
||||
return "event";
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> EventLogList::roleNames() const {
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Qt::DisplayRole] = "modelData";
|
||||
roles[Qt::DisplayRole + 1] = "eventType";
|
||||
return roles;
|
||||
}
|
||||
88
Linphone/core/chat/message/EventLogList.hpp
Normal file
88
Linphone/core/chat/message/EventLogList.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_LOG_LIST_H_
|
||||
#define EVENT_LOG_LIST_H_
|
||||
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
class EventLogGui;
|
||||
class EventLogCore;
|
||||
class ChatCore;
|
||||
class ChatGui;
|
||||
class ChatModel;
|
||||
// =============================================================================
|
||||
|
||||
class EventLogList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<EventLogList> create();
|
||||
EventLogList(QObject *parent = Q_NULLPTR);
|
||||
~EventLogList();
|
||||
|
||||
QSharedPointer<ChatCore> getChatCore() const;
|
||||
ChatGui *getChat() const;
|
||||
void setChatCore(QSharedPointer<ChatCore> core);
|
||||
void setChatGui(ChatGui *chat);
|
||||
|
||||
void connectItem(const QSharedPointer<EventLogCore> &item);
|
||||
void disconnectItem(const QSharedPointer<EventLogCore> &item);
|
||||
|
||||
void loadMessagesUpTo(std::shared_ptr<linphone::EventLog> event);
|
||||
|
||||
void setLastFoundResult(const QSharedPointer<EventLogCore> &eventLog);
|
||||
|
||||
int findFirstUnreadIndex();
|
||||
|
||||
void markIndexAsRead(int index);
|
||||
|
||||
void displayMore();
|
||||
void setDisplayItemsStep(int displayItemsStep);
|
||||
|
||||
void findChatMessageWithFilter(QString filter, int startIndex, bool forward = true, bool isFirstResearch = true);
|
||||
|
||||
void setSelf(QSharedPointer<EventLogList> me);
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
signals:
|
||||
void lUpdate();
|
||||
void filterChanged(QString filter);
|
||||
void eventInsertedByUser(int index);
|
||||
void messageWithFilterFound(int index);
|
||||
void listAboutToBeReset();
|
||||
void chatGuiChanged();
|
||||
void displayItemsStepChanged();
|
||||
void messagesLoadedUpTo(std::shared_ptr<linphone::EventLog> event);
|
||||
|
||||
private:
|
||||
QString mFilter;
|
||||
QSharedPointer<ChatCore> mChatCore;
|
||||
QSharedPointer<SafeConnection<EventLogList, CoreModel>> mCoreModelConnection;
|
||||
int mDisplayItemsStep = 0;
|
||||
int mItemsToLoadBeforeSearchResult = 3;
|
||||
QSharedPointer<EventLogCore> mLastFoundResult;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
208
Linphone/core/chat/message/EventLogProxy.cpp
Normal file
208
Linphone/core/chat/message/EventLogProxy.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "EventLogProxy.hpp"
|
||||
#include "EventLogGui.hpp"
|
||||
#include "EventLogList.hpp"
|
||||
// #include "core/chat/ChatGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventLogProxy)
|
||||
|
||||
EventLogProxy::EventLogProxy(QObject *parent) : QSortFilterProxyModel(parent) {
|
||||
mList = EventLogList::create();
|
||||
setSourceModel(mList.get());
|
||||
}
|
||||
|
||||
EventLogProxy::~EventLogProxy() {
|
||||
}
|
||||
|
||||
void EventLogProxy::setSourceModel(QAbstractItemModel *model) {
|
||||
auto oldEventLogList = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (oldEventLogList) {
|
||||
disconnect(oldEventLogList, &EventLogList::displayItemsStepChanged, this, nullptr);
|
||||
disconnect(oldEventLogList, &EventLogList::messageWithFilterFound, this, nullptr);
|
||||
disconnect(oldEventLogList, &EventLogList::eventInsertedByUser, this, nullptr);
|
||||
}
|
||||
auto newEventLogList = dynamic_cast<EventLogList *>(model);
|
||||
if (newEventLogList) {
|
||||
connect(this, &EventLogProxy::displayItemsStepChanged, newEventLogList,
|
||||
[this, newEventLogList] { newEventLogList->setDisplayItemsStep(mDisplayItemsStep); });
|
||||
connect(newEventLogList, &EventLogList::messageWithFilterFound, this, [this, newEventLogList](int i) {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
int proxyIndex = mapFromSource(newEventLogList->index(i, 0)).row();
|
||||
if (i != -1) {
|
||||
loadUntil(proxyIndex);
|
||||
}
|
||||
emit indexWithFilterFound(proxyIndex);
|
||||
});
|
||||
connect(newEventLogList, &EventLogList::eventInsertedByUser, this, [this, newEventLogList](int i) {
|
||||
int proxyIndex = mapFromSource(newEventLogList->index(i, 0)).row();
|
||||
emit eventInsertedByUser(proxyIndex);
|
||||
});
|
||||
}
|
||||
QSortFilterProxyModel::setSourceModel(model);
|
||||
}
|
||||
|
||||
ChatGui *EventLogProxy::getChatGui() {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (!mChatGui && model) mChatGui = model->getChat();
|
||||
return mChatGui;
|
||||
}
|
||||
|
||||
void EventLogProxy::setChatGui(ChatGui *chat) {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (model) model->setChatGui(chat);
|
||||
}
|
||||
|
||||
EventLogGui *EventLogProxy::getEventAtIndex(int i) {
|
||||
auto eventCore = getEventCoreAtIndex(i);
|
||||
return eventCore == nullptr ? nullptr : new EventLogGui(eventCore);
|
||||
}
|
||||
|
||||
int EventLogProxy::getCount() const {
|
||||
return rowCount();
|
||||
}
|
||||
|
||||
int EventLogProxy::getInitialDisplayItems() const {
|
||||
return mInitialDisplayItems;
|
||||
}
|
||||
|
||||
void EventLogProxy::setInitialDisplayItems(int initialItems) {
|
||||
if (mInitialDisplayItems != initialItems) {
|
||||
mInitialDisplayItems = initialItems;
|
||||
if (getMaxDisplayItems() <= mInitialDisplayItems) setMaxDisplayItems(initialItems);
|
||||
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(initialItems);
|
||||
emit initialDisplayItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int EventLogProxy::getDisplayCount(int listCount, int maxCount) {
|
||||
return maxCount >= 0 ? qMin(listCount, maxCount) : listCount;
|
||||
}
|
||||
|
||||
int EventLogProxy::getDisplayCount(int listCount) const {
|
||||
return getDisplayCount(listCount, mMaxDisplayItems);
|
||||
}
|
||||
|
||||
QSharedPointer<EventLogCore> EventLogProxy::getEventCoreAtIndex(int i) {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (model) {
|
||||
return model->getAt<EventLogCore>(mapToSource(index(i, 0)).row());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EventLogProxy::displayMore() {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (model) {
|
||||
model->displayMore();
|
||||
}
|
||||
}
|
||||
int EventLogProxy::getMaxDisplayItems() const {
|
||||
return mMaxDisplayItems;
|
||||
}
|
||||
|
||||
void EventLogProxy::setMaxDisplayItems(int maxItems) {
|
||||
if (mMaxDisplayItems != maxItems) {
|
||||
auto model = sourceModel();
|
||||
int modelCount = model ? model->rowCount() : 0;
|
||||
int oldCount = getDisplayCount(modelCount);
|
||||
mMaxDisplayItems = maxItems;
|
||||
if (getInitialDisplayItems() > mMaxDisplayItems) setInitialDisplayItems(maxItems);
|
||||
if (getDisplayItemsStep() <= 0) setDisplayItemsStep(maxItems);
|
||||
emit maxDisplayItemsChanged();
|
||||
|
||||
if (model && getDisplayCount(modelCount) != oldCount) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EventLogProxy::getDisplayItemsStep() const {
|
||||
return mDisplayItemsStep;
|
||||
}
|
||||
|
||||
void EventLogProxy::setDisplayItemsStep(int step) {
|
||||
if (step > 0 && mDisplayItemsStep != step) {
|
||||
mDisplayItemsStep = step;
|
||||
emit displayItemsStepChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void EventLogProxy::loadUntil(int index) {
|
||||
if (mMaxDisplayItems < index) setMaxDisplayItems(index + mDisplayItemsStep);
|
||||
}
|
||||
|
||||
int EventLogProxy::findFirstUnreadIndex() {
|
||||
auto eventLogList = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (eventLogList) {
|
||||
auto listIndex = eventLogList->findFirstUnreadIndex();
|
||||
if (listIndex != -1) {
|
||||
listIndex = mapFromSource(eventLogList->index(listIndex, 0)).row();
|
||||
if (mMaxDisplayItems <= listIndex) setMaxDisplayItems(listIndex + mDisplayItemsStep);
|
||||
return listIndex;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString EventLogProxy::getFilterText() const {
|
||||
return mFilterText;
|
||||
}
|
||||
|
||||
void EventLogProxy::setFilterText(const QString &filter) {
|
||||
if (mFilterText != filter) {
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||
beginFilterChange();
|
||||
mFilterText = filter;
|
||||
endFilterChange();
|
||||
#else
|
||||
mFilterText = filter;
|
||||
invalidateFilter();
|
||||
#endif
|
||||
emit filterTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<EventLogCore> EventLogProxy::getAt(int atIndex) const {
|
||||
auto model = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (model) {
|
||||
return model->getAt<EventLogCore>(mapToSource(index(atIndex, 0)).row());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void EventLogProxy::markIndexAsRead(int proxyIndex) {
|
||||
auto event = getAt(proxyIndex);
|
||||
if (event && event->getChatMessageCore()) event->getChatMessageCore()->lMarkAsRead();
|
||||
}
|
||||
|
||||
void EventLogProxy::findIndexCorrespondingToFilter(int startIndex, bool forward, bool isFirstResearch) {
|
||||
auto filter = getFilterText();
|
||||
if (filter.isEmpty()) return;
|
||||
auto eventLogList = dynamic_cast<EventLogList *>(sourceModel());
|
||||
if (eventLogList) {
|
||||
auto listIndex = mapToSource(index(startIndex, 0)).row();
|
||||
eventLogList->findChatMessageWithFilter(filter, listIndex, forward, isFirstResearch);
|
||||
}
|
||||
}
|
||||
102
Linphone/core/chat/message/EventLogProxy.hpp
Normal file
102
Linphone/core/chat/message/EventLogProxy.hpp
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_LIST_PROXY_H_
|
||||
#define EVENT_LIST_PROXY_H_
|
||||
|
||||
#include "EventLogList.hpp"
|
||||
// #include "core/proxy/LimitProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ChatGui;
|
||||
|
||||
class EventLogProxy : public QSortFilterProxyModel, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ getCount NOTIFY countChanged)
|
||||
Q_PROPERTY(ChatGui *chatGui READ getChatGui WRITE setChatGui NOTIFY chatGuiChanged)
|
||||
Q_PROPERTY(int initialDisplayItems READ getInitialDisplayItems WRITE setInitialDisplayItems NOTIFY
|
||||
initialDisplayItemsChanged)
|
||||
Q_PROPERTY(int maxDisplayItems READ getMaxDisplayItems WRITE setMaxDisplayItems NOTIFY maxDisplayItemsChanged)
|
||||
Q_PROPERTY(int displayItemsStep READ getDisplayItemsStep WRITE setDisplayItemsStep NOTIFY displayItemsStepChanged)
|
||||
Q_PROPERTY(QString filterText READ getFilterText WRITE setFilterText NOTIFY filterTextChanged)
|
||||
|
||||
public:
|
||||
// DECLARE_SORTFILTER_CLASS()
|
||||
|
||||
EventLogProxy(QObject *parent = Q_NULLPTR);
|
||||
~EventLogProxy();
|
||||
|
||||
ChatGui *getChatGui();
|
||||
void setChatGui(ChatGui *chat);
|
||||
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
virtual int getCount() const;
|
||||
static int getDisplayCount(int listCount, int maxCount);
|
||||
int getDisplayCount(int listCount) const;
|
||||
int getInitialDisplayItems() const;
|
||||
void setInitialDisplayItems(int initialItems);
|
||||
|
||||
int getMaxDisplayItems() const;
|
||||
void setMaxDisplayItems(int maxItems);
|
||||
|
||||
int getDisplayItemsStep() const;
|
||||
void setDisplayItemsStep(int step);
|
||||
|
||||
QString getFilterText() const;
|
||||
void setFilterText(const QString &filter);
|
||||
|
||||
// bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
// bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
|
||||
|
||||
QSharedPointer<EventLogCore> getAt(int atIndex) const;
|
||||
|
||||
Q_INVOKABLE void displayMore();
|
||||
Q_INVOKABLE void loadUntil(int index);
|
||||
Q_INVOKABLE EventLogGui *getEventAtIndex(int i);
|
||||
QSharedPointer<EventLogCore> getEventCoreAtIndex(int i);
|
||||
Q_INVOKABLE int findFirstUnreadIndex();
|
||||
Q_INVOKABLE void markIndexAsRead(int proxyIndex);
|
||||
Q_INVOKABLE void findIndexCorrespondingToFilter(int startIndex, bool forward = true, bool isFirstResearch = true);
|
||||
|
||||
signals:
|
||||
void eventInsertedByUser(int index);
|
||||
void indexWithFilterFound(int index);
|
||||
void chatGuiChanged();
|
||||
void countChanged();
|
||||
void initialDisplayItemsChanged();
|
||||
void maxDisplayItemsChanged();
|
||||
void displayItemsStepChanged();
|
||||
void filterTextChanged();
|
||||
|
||||
protected:
|
||||
QSharedPointer<EventLogList> mList;
|
||||
QSharedPointer<EventLogCore> mLastSearchStart;
|
||||
ChatGui *mChatGui = nullptr;
|
||||
int mInitialDisplayItems = -1;
|
||||
int mMaxDisplayItems = -1;
|
||||
int mDisplayItemsStep = 5;
|
||||
QString mFilterText;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
272
Linphone/core/chat/message/content/ChatMessageContentCore.cpp
Normal file
272
Linphone/core/chat/message/content/ChatMessageContentCore.cpp
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageContentCore.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/providers/ThumbnailProvider.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageContentCore)
|
||||
|
||||
QSharedPointer<ChatMessageContentCore>
|
||||
ChatMessageContentCore::create(const std::shared_ptr<linphone::Content> &content,
|
||||
std::shared_ptr<ChatMessageModel> chatMessageModel) {
|
||||
auto sharedPointer = QSharedPointer<ChatMessageContentCore>(new ChatMessageContentCore(content, chatMessageModel),
|
||||
&QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
ChatMessageContentCore::ChatMessageContentCore(const std::shared_ptr<linphone::Content> &content,
|
||||
std::shared_ptr<ChatMessageModel> chatMessageModel) {
|
||||
if (content) {
|
||||
mName = Utils::coreStringToAppString(content->getName());
|
||||
if (mName.isEmpty()) { // Try to find the name from file Path
|
||||
QString fileName = Utils::coreStringToAppString(content->getFilePath());
|
||||
if (!fileName.isEmpty()) {
|
||||
mName = QFileInfo(fileName).baseName();
|
||||
}
|
||||
}
|
||||
mFilePath = QDir::fromNativeSeparators(Utils::coreStringToAppString(content->getFilePath()));
|
||||
mIsFile = content->isFile();
|
||||
mIsFileEncrypted = content->isFileEncrypted();
|
||||
mIsFileTransfer = content->isFileTransfer();
|
||||
mIsCalendar = content->isIcalendar();
|
||||
if (content->isIcalendar()) {
|
||||
auto conferenceInfo = linphone::Factory::get()->createConferenceInfoFromIcalendarContent(content);
|
||||
mConferenceInfo = ConferenceInfoCore::create(conferenceInfo);
|
||||
}
|
||||
mIsMultipart = content->isMultipart();
|
||||
mIsText = content->isText();
|
||||
mIsVoiceRecording = content->isVoiceRecording();
|
||||
mIsVideo = Utils::isVideo(mFilePath);
|
||||
mFileSize = (quint64)content->getFileSize();
|
||||
mFileDuration = content->getFileDuration();
|
||||
mFileOffset = 0;
|
||||
mUtf8Text = Utils::coreStringToAppString(content->getUtf8Text());
|
||||
auto chatRoom = chatMessageModel ? chatMessageModel->getMonitor()->getChatRoom() : nullptr;
|
||||
mRichFormatText = ToolModel::encodeTextToQmlRichFormat(mUtf8Text, {}, chatRoom);
|
||||
mWasDownloaded = !mFilePath.isEmpty() && QFileInfo(mFilePath).isFile();
|
||||
mThumbnail = mFilePath.isEmpty()
|
||||
? QUrl()
|
||||
: QUrl(QString("image://%1/%2").arg(ThumbnailProvider::ProviderId).arg(mFilePath));
|
||||
mChatMessageContentModel = Utils::makeQObject_ptr<ChatMessageContentModel>(content, chatMessageModel);
|
||||
}
|
||||
}
|
||||
|
||||
ChatMessageContentCore ::~ChatMessageContentCore() {
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setSelf(QSharedPointer<ChatMessageContentCore> me) {
|
||||
mChatMessageContentModelConnection =
|
||||
SafeConnection<ChatMessageContentCore, ChatMessageContentModel>::create(me, mChatMessageContentModel);
|
||||
|
||||
auto updateThumbnailType = [this] {
|
||||
if (Utils::isVideo(mFilePath)) mIsVideo = true;
|
||||
emit isVideoChanged();
|
||||
};
|
||||
|
||||
mChatMessageContentModelConnection->makeConnectToCore(
|
||||
&ChatMessageContentCore::lCreateThumbnail, [this](const bool &force = false) {
|
||||
mChatMessageContentModelConnection->invokeToModel(
|
||||
[this, force] { mChatMessageContentModel->createThumbnail(); });
|
||||
});
|
||||
mChatMessageContentModelConnection->makeConnectToModel(
|
||||
&ChatMessageContentModel::thumbnailChanged, [this, updateThumbnailType](QString thumbnail) {
|
||||
mChatMessageContentModelConnection->invokeToCore([this, thumbnail] { setThumbnail(QUrl(thumbnail)); });
|
||||
});
|
||||
|
||||
mChatMessageContentModelConnection->makeConnectToCore(&ChatMessageContentCore::lDownloadFile, [this]() {
|
||||
mChatMessageContentModelConnection->invokeToModel([this] {
|
||||
QString *error = new QString();
|
||||
bool downloaded = mChatMessageContentModel->downloadFile(mName, error);
|
||||
if (!downloaded) {
|
||||
mChatMessageContentModelConnection->invokeToCore([this, error] {
|
||||
//: Error downloading file %1
|
||||
if (error->isEmpty()) *error = tr("download_file_default_error").arg(mName);
|
||||
Utils::showInformationPopup(tr("info_popup_error_titile"), *error, false);
|
||||
delete error;
|
||||
});
|
||||
} else delete error;
|
||||
});
|
||||
});
|
||||
mChatMessageContentModelConnection->makeConnectToModel(
|
||||
&ChatMessageContentModel::wasDownloadedChanged,
|
||||
[this](const std::shared_ptr<linphone::Content> &content, bool downloaded) {
|
||||
mChatMessageContentModelConnection->invokeToCore([this, downloaded] { setWasDownloaded(downloaded); });
|
||||
});
|
||||
mChatMessageContentModelConnection->makeConnectToModel(
|
||||
&ChatMessageContentModel::filePathChanged,
|
||||
[this](const std::shared_ptr<linphone::Content> &content, QString filePath) {
|
||||
auto isFile = content->isFile();
|
||||
auto isFileTransfer = content->isFileTransfer();
|
||||
auto isFileEncrypted = content->isFileEncrypted();
|
||||
mChatMessageContentModelConnection->invokeToCore([this, filePath, isFile, isFileTransfer, isFileEncrypted] {
|
||||
setIsFile(isFile || QFileInfo(filePath).isFile());
|
||||
setIsFileTransfer(isFileTransfer);
|
||||
setIsFileEncrypted(isFileEncrypted);
|
||||
setFilePath(filePath);
|
||||
});
|
||||
});
|
||||
|
||||
mChatMessageContentModelConnection->makeConnectToCore(&ChatMessageContentCore::lCancelDownloadFile, [this]() {
|
||||
mChatMessageContentModelConnection->invokeToModel([this] { mChatMessageContentModel->cancelDownloadFile(); });
|
||||
});
|
||||
mChatMessageContentModelConnection->makeConnectToCore(
|
||||
&ChatMessageContentCore::lOpenFile, [this](bool showDirectory = false) {
|
||||
if (!QFileInfo(mFilePath).exists()) {
|
||||
//: Error
|
||||
Utils::showInformationPopup(tr("popup_error_title"),
|
||||
//: Could not open file : unknown path %1
|
||||
tr("popup_open_file_error_does_not_exist_message").arg(mFilePath), false);
|
||||
} else {
|
||||
mChatMessageContentModelConnection->invokeToModel([this, showDirectory] {
|
||||
mChatMessageContentModel->openFile(mName, mWasDownloaded, showDirectory);
|
||||
});
|
||||
}
|
||||
});
|
||||
mChatMessageContentModelConnection->makeConnectToModel(
|
||||
&ChatMessageContentModel::messageStateChanged, [this](linphone::ChatMessage::State state) {
|
||||
mChatMessageContentModelConnection->invokeToCore(
|
||||
[this, msgState = LinphoneEnums::fromLinphone(state)] { emit msgStateChanged(msgState); });
|
||||
});
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isFile() const {
|
||||
return mIsFile;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setIsFile(bool isFile) {
|
||||
if (mIsFile != isFile) {
|
||||
mIsFile = isFile;
|
||||
emit isFileChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isVideo() const {
|
||||
return mIsVideo;
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isFileEncrypted() const {
|
||||
return mIsFileEncrypted;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setIsFileEncrypted(bool isFileEncrypted) {
|
||||
if (mIsFileEncrypted != isFileEncrypted) {
|
||||
mIsFileEncrypted = isFileEncrypted;
|
||||
emit isFileEncryptedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isFileTransfer() const {
|
||||
return mIsFileTransfer;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setIsFileTransfer(bool isFileTransfer) {
|
||||
if (mIsFileTransfer != isFileTransfer) {
|
||||
mIsFileTransfer = isFileTransfer;
|
||||
emit isFileTransferChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isCalendar() const {
|
||||
return mIsCalendar;
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isMultipart() const {
|
||||
return mIsMultipart;
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isText() const {
|
||||
return mIsText;
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::isVoiceRecording() const {
|
||||
return mIsVoiceRecording;
|
||||
}
|
||||
|
||||
QString ChatMessageContentCore::getFilePath() const {
|
||||
return mFilePath;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setFilePath(QString path) {
|
||||
if (mFilePath != path) {
|
||||
mFilePath = path;
|
||||
emit filePathChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatMessageContentCore::getUtf8Text() const {
|
||||
return mUtf8Text;
|
||||
}
|
||||
|
||||
QString ChatMessageContentCore::getName() const {
|
||||
return mName;
|
||||
}
|
||||
|
||||
quint64 ChatMessageContentCore::getFileSize() const {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
quint64 ChatMessageContentCore::getFileOffset() const {
|
||||
return mFileOffset;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setFileOffset(quint64 fileOffset) {
|
||||
if (mFileOffset != fileOffset) {
|
||||
mFileOffset = fileOffset;
|
||||
emit fileOffsetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
int ChatMessageContentCore::getFileDuration() const {
|
||||
return mFileDuration;
|
||||
}
|
||||
|
||||
ConferenceInfoGui *ChatMessageContentCore::getConferenceInfoGui() const {
|
||||
return mConferenceInfo ? new ConferenceInfoGui(mConferenceInfo) : nullptr;
|
||||
}
|
||||
|
||||
bool ChatMessageContentCore::wasDownloaded() const {
|
||||
return mWasDownloaded;
|
||||
}
|
||||
|
||||
QUrl ChatMessageContentCore::getThumbnail() const {
|
||||
return mThumbnail;
|
||||
}
|
||||
|
||||
void ChatMessageContentCore::setThumbnail(const QUrl &data) {
|
||||
if (mThumbnail != data) {
|
||||
mThumbnail = data;
|
||||
emit thumbnailChanged();
|
||||
}
|
||||
}
|
||||
void ChatMessageContentCore::setWasDownloaded(bool wasDownloaded) {
|
||||
if (mWasDownloaded != wasDownloaded) {
|
||||
mWasDownloaded = wasDownloaded;
|
||||
emit wasDownloadedChanged(wasDownloaded);
|
||||
}
|
||||
}
|
||||
|
||||
const std::shared_ptr<ChatMessageContentModel> &ChatMessageContentCore::getContentModel() const {
|
||||
return mChatMessageContentModel;
|
||||
}
|
||||
138
Linphone/core/chat/message/content/ChatMessageContentCore.hpp
Normal file
138
Linphone/core/chat/message/content/ChatMessageContentCore.hpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_CONTENT_CORE_H_
|
||||
#define CHAT_MESSAGE_CONTENT_CORE_H_
|
||||
|
||||
#include "core/conference/ConferenceInfoCore.hpp"
|
||||
#include "core/conference/ConferenceInfoGui.hpp"
|
||||
#include "model/chat/message/content/ChatMessageContentModel.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
class ChatMessageContentCore : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString name READ getName CONSTANT)
|
||||
Q_PROPERTY(quint64 fileOffset READ getFileOffset WRITE setFileOffset NOTIFY fileOffsetChanged)
|
||||
|
||||
Q_PROPERTY(QUrl thumbnail READ getThumbnail WRITE setThumbnail NOTIFY thumbnailChanged)
|
||||
Q_PROPERTY(bool wasDownloaded READ wasDownloaded WRITE setWasDownloaded NOTIFY wasDownloadedChanged)
|
||||
Q_PROPERTY(QString filePath READ getFilePath WRITE setFilePath NOTIFY filePathChanged)
|
||||
Q_PROPERTY(QString utf8Text READ getUtf8Text CONSTANT)
|
||||
Q_PROPERTY(QString richFormatText MEMBER mRichFormatText CONSTANT)
|
||||
Q_PROPERTY(bool isFile READ isFile WRITE setIsFile NOTIFY isFileChanged)
|
||||
Q_PROPERTY(bool isFileEncrypted READ isFileEncrypted WRITE setIsFileEncrypted NOTIFY isFileEncryptedChanged)
|
||||
Q_PROPERTY(bool isFileTransfer READ isFileTransfer WRITE setIsFileTransfer NOTIFY isFileTransferChanged)
|
||||
Q_PROPERTY(bool isCalendar READ isCalendar CONSTANT)
|
||||
Q_PROPERTY(ConferenceInfoGui *conferenceInfo READ getConferenceInfoGui CONSTANT)
|
||||
Q_PROPERTY(bool isMultipart READ isMultipart CONSTANT)
|
||||
Q_PROPERTY(bool isText READ isText CONSTANT)
|
||||
Q_PROPERTY(bool isVideo READ isVideo NOTIFY isVideoChanged)
|
||||
Q_PROPERTY(bool isVoiceRecording READ isVoiceRecording CONSTANT)
|
||||
Q_PROPERTY(int fileDuration READ getFileDuration CONSTANT)
|
||||
Q_PROPERTY(quint64 fileSize READ getFileSize CONSTANT)
|
||||
|
||||
public:
|
||||
static QSharedPointer<ChatMessageContentCore> create(const std::shared_ptr<linphone::Content> &content,
|
||||
std::shared_ptr<ChatMessageModel> chatMessageModel);
|
||||
ChatMessageContentCore(const std::shared_ptr<linphone::Content> &content,
|
||||
std::shared_ptr<ChatMessageModel> chatMessageModel);
|
||||
~ChatMessageContentCore();
|
||||
void setSelf(QSharedPointer<ChatMessageContentCore> me);
|
||||
|
||||
bool isFile() const;
|
||||
void setIsFile(bool isFile);
|
||||
bool isFileEncrypted() const;
|
||||
void setIsFileEncrypted(bool isFileEncrypted);
|
||||
bool isFileTransfer() const;
|
||||
void setIsFileTransfer(bool isFileTransfer);
|
||||
|
||||
bool isVideo() const;
|
||||
bool isCalendar() const;
|
||||
bool isMultipart() const;
|
||||
bool isText() const;
|
||||
bool isVoiceRecording() const;
|
||||
|
||||
QString getUtf8Text() const;
|
||||
QString getName() const;
|
||||
quint64 getFileSize() const;
|
||||
quint64 getFileOffset() const;
|
||||
void setFileOffset(quint64 fileOffset);
|
||||
QString getFilePath() const;
|
||||
void setFilePath(QString path);
|
||||
int getFileDuration() const;
|
||||
ConferenceInfoGui *getConferenceInfoGui() const;
|
||||
|
||||
void setThumbnail(const QUrl &data);
|
||||
QUrl getThumbnail() const;
|
||||
|
||||
bool wasDownloaded() const;
|
||||
void setWasDownloaded(bool downloaded);
|
||||
|
||||
const std::shared_ptr<ChatMessageContentModel> &getContentModel() const;
|
||||
|
||||
signals:
|
||||
void msgStateChanged(LinphoneEnums::ChatMessageState state);
|
||||
void thumbnailChanged();
|
||||
void fileOffsetChanged();
|
||||
void filePathChanged();
|
||||
void isFileChanged();
|
||||
void isFileTransferChanged();
|
||||
void isFileEncryptedChanged();
|
||||
void wasDownloadedChanged(bool downloaded);
|
||||
void isVideoChanged();
|
||||
|
||||
void lCreateThumbnail(const bool &force = false);
|
||||
void lRemoveDownloadedFile();
|
||||
void lDownloadFile();
|
||||
void lCancelDownloadFile();
|
||||
void lOpenFile(bool showDirectory = false);
|
||||
bool lSaveAs(const QString &path);
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
bool mIsFile;
|
||||
bool mIsVideo;
|
||||
bool mIsFileEncrypted;
|
||||
bool mIsFileTransfer;
|
||||
bool mIsCalendar;
|
||||
bool mIsMultipart;
|
||||
bool mIsText;
|
||||
bool mIsVoiceRecording;
|
||||
int mFileDuration;
|
||||
QUrl mThumbnail;
|
||||
QString mUtf8Text;
|
||||
QString mRichFormatText;
|
||||
QString mFilePath;
|
||||
QString mName;
|
||||
quint64 mFileSize;
|
||||
quint64 mFileOffset;
|
||||
bool mWasDownloaded;
|
||||
QSharedPointer<ConferenceInfoCore> mConferenceInfo = nullptr;
|
||||
|
||||
std::shared_ptr<ChatMessageContentModel> mChatMessageContentModel;
|
||||
QSharedPointer<SafeConnection<ChatMessageContentCore, ChatMessageContentModel>> mChatMessageContentModelConnection;
|
||||
};
|
||||
|
||||
#endif // CHAT_MESSAGE_CONTENT_CORE_H_
|
||||
38
Linphone/core/chat/message/content/ChatMessageContentGui.cpp
Normal file
38
Linphone/core/chat/message/content/ChatMessageContentGui.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageContentGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageContentGui)
|
||||
|
||||
ChatMessageContentGui::ChatMessageContentGui(QSharedPointer<ChatMessageContentCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
ChatMessageContentGui::~ChatMessageContentGui() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
ChatMessageContentCore *ChatMessageContentGui::getCore() const {
|
||||
return mCore.get();
|
||||
}
|
||||
41
Linphone/core/chat/message/content/ChatMessageContentGui.hpp
Normal file
41
Linphone/core/chat/message/content/ChatMessageContentGui.hpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_CONTENT_GUI_H_
|
||||
#define CHAT_MESSAGE_CONTENT_GUI_H_
|
||||
|
||||
#include "core/chat/message/content/ChatMessageContentCore.hpp"
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
class ChatMessageContentGui : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(ChatMessageContentCore *core READ getCore CONSTANT)
|
||||
|
||||
public:
|
||||
ChatMessageContentGui(QSharedPointer<ChatMessageContentCore> core);
|
||||
~ChatMessageContentGui();
|
||||
ChatMessageContentCore *getCore() const;
|
||||
QSharedPointer<ChatMessageContentCore> mCore;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
227
Linphone/core/chat/message/content/ChatMessageContentList.cpp
Normal file
227
Linphone/core/chat/message/content/ChatMessageContentList.cpp
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageContentList.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentGui.hpp"
|
||||
|
||||
#include <QMimeDatabase>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageContentList)
|
||||
|
||||
QSharedPointer<ChatMessageContentList> ChatMessageContentList::create() {
|
||||
auto model = QSharedPointer<ChatMessageContentList>(new ChatMessageContentList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
model->setSelf(model);
|
||||
return model;
|
||||
}
|
||||
|
||||
ChatMessageContentList::ChatMessageContentList(QObject *parent) : ListProxy(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ChatMessageContentList::~ChatMessageContentList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
mModelConnection = nullptr;
|
||||
}
|
||||
|
||||
ChatMessageGui *ChatMessageContentList::getChatMessage() const {
|
||||
if (mChatMessageCore) return new ChatMessageGui(mChatMessageCore);
|
||||
else return nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<ChatMessageCore> ChatMessageContentList::getChatMessageCore() const {
|
||||
return mChatMessageCore;
|
||||
}
|
||||
|
||||
void ChatMessageContentList::setChatMessageCore(QSharedPointer<ChatMessageCore> core) {
|
||||
if (mChatMessageCore != core) {
|
||||
// if (mChatMessageCore) disconnect(mChatMessageCore.get(), &ChatCore::, this, nullptr);
|
||||
mChatMessageCore = core;
|
||||
// if (mChatMessageCore)
|
||||
// connect(mChatMessageCore.get(), &ChatCore::messageListChanged, this, &ChatMessageContentList::lUpdate);
|
||||
emit chatMessageChanged();
|
||||
lUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageContentList::setChatMessageGui(ChatMessageGui *chat) {
|
||||
auto chatCore = chat ? chat->mCore : nullptr;
|
||||
setChatMessageCore(chatCore);
|
||||
}
|
||||
|
||||
int ChatMessageContentList::findFirstUnreadIndex() {
|
||||
auto chatList = getSharedList<ChatMessageCore>();
|
||||
auto it = std::find_if(chatList.begin(), chatList.end(),
|
||||
[](const QSharedPointer<ChatMessageCore> item) { return !item->isRead(); });
|
||||
return it == chatList.end() ? -1 : std::distance(chatList.begin(), it);
|
||||
}
|
||||
|
||||
void ChatMessageContentList::addFiles(const QStringList &paths) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
|
||||
QStringList finalList;
|
||||
QList<QFileInfo> fileList;
|
||||
|
||||
int nbNotFound = 0;
|
||||
QString lastNotFound;
|
||||
int nbExcess = 0;
|
||||
int count = rowCount();
|
||||
|
||||
for (auto &path : paths) {
|
||||
QFileInfo file(path.toUtf8());
|
||||
// #ifdef _WIN32
|
||||
// // A bug from FileDialog suppose that the file is local and overwrite the uri by removing "\\".
|
||||
// if (!file.exists()) {
|
||||
// path.prepend("\\\\");
|
||||
// file.setFileName(path);
|
||||
// }
|
||||
// #endif
|
||||
if (!file.exists()) {
|
||||
++nbNotFound;
|
||||
lastNotFound = path;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count + finalList.count() >= 12) {
|
||||
++nbExcess;
|
||||
continue;
|
||||
}
|
||||
finalList.append(path);
|
||||
fileList.append(file);
|
||||
}
|
||||
if (nbNotFound > 0) {
|
||||
//: Error adding file
|
||||
Utils::showInformationPopup(tr("popup_error_title"),
|
||||
//: File was not found: %1
|
||||
(nbNotFound == 1 ? tr("popup_error_path_does_not_exist_message").arg(lastNotFound)
|
||||
//: %n files were not found
|
||||
: tr("popup_error_nb_files_not_found_message").arg(nbNotFound)),
|
||||
false);
|
||||
}
|
||||
if (nbExcess > 0) {
|
||||
//: Error
|
||||
Utils::showInformationPopup(tr("popup_error_title"),
|
||||
//: You can send 12 files maximum at a time. %n files were ignored
|
||||
tr("popup_error_max_files_count_message", "", nbExcess), false);
|
||||
}
|
||||
|
||||
mModelConnection->invokeToModel([this, finalList, fileList] {
|
||||
int nbTooBig = 0;
|
||||
int nbMimeError = 0;
|
||||
QString lastMimeError;
|
||||
QList<QSharedPointer<ChatMessageContentCore>> contentList;
|
||||
for (auto &file : fileList) {
|
||||
qint64 fileSize = file.size();
|
||||
if (fileSize > Constants::FileSizeLimit) {
|
||||
++nbTooBig;
|
||||
lWarning() << log().arg("Unable to send file. (Size limit=%1)").arg(Constants::FileSizeLimit);
|
||||
continue;
|
||||
}
|
||||
auto name = file.fileName().toStdString();
|
||||
auto path = file.filePath();
|
||||
std::shared_ptr<linphone::Content> content = CoreModel::getInstance()->getCore()->createContent();
|
||||
QStringList mimeType = QMimeDatabase().mimeTypeForFile(path).name().split('/');
|
||||
if (mimeType.length() != 2) {
|
||||
++nbMimeError;
|
||||
lastMimeError = path;
|
||||
lWarning() << log().arg("Unable to get supported mime type for: `%1`.").arg(path);
|
||||
continue;
|
||||
}
|
||||
content->setType(Utils::appStringToCoreString(mimeType[0]));
|
||||
content->setSubtype(Utils::appStringToCoreString(mimeType[1]));
|
||||
content->setSize(size_t(fileSize));
|
||||
content->setName(name);
|
||||
content->setFilePath(Utils::appStringToCoreString(path));
|
||||
contentList.append(ChatMessageContentCore::create(content, nullptr));
|
||||
}
|
||||
if (nbTooBig > 0) {
|
||||
//: Error adding file
|
||||
Utils::showInformationPopup(
|
||||
tr("popup_error_title"),
|
||||
//: %n files were ignored cause they exceed the maximum size. (Size limit=%2)
|
||||
tr("popup_error_file_too_big_message").arg(nbTooBig).arg(Constants::FileSizeLimit), false);
|
||||
}
|
||||
if (nbMimeError > 0) {
|
||||
//: Error adding file
|
||||
Utils::showInformationPopup(tr("popup_error_title"),
|
||||
//: Unable to get supported mime type for: `%1`.
|
||||
(nbMimeError == 1
|
||||
? tr("popup_error_unsupported_file_message").arg(lastMimeError)
|
||||
//: Unable to get supported mime type for %1 files.
|
||||
: tr("popup_error_unsupported_files_message").arg(nbMimeError)),
|
||||
false);
|
||||
}
|
||||
|
||||
mModelConnection->invokeToCore([this, contentList] {
|
||||
for (auto &contentCore : contentList) {
|
||||
connect(contentCore.get(), &ChatMessageContentCore::isFileChanged, this, [this, contentCore] {
|
||||
int i = -1;
|
||||
get(contentCore.get(), &i);
|
||||
emit dataChanged(index(i), index(i));
|
||||
});
|
||||
add(contentCore);
|
||||
contentCore->lCreateThumbnail(
|
||||
true); // Was not created because linphone::Content is not considered as a file (yet)
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void ChatMessageContentList::setSelf(QSharedPointer<ChatMessageContentList> me) {
|
||||
mModelConnection = SafeConnection<ChatMessageContentList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
|
||||
mModelConnection->makeConnectToCore(&ChatMessageContentList::lUpdate, [this]() {
|
||||
for (auto &content : getSharedList<ChatMessageContentCore>()) {
|
||||
if (content) disconnect(content.get(), &ChatMessageContentCore::wasDownloadedChanged, this, nullptr);
|
||||
if (content) disconnect(content.get(), &ChatMessageContentCore::thumbnailChanged, this, nullptr);
|
||||
}
|
||||
if (!mChatMessageCore) return;
|
||||
auto contents = mChatMessageCore->getChatMessageContentList();
|
||||
for (auto &content : contents) {
|
||||
connect(content.get(), &ChatMessageContentCore::wasDownloadedChanged, this,
|
||||
[this, content](bool wasDownloaded) {
|
||||
if (wasDownloaded) {
|
||||
content->lCreateThumbnail();
|
||||
}
|
||||
});
|
||||
connect(content.get(), &ChatMessageContentCore::thumbnailChanged, this, [this] { emit lUpdate(); });
|
||||
}
|
||||
resetData<ChatMessageContentCore>(contents);
|
||||
});
|
||||
mModelConnection->makeConnectToCore(&ChatMessageContentList::lAddFiles,
|
||||
[this](const QStringList &paths) { addFiles(paths); });
|
||||
emit lUpdate();
|
||||
}
|
||||
|
||||
QVariant ChatMessageContentList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole)
|
||||
return QVariant::fromValue(new ChatMessageContentGui(mList[row].objectCast<ChatMessageContentCore>()));
|
||||
return QVariant();
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_CONTENT_LIST_H_
|
||||
#define CHAT_MESSAGE_CONTENT_LIST_H_
|
||||
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
class ChatMessageGui;
|
||||
class ChatMessageCore;
|
||||
// =============================================================================
|
||||
|
||||
class ChatMessageContentList : public ListProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<ChatMessageContentList> create();
|
||||
ChatMessageContentList(QObject *parent = Q_NULLPTR);
|
||||
~ChatMessageContentList();
|
||||
|
||||
QSharedPointer<ChatMessageCore> getChatMessageCore() const;
|
||||
ChatMessageGui *getChatMessage() const;
|
||||
void setChatMessageCore(QSharedPointer<ChatMessageCore> core);
|
||||
void setChatMessageGui(ChatMessageGui *chat);
|
||||
|
||||
int findFirstUnreadIndex();
|
||||
|
||||
void addFiles(const QStringList &paths);
|
||||
|
||||
void setSelf(QSharedPointer<ChatMessageContentList> me);
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void lAddFiles(QStringList paths);
|
||||
void isFileChanged();
|
||||
void lUpdate();
|
||||
void chatMessageChanged();
|
||||
|
||||
private:
|
||||
QSharedPointer<ChatMessageCore> mChatMessageCore;
|
||||
QSharedPointer<SafeConnection<ChatMessageContentList, CoreModel>> mModelConnection;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
103
Linphone/core/chat/message/content/ChatMessageContentProxy.cpp
Normal file
103
Linphone/core/chat/message/content/ChatMessageContentProxy.cpp
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ChatMessageContentProxy.hpp"
|
||||
#include "ChatMessageContentGui.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/message/ChatMessageGui.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ChatMessageContentProxy)
|
||||
|
||||
ChatMessageContentProxy::ChatMessageContentProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mList = ChatMessageContentList::create();
|
||||
setSourceModel(mList.get());
|
||||
}
|
||||
|
||||
ChatMessageContentProxy::~ChatMessageContentProxy() {
|
||||
}
|
||||
|
||||
void ChatMessageContentProxy::setSourceModel(QAbstractItemModel *model) {
|
||||
auto oldChatMessageContentList = getListModel<ChatMessageContentList>();
|
||||
if (oldChatMessageContentList) {
|
||||
// disconnect(oldChatMessageContentList);
|
||||
}
|
||||
auto newChatMessageContentList = dynamic_cast<ChatMessageContentList *>(model);
|
||||
if (newChatMessageContentList) {
|
||||
// connect(newChatMessageContentList, &ChatMessageContentList::chatChanged, this,
|
||||
// &ChatMessageContentProxy::chatChanged);
|
||||
}
|
||||
setSourceModels(new SortFilterList(model));
|
||||
sort(0);
|
||||
}
|
||||
|
||||
ChatMessageGui *ChatMessageContentProxy::getChatMessageGui() {
|
||||
auto model = getListModel<ChatMessageContentList>();
|
||||
if (!mChatMessageGui && model) mChatMessageGui = model->getChatMessage();
|
||||
return mChatMessageGui;
|
||||
}
|
||||
|
||||
void ChatMessageContentProxy::setChatMessageGui(ChatMessageGui *chat) {
|
||||
getListModel<ChatMessageContentList>()->setChatMessageGui(chat);
|
||||
}
|
||||
|
||||
ChatMessageContentGui *ChatMessageContentProxy::getChatMessageContentAtIndex(int i) {
|
||||
auto model = getListModel<ChatMessageContentList>();
|
||||
auto sourceIndex = mapToSource(index(i, 0)).row();
|
||||
if (model) {
|
||||
auto chat = model->getAt<ChatMessageContentCore>(sourceIndex);
|
||||
if (chat) return new ChatMessageContentGui(chat);
|
||||
else return nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ChatMessageContentProxy::addFiles(const QStringList &paths) {
|
||||
auto model = getListModel<ChatMessageContentList>();
|
||||
if (model) emit model->lAddFiles(paths);
|
||||
}
|
||||
|
||||
void ChatMessageContentProxy::removeContent(ChatMessageContentGui *contentGui) {
|
||||
auto model = getListModel<ChatMessageContentList>();
|
||||
if (model && contentGui) model->remove(contentGui->mCore);
|
||||
}
|
||||
|
||||
void ChatMessageContentProxy::clear() {
|
||||
auto model = getListModel<ChatMessageContentList>();
|
||||
if (model) model->clearData();
|
||||
}
|
||||
|
||||
bool ChatMessageContentProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
auto contentCore = getItemAtSource<ChatMessageContentList, ChatMessageContentCore>(sourceRow);
|
||||
if (contentCore) {
|
||||
if (mFilterType == (int)FilterContentType::Unknown) return false;
|
||||
else if (mFilterType == (int)FilterContentType::File) {
|
||||
return !contentCore->isVoiceRecording() && (contentCore->isFile() || contentCore->isFileTransfer());
|
||||
} else if (mFilterType == (int)FilterContentType::Text) return contentCore->isText();
|
||||
else if (mFilterType == (int)FilterContentType::Voice) return contentCore->isVoiceRecording();
|
||||
else if (mFilterType == (int)FilterContentType::Conference) return contentCore->isCalendar();
|
||||
else if (mFilterType == (int)FilterContentType::All) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ChatMessageContentProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
|
||||
const QModelIndex &sourceRight) const {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CHAT_MESSAGE_CONENT_PROXY_H_
|
||||
#define CHAT_MESSAGE_CONENT_PROXY_H_
|
||||
|
||||
#include "ChatMessageContentList.hpp"
|
||||
#include "core/proxy/LimitProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ChatMessageGui;
|
||||
class ChatMessageContentGui;
|
||||
|
||||
class ChatMessageContentProxy : public LimitProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(ChatMessageGui *chatMessageGui READ getChatMessageGui WRITE setChatMessageGui NOTIFY chatChanged)
|
||||
|
||||
public:
|
||||
enum class FilterContentType { Unknown = 0, File = 1, Text = 2, Voice = 3, Conference = 4, All = 5 };
|
||||
Q_ENUM(FilterContentType)
|
||||
|
||||
DECLARE_SORTFILTER_CLASS(ChatMessageContentProxy *mHideListProxy = nullptr;)
|
||||
ChatMessageContentProxy(QObject *parent = Q_NULLPTR);
|
||||
~ChatMessageContentProxy();
|
||||
|
||||
ChatMessageGui *getChatMessageGui();
|
||||
void setChatMessageGui(ChatMessageGui *chat);
|
||||
|
||||
Q_INVOKABLE ChatMessageContentGui *getChatMessageContentAtIndex(int i);
|
||||
|
||||
void setSourceModel(QAbstractItemModel *sourceModel) override;
|
||||
|
||||
Q_INVOKABLE void addFiles(const QStringList &paths);
|
||||
Q_INVOKABLE void removeContent(ChatMessageContentGui *contentGui);
|
||||
Q_INVOKABLE void clear();
|
||||
|
||||
signals:
|
||||
void chatChanged();
|
||||
|
||||
protected:
|
||||
QSharedPointer<ChatMessageContentList> mList;
|
||||
ChatMessageGui *mChatMessageGui = nullptr;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
61
Linphone/core/chat/message/imdn/ImdnStatusList.cpp
Normal file
61
Linphone/core/chat/message/imdn/ImdnStatusList.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ImdnStatusList.hpp"
|
||||
#include "core/App.hpp"
|
||||
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ImdnStatusList)
|
||||
|
||||
QSharedPointer<ImdnStatusList> ImdnStatusList::create() {
|
||||
auto model = QSharedPointer<ImdnStatusList>(new ImdnStatusList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
return model;
|
||||
}
|
||||
|
||||
ImdnStatusList::ImdnStatusList(QObject *parent) : AbstractListProxy<ImdnStatus>(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ImdnStatusList::~ImdnStatusList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
QList<ImdnStatus> ImdnStatusList::getImdnStatusList() {
|
||||
return mList;
|
||||
}
|
||||
|
||||
void ImdnStatusList::setImdnStatusList(QList<ImdnStatus> imdnStatusList) {
|
||||
resetData(imdnStatusList);
|
||||
}
|
||||
|
||||
QVariant ImdnStatusList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole) return QVariant::fromValue(mList.at(row));
|
||||
return QVariant();
|
||||
}
|
||||
51
Linphone/core/chat/message/imdn/ImdnStatusList.hpp
Normal file
51
Linphone/core/chat/message/imdn/ImdnStatusList.hpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 IMDN_STATUS_LIST_H_
|
||||
#define IMDN_STATUS_LIST_H_
|
||||
|
||||
#include "core/chat/message/ChatMessageCore.hpp"
|
||||
#include "core/proxy/AbstractListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ImdnStatusList : public AbstractListProxy<ImdnStatus>, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<ImdnStatusList> create();
|
||||
ImdnStatusList(QObject *parent = Q_NULLPTR);
|
||||
~ImdnStatusList();
|
||||
|
||||
QList<ImdnStatus> getImdnStatusList();
|
||||
void setImdnStatusList(QList<ImdnStatus> imdnStatusList);
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void imdnStatusListChanged();
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
65
Linphone/core/chat/message/imdn/ImdnStatusProxy.cpp
Normal file
65
Linphone/core/chat/message/imdn/ImdnStatusProxy.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 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 "ImdnStatusProxy.hpp"
|
||||
#include "ImdnStatusList.hpp"
|
||||
#include "core/App.hpp"
|
||||
// #include "core/chat/message/ChatMessageGui.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ImdnStatusProxy)
|
||||
|
||||
ImdnStatusProxy::ImdnStatusProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mList = ImdnStatusList::create();
|
||||
setSourceModel(mList.get());
|
||||
connect(mList.get(), &ImdnStatusList::modelReset, this, &ImdnStatusProxy::imdnStatusListChanged);
|
||||
connect(this, &ImdnStatusProxy::filterChanged, this, [this] { invalidate(); });
|
||||
}
|
||||
|
||||
ImdnStatusProxy::~ImdnStatusProxy() {
|
||||
}
|
||||
|
||||
QList<ImdnStatus> ImdnStatusProxy::getImdnStatusList() {
|
||||
return mList->getImdnStatusList();
|
||||
}
|
||||
|
||||
void ImdnStatusProxy::setImdnStatusList(QList<ImdnStatus> statusList) {
|
||||
mList->setImdnStatusList(statusList);
|
||||
}
|
||||
|
||||
LinphoneEnums::ChatMessageState ImdnStatusProxy::getFilter() const {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
void ImdnStatusProxy::setFilter(LinphoneEnums::ChatMessageState filter) {
|
||||
if (mFilter != filter) {
|
||||
mFilter = filter;
|
||||
emit filterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool ImdnStatusProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
auto imdn = mList->getAt(sourceRow);
|
||||
return imdn.mState == mFilter;
|
||||
}
|
||||
|
||||
bool ImdnStatusProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||
return true;
|
||||
}
|
||||
62
Linphone/core/chat/message/imdn/ImdnStatusProxy.hpp
Normal file
62
Linphone/core/chat/message/imdn/ImdnStatusProxy.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 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 IMDN_STATUS_PROXY_H_
|
||||
#define IMDN_STATUS_PROXY_H_
|
||||
|
||||
#include "core/chat/message/ChatMessageCore.hpp"
|
||||
#include "core/proxy/LimitProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class ImdnStatusList;
|
||||
|
||||
class ImdnStatusProxy : public LimitProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(
|
||||
QList<ImdnStatus> imdnStatusList READ getImdnStatusList WRITE setImdnStatusList NOTIFY imdnStatusListChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ChatMessageState filter READ getFilter WRITE setFilter NOTIFY filterChanged)
|
||||
|
||||
public:
|
||||
ImdnStatusProxy(QObject *parent = Q_NULLPTR);
|
||||
~ImdnStatusProxy();
|
||||
|
||||
QList<ImdnStatus> getImdnStatusList();
|
||||
void setImdnStatusList(QList<ImdnStatus> imdnStatusList);
|
||||
|
||||
LinphoneEnums::ChatMessageState getFilter() const;
|
||||
void setFilter(LinphoneEnums::ChatMessageState filter);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
|
||||
|
||||
signals:
|
||||
void imdnStatusListChanged();
|
||||
void filterChanged();
|
||||
|
||||
protected:
|
||||
LinphoneEnums::ChatMessageState mFilter;
|
||||
QSharedPointer<ImdnStatusList> mList;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -47,7 +47,12 @@ ConferenceCore::ConferenceCore(const std::shared_ptr<linphone::Conference> &conf
|
|||
mIsLocalScreenSharing = mConferenceModel->isLocalScreenSharing();
|
||||
mIsScreenSharingEnabled = mConferenceModel->isScreenSharingEnabled();
|
||||
mIsRecording = conference->isRecording();
|
||||
if (conference->getCurrentParams()) mIsChatEnabled = conference->getCurrentParams()->chatEnabled();
|
||||
auto me = conference->getMe();
|
||||
auto confAddress = conference->getConferenceAddress();
|
||||
if (confAddress) {
|
||||
mConfUri = Utils::coreStringToAppString(confAddress->asStringUriOnly());
|
||||
}
|
||||
if (me) {
|
||||
mMe = ParticipantCore::create(me);
|
||||
}
|
||||
|
|
@ -75,7 +80,14 @@ void ConferenceCore::setSelf(QSharedPointer<ConferenceCore> me) {
|
|||
if (newState == linphone::Conference::State::Created) {
|
||||
if (auto participantDevice = conference->getActiveSpeakerParticipantDevice()) {
|
||||
auto device = ParticipantDeviceCore::create(participantDevice);
|
||||
mConferenceModelConnection->invokeToCore([this, device]() { setActiveSpeakerDevice(device); });
|
||||
QString address;
|
||||
auto confAddress = conference->getConferenceAddress();
|
||||
if (confAddress) address = Utils::coreStringToAppString(confAddress->asStringUriOnly());
|
||||
mConferenceModelConnection->invokeToCore([this, device, address]() {
|
||||
setActiveSpeakerDevice(device);
|
||||
mConfUri = address;
|
||||
emit conferenceUriChanged();
|
||||
});
|
||||
} else if (conference->getParticipantDeviceList().size() > 1) {
|
||||
for (auto &device : conference->getParticipantDeviceList()) {
|
||||
if (!ToolModel::isMe(device->getAddress())) {
|
||||
|
|
@ -194,6 +206,10 @@ void ConferenceCore::setIsScreenSharingEnabled(bool state) {
|
|||
}
|
||||
}
|
||||
|
||||
bool ConferenceCore::isChatEnabled() const {
|
||||
return mIsChatEnabled;
|
||||
}
|
||||
|
||||
std::shared_ptr<ConferenceModel> ConferenceCore::getModel() const {
|
||||
return mConferenceModel;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,12 +37,14 @@ class ConferenceCore : public QObject, public AbstractObject {
|
|||
Q_OBJECT
|
||||
public:
|
||||
Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT)
|
||||
Q_PROPERTY(bool isChatEnabled READ isChatEnabled CONSTANT)
|
||||
// Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT)
|
||||
// Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged)
|
||||
Q_PROPERTY(bool isReady MEMBER mIsReady WRITE setIsReady NOTIFY isReadyChanged)
|
||||
Q_PROPERTY(bool isRecording READ isRecording WRITE setRecording NOTIFY isRecordingChanged)
|
||||
|
||||
Q_PROPERTY(QString subject READ getSubject WRITE setSubject NOTIFY subjectChanged)
|
||||
Q_PROPERTY(QString uri MEMBER mConfUri NOTIFY conferenceUriChanged)
|
||||
Q_PROPERTY(bool isLocalScreenSharing MEMBER mIsLocalScreenSharing WRITE setIsLocalScreenSharing NOTIFY
|
||||
isLocalScreenSharingChanged)
|
||||
Q_PROPERTY(bool isScreenSharingEnabled MEMBER mIsScreenSharingEnabled WRITE setIsScreenSharingEnabled NOTIFY
|
||||
|
|
@ -80,6 +82,8 @@ public:
|
|||
void setIsLocalScreenSharing(bool state);
|
||||
void setIsScreenSharingEnabled(bool state);
|
||||
|
||||
bool isChatEnabled() const;
|
||||
|
||||
std::shared_ptr<ConferenceModel> getModel() const;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
@ -92,6 +96,7 @@ signals:
|
|||
void activeSpeakerDeviceChanged();
|
||||
void subjectChanged();
|
||||
void isRecordingChanged();
|
||||
void conferenceUriChanged();
|
||||
|
||||
void lToggleScreenSharing();
|
||||
|
||||
|
|
@ -106,7 +111,9 @@ private:
|
|||
bool mIsRecording = false;
|
||||
bool mIsLocalScreenSharing = false;
|
||||
bool mIsScreenSharingEnabled = false;
|
||||
bool mIsChatEnabled = false;
|
||||
QString mSubject;
|
||||
QString mConfUri;
|
||||
QDateTime mStartDate = QDateTime::currentDateTime();
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright (c) 2021 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
|
|
@ -21,12 +21,15 @@
|
|||
#include "ConferenceInfoCore.hpp"
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "core/proxy/ListProxy.hpp"
|
||||
#include "model/object/VariantObject.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
#include <QDesktopServices>
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ConferenceInfoCore)
|
||||
|
||||
QSharedPointer<ConferenceInfoCore>
|
||||
|
|
@ -69,16 +72,13 @@ ConferenceInfoCore::ConferenceInfoCore(std::shared_ptr<linphone::ConferenceInfo>
|
|||
mUri = address && address->isValid() && !address->getDomain().empty()
|
||||
? Utils::coreStringToAppString(address->asStringUriOnly())
|
||||
: "";
|
||||
mIcalendarString = Utils::coreStringToAppString(conferenceInfo->getIcalendarString());
|
||||
mDateTime = QDateTime::fromMSecsSinceEpoch(conferenceInfo->getDateTime() * 1000);
|
||||
mDuration = conferenceInfo->getDuration();
|
||||
mEndDateTime = mDateTime.addSecs(mDuration * 60);
|
||||
mIsScheduled = mDateTime.isValid();
|
||||
mOrganizerAddress = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->asStringUriOnly());
|
||||
mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getDisplayName());
|
||||
if (mOrganizerName.isEmpty()) {
|
||||
mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getUsername());
|
||||
mOrganizerName.replace(".", " ");
|
||||
}
|
||||
mOrganizerName = mConferenceInfoModel->getOrganizerName();
|
||||
mSubject = Utils::coreStringToAppString(conferenceInfo->getSubject());
|
||||
mDescription = Utils::coreStringToAppString(conferenceInfo->getDescription());
|
||||
mIsEnded = getDateTimeUtc().addSecs(mDuration * 60) < QDateTime::currentDateTimeUtc();
|
||||
|
|
@ -127,6 +127,7 @@ ConferenceInfoCore::ConferenceInfoCore(const ConferenceInfoCore &conferenceInfoC
|
|||
mIsEnded = conferenceInfoCore.mIsEnded;
|
||||
mInviteEnabled = conferenceInfoCore.mInviteEnabled;
|
||||
mConferenceInfoState = conferenceInfoCore.mConferenceInfoState;
|
||||
mIcalendarString = conferenceInfoCore.mIcalendarString;
|
||||
}
|
||||
|
||||
ConferenceInfoCore::~ConferenceInfoCore() {
|
||||
|
|
@ -179,6 +180,13 @@ void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
|
|||
}
|
||||
});
|
||||
});
|
||||
mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lCancelCreation, [this]() {
|
||||
mConfInfoModelConnection->invokeToModel([this] {
|
||||
if (mConferenceInfoModel) {
|
||||
mConferenceInfoModel->setConferenceScheduler(nullptr);
|
||||
}
|
||||
});
|
||||
});
|
||||
mConfInfoModelConnection->makeConnectToCore(&ConferenceInfoCore::lDeleteConferenceInfo, [this]() {
|
||||
mConfInfoModelConnection->invokeToModel([this] { mConferenceInfoModel->deleteConferenceInfo(); });
|
||||
});
|
||||
|
|
@ -192,21 +200,15 @@ void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
|
|||
QString uri;
|
||||
if (state == linphone::ConferenceScheduler::State::Ready) {
|
||||
uri = mConferenceInfoModel->getConferenceScheduler()->getUri();
|
||||
emit CoreModel::getInstance() -> conferenceInfoReceived(
|
||||
CoreModel::getInstance()->getCore(),
|
||||
mConferenceInfoModel->getConferenceInfo());
|
||||
}
|
||||
mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state),
|
||||
infoState = LinphoneEnums::fromLinphone(confInfoState),
|
||||
uri] {
|
||||
setConferenceSchedulerState(state);
|
||||
setConferenceInfoState(infoState);
|
||||
if (state == LinphoneEnums::ConferenceSchedulerState::Ready) {
|
||||
setUri(uri);
|
||||
mConfInfoModelConnection->invokeToModel([this, uri, infoState] {
|
||||
if (infoState == LinphoneEnums::ConferenceInfoState::New)
|
||||
emit CoreModel::getInstance()->conferenceInfoCreated(
|
||||
mConferenceInfoModel->getConferenceInfo());
|
||||
});
|
||||
}
|
||||
setConferenceSchedulerState(state);
|
||||
});
|
||||
});
|
||||
mConfInfoModelConnection->makeConnectToModel(
|
||||
|
|
@ -328,7 +330,8 @@ void ConferenceInfoCore::setTimeZoneModel(TimeZoneModel *model) {
|
|||
mTimeZoneModel->getStandardTimeOffset() != model->getStandardTimeOffset() ||
|
||||
mTimeZoneModel->getTimeZone() != model->getTimeZone()) {
|
||||
|
||||
mTimeZoneModel = QSharedPointer<TimeZoneModel>(model);
|
||||
mTimeZoneModel = QSharedPointer<TimeZoneModel>(new TimeZoneModel(model->getTimeZone()));
|
||||
|
||||
emit timeZoneModelChanged();
|
||||
}
|
||||
}
|
||||
|
|
@ -555,6 +558,10 @@ void ConferenceInfoCore::writeIntoModel(std::shared_ptr<ConferenceInfoModel> mod
|
|||
model->setParticipantInfos(participantInfos);
|
||||
}
|
||||
|
||||
std::shared_ptr<ConferenceInfoModel> ConferenceInfoCore::getModel() const {
|
||||
return mConferenceInfoModel;
|
||||
}
|
||||
|
||||
void ConferenceInfoCore::save() {
|
||||
mustBeInMainThread(getClassName() + "::save()");
|
||||
ConferenceInfoCore *thisCopy = new ConferenceInfoCore(*this); // Pointer to avoid multiple copies in lambdas
|
||||
|
|
@ -575,8 +582,8 @@ void ConferenceInfoCore::save() {
|
|||
linphone::RegistrationState::Ok) {
|
||||
//: "Erreur"
|
||||
Utils::showInformationPopup(tr("information_popup_error_title"),
|
||||
//: "Votre compte est déconnecté"
|
||||
tr("information_popup_disconnected_account_message"), false);
|
||||
//: "Votre compte est déconnecté"
|
||||
tr("information_popup_disconnected_account_message"), false);
|
||||
emit saveFailed();
|
||||
return;
|
||||
}
|
||||
|
|
@ -599,6 +606,9 @@ void ConferenceInfoCore::save() {
|
|||
} else lCritical() << "No default account";
|
||||
// Add text capability for chat in conf
|
||||
linphoneConf->setCapability(linphone::StreamType::Text, true);
|
||||
if (SettingsModel::getInstance()->getCreateEndToEndEncryptedMeetingsAndGroupCalls())
|
||||
linphoneConf->setSecurityLevel(linphone::Conference::SecurityLevel::EndToEnd);
|
||||
else linphoneConf->setSecurityLevel(linphone::Conference::SecurityLevel::PointToPoint);
|
||||
auto confInfoModel = Utils::makeQObject_ptr<ConferenceInfoModel>(linphoneConf);
|
||||
auto confSchedulerModel = confInfoModel->getConferenceScheduler();
|
||||
if (!confSchedulerModel) {
|
||||
|
|
@ -637,12 +647,6 @@ void ConferenceInfoCore::undo() {
|
|||
}
|
||||
}
|
||||
|
||||
void ConferenceInfoCore::cancelCreation() {
|
||||
if (mConferenceInfoModel) {
|
||||
mConferenceInfoModel->setConferenceScheduler(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
void ConferenceInfoCore::onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {
|
||||
|
|
@ -654,3 +658,14 @@ bool ConferenceInfoCore::isAllDayConf() const {
|
|||
return mDateTime.time().hour() == 0 && mDateTime.time().minute() == 0 && mEndDateTime.time().hour() == 23 &&
|
||||
mEndDateTime.time().minute() == 59;
|
||||
}
|
||||
|
||||
void ConferenceInfoCore::exportConferenceToICS() const {
|
||||
QString filePath(Paths::getAppLocalDirPath() + "conference.ics");
|
||||
QFile file(filePath);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out << mIcalendarString;
|
||||
file.close();
|
||||
}
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(filePath));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* Copyright (c) 2022 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
|
|
@ -126,14 +126,17 @@ public:
|
|||
void writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model);
|
||||
void writeIntoModel(std::shared_ptr<ConferenceInfoModel> model);
|
||||
|
||||
std::shared_ptr<ConferenceInfoModel> getModel() const;
|
||||
|
||||
Q_INVOKABLE void save();
|
||||
Q_INVOKABLE void undo();
|
||||
Q_INVOKABLE void cancelCreation();
|
||||
|
||||
virtual void onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations);
|
||||
|
||||
Q_INVOKABLE bool isAllDayConf() const;
|
||||
|
||||
Q_INVOKABLE void exportConferenceToICS() const;
|
||||
|
||||
signals:
|
||||
void dateTimeChanged();
|
||||
void endDateTimeChanged();
|
||||
|
|
@ -158,6 +161,7 @@ signals:
|
|||
void invitationsSent();
|
||||
void removed(ConferenceInfoCore *confInfo);
|
||||
|
||||
void lCancelCreation();
|
||||
void lCancelConferenceInfo();
|
||||
void lDeleteConferenceInfo(); // Remove completly this conference info from DB
|
||||
|
||||
|
|
@ -175,6 +179,7 @@ private:
|
|||
QString mSubject;
|
||||
QString mDescription;
|
||||
QString mUri;
|
||||
QString mIcalendarString;
|
||||
QVariantList mParticipants;
|
||||
QSharedPointer<TimeZoneModel> mTimeZoneModel;
|
||||
LinphoneEnums::ConferenceSchedulerState mConferenceSchedulerState;
|
||||
|
|
|
|||
|
|
@ -58,58 +58,119 @@ ConferenceInfoList::~ConferenceInfoList() {
|
|||
void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
|
||||
mCoreModelConnection = SafeConnection<ConferenceInfoList, CoreModel>::create(me, CoreModel::getInstance());
|
||||
|
||||
mCoreModelConnection->makeConnectToCore(&ConferenceInfoList::lUpdate, [this](bool isInitialization) {
|
||||
mCoreModelConnection->invokeToModel([this, isInitialization]() {
|
||||
QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>();
|
||||
mCoreModelConnection->makeConnectToCore(&ConferenceInfoList::lUpdate, [this]() {
|
||||
if (mIsUpdating) {
|
||||
connect(this, &ConferenceInfoList::isUpdatingChanged, this, [this] {
|
||||
if (!mIsUpdating) {
|
||||
disconnect(this, &ConferenceInfoList::isUpdatingChanged, this, nullptr);
|
||||
lUpdate();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
setIsUpdating(true);
|
||||
mCoreModelConnection->invokeToModel([this]() {
|
||||
mustBeInLinphoneThread(getClassName());
|
||||
beginResetModel();
|
||||
mList.clear();
|
||||
QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>();
|
||||
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (!defaultAccount) return;
|
||||
setAccountConnected(defaultAccount && defaultAccount->getState() == linphone::RegistrationState::Ok);
|
||||
if (!defaultAccount || !mAccountConnected) {
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
return;
|
||||
}
|
||||
std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos =
|
||||
defaultAccount->getConferenceInformationList();
|
||||
if (conferenceInfos.empty()) {
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
return;
|
||||
}
|
||||
items->push_back(nullptr); // Add Dummy conference for today
|
||||
for (auto conferenceInfo : conferenceInfos) {
|
||||
if (conferenceInfo->getState() == linphone::ConferenceInfo::State::Cancelled) {
|
||||
auto myAddress = defaultAccount->getParams()->getIdentityAddress();
|
||||
if (!myAddress || myAddress->weakEqual(conferenceInfo->getOrganizer())) continue;
|
||||
}
|
||||
// if (conferenceInfo->getState() == linphone::ConferenceInfo::State::Cancelled) {
|
||||
// auto myAddress = defaultAccount->getParams()->getIdentityAddress();
|
||||
// if (!myAddress || myAddress->weakEqual(conferenceInfo->getOrganizer())) continue;
|
||||
// }
|
||||
auto confInfoCore = build(conferenceInfo);
|
||||
// Cancelled conference organized ourself me must be hidden
|
||||
if (confInfoCore) {
|
||||
// qDebug() << log().arg("Add conf") << confInfoCore->getSubject() << "with state"
|
||||
// << confInfoCore->getConferenceInfoState();
|
||||
items->push_back(confInfoCore);
|
||||
}
|
||||
}
|
||||
mCoreModelConnection->invokeToCore([this, items, isInitialization]() {
|
||||
mCoreModelConnection->invokeToCore([this, items]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
for (auto &item : *items) {
|
||||
connectItem(item);
|
||||
mList << item.template objectCast<QObject>();
|
||||
}
|
||||
resetData(*items);
|
||||
updateHaveCurrentDate();
|
||||
endResetModel();
|
||||
setIsUpdating(false);
|
||||
delete items;
|
||||
if (isInitialization) {
|
||||
emit initialized();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// This is needed because account does not have a contact address until
|
||||
// it is connected, so we can't verify if it is the organizer of a deleted
|
||||
// conference (which must hidden)
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, [this]() { emit lUpdate(true); });
|
||||
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoCreated,
|
||||
[this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { addConference(confInfo); });
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoReceived,
|
||||
[this](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
|
||||
lDebug() << log().arg("conference info received") << conferenceInfo->getSubject();
|
||||
addConference(conferenceInfo->clone());
|
||||
lInfo() << log().arg("conference info received") << conferenceInfo->getSubject();
|
||||
// We must refresh all the conference infos cause we are not able to determine
|
||||
// which account is concerned by the signal if multiple accounts are connected
|
||||
emit lUpdate();
|
||||
});
|
||||
emit lUpdate(true);
|
||||
|
||||
// This is needed because account does not have a contact address until
|
||||
// it is connected, so we can't verify if it is the organizer of a deleted
|
||||
// conference (which must hidden)
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::defaultAccountChanged,
|
||||
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) {
|
||||
auto accountCore = account ? AccountCore::create(account) : nullptr;
|
||||
mCoreModelConnection->invokeToCore([this, accountCore] {
|
||||
if (mCurrentAccountCore) {
|
||||
disconnect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this, nullptr);
|
||||
disconnect(mCurrentAccountCore.get(), &AccountCore::conferenceInformationUpdated, this, nullptr);
|
||||
}
|
||||
mCurrentAccountCore = accountCore;
|
||||
if (mCurrentAccountCore) {
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this,
|
||||
[this] { emit lUpdate(); });
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::conferenceInformationUpdated, this,
|
||||
[this] { emit lUpdate(); });
|
||||
}
|
||||
emit lUpdate();
|
||||
});
|
||||
});
|
||||
mCoreModelConnection->invokeToModel([this] {
|
||||
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
auto accountCore = defaultAccount ? AccountCore::create(defaultAccount) : nullptr;
|
||||
mCoreModelConnection->invokeToCore([this, accountCore] {
|
||||
mCurrentAccountCore = accountCore;
|
||||
if (mCurrentAccountCore) {
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this,
|
||||
[this] { emit lUpdate(); });
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::conferenceInformationUpdated, this,
|
||||
[this] { emit lUpdate(); });
|
||||
}
|
||||
});
|
||||
});
|
||||
emit lUpdate();
|
||||
}
|
||||
|
||||
void ConferenceInfoList::setAccountConnected(bool connected) {
|
||||
if (mAccountConnected != connected) {
|
||||
mAccountConnected = connected;
|
||||
emit accountConnectedChanged(mAccountConnected);
|
||||
}
|
||||
}
|
||||
|
||||
bool ConferenceInfoList::getAccountConnected() const {
|
||||
return mAccountConnected;
|
||||
}
|
||||
|
||||
void ConferenceInfoList::resetData(QList<QSharedPointer<ConferenceInfoCore>> data) {
|
||||
|
|
@ -129,6 +190,7 @@ void ConferenceInfoList::addConference(const std::shared_ptr<linphone::Conferenc
|
|||
return confInfo->getUri()->weakEqual(confAddr);
|
||||
});
|
||||
if (haveConf == list.end()) {
|
||||
if (confInfo->getState() == linphone::ConferenceInfo::State::Cancelled) return;
|
||||
auto confInfoCore = build(confInfo);
|
||||
mCoreModelConnection->invokeToCore([this, confInfoCore] {
|
||||
connectItem(confInfoCore);
|
||||
|
|
@ -173,13 +235,17 @@ int ConferenceInfoList::getCurrentDateIndex() {
|
|||
return it == confInfoList.end() ? -1 : std::distance(confInfoList.begin(), it);
|
||||
}
|
||||
|
||||
QSharedPointer<ConferenceInfoCore> ConferenceInfoList::getCurrentDateConfInfo() {
|
||||
QSharedPointer<ConferenceInfoCore> ConferenceInfoList::getCurrentDateConfInfo(bool enableCancelledConference) {
|
||||
auto today = QDate::currentDate();
|
||||
auto confInfoList = getSharedList<ConferenceInfoCore>();
|
||||
QList<QSharedPointer<ConferenceInfoCore>>::iterator it;
|
||||
if (mHaveCurrentDate) {
|
||||
it = std::find_if(confInfoList.begin(), confInfoList.end(),
|
||||
[today](const QSharedPointer<ConferenceInfoCore> &item) {
|
||||
[today, enableCancelledConference](const QSharedPointer<ConferenceInfoCore> &item) {
|
||||
if (!item) return false;
|
||||
if (!enableCancelledConference &&
|
||||
item->getConferenceInfoState() == LinphoneEnums::ConferenceInfoState::Cancelled)
|
||||
return false;
|
||||
return item && item->getDateTimeUtc().date() == today;
|
||||
});
|
||||
} else it = std::find(confInfoList.begin(), confInfoList.end(), nullptr);
|
||||
|
|
@ -236,7 +302,9 @@ QVariant ConferenceInfoList::data(const QModelIndex &index, int role) const {
|
|||
if (role == Qt::DisplayRole) {
|
||||
return QVariant::fromValue(new ConferenceInfoGui(mList[row].objectCast<ConferenceInfoCore>()));
|
||||
} else if (role == Qt::DisplayRole + 1) {
|
||||
return Utils::toDateMonthString(mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc());
|
||||
auto date = mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc();
|
||||
if (date.date().year() != QDate::currentDate().year()) return Utils::toDateMonthAndYearString(date);
|
||||
else return Utils::toDateMonthString(date);
|
||||
}
|
||||
} else { // Dummy date
|
||||
if (role == Qt::DisplayRole) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
|
|
@ -48,28 +48,32 @@ public:
|
|||
void updateHaveCurrentDate();
|
||||
|
||||
int getCurrentDateIndex();
|
||||
QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo();
|
||||
QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo(bool enableCancelledConference = false);
|
||||
|
||||
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo);
|
||||
void connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore);
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
void setAccountConnected(bool connected);
|
||||
bool getAccountConnected() const;
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
signals:
|
||||
void lUpdate(bool isInitialization = false);
|
||||
void initialized();
|
||||
void lUpdate();
|
||||
void addCurrentDateChanged();
|
||||
void haveCurrentDateChanged();
|
||||
void currentDateIndexChanged(int index);
|
||||
void confInfoInserted(QSharedPointer<ConferenceInfoCore> data);
|
||||
void confInfoUpdated(QSharedPointer<ConferenceInfoCore> data);
|
||||
void accountConnectedChanged(bool connected);
|
||||
|
||||
private:
|
||||
QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection;
|
||||
QSharedPointer<AccountCore> mCurrentAccountCore;
|
||||
bool mHaveCurrentDate = false;
|
||||
bool mAccountConnected = false;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
#endif // CONFERENCE_INFO_LIST_H_
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2020 Belledonne Communications SARL.
|
||||
* Copyright (c) 2010-2024 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of linphone-desktop
|
||||
* (see https://www.linphone.org).
|
||||
|
|
@ -57,20 +57,26 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) {
|
|||
if (isSignalConnected(conferenceInfoUpdatedSignal)) emit conferenceInfoUpdated(new ConferenceInfoGui(data));
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
connect(mList.get(), &ConferenceInfoList::initialized, this, &ConferenceInfoProxy::initialized);
|
||||
connect(mList.get(), &ConferenceInfoList::accountConnectedChanged, this,
|
||||
&ConferenceInfoProxy::accountConnectedChanged);
|
||||
}
|
||||
|
||||
ConferenceInfoProxy::~ConferenceInfoProxy() {
|
||||
}
|
||||
|
||||
bool ConferenceInfoProxy::haveCurrentDate() const {
|
||||
return mList->haveCurrentDate();
|
||||
return mList && mList->haveCurrentDate();
|
||||
}
|
||||
|
||||
bool ConferenceInfoProxy::getAccountConnected() const {
|
||||
return mList && mList->getAccountConnected();
|
||||
}
|
||||
|
||||
bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
auto list = qobject_cast<ConferenceInfoList *>(sourceModel());
|
||||
auto ciCore = list->getAt<ConferenceInfoCore>(sourceRow);
|
||||
if (ciCore) {
|
||||
if (ciCore->getDuration() == 0) return false;
|
||||
bool searchTextInSubject = false;
|
||||
bool searchTextInParticipant = false;
|
||||
if (ciCore->getSubject().contains(mFilterText, Qt::CaseInsensitive)) searchTextInSubject = true;
|
||||
|
|
@ -99,6 +105,14 @@ void ConferenceInfoProxy::clear() {
|
|||
mList->clearData();
|
||||
}
|
||||
|
||||
ConferenceInfoGui *ConferenceInfoProxy::getCurrentDateConfInfo(bool enableCancelledConference) {
|
||||
if (mList) {
|
||||
auto confInfo = mList->getCurrentDateConfInfo();
|
||||
return confInfo ? new ConferenceInfoGui(confInfo) : nullptr;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ConferenceInfoProxy::loadUntil(ConferenceInfoGui *confInfo) {
|
||||
return loadUntil(confInfo ? confInfo->mCore : nullptr);
|
||||
}
|
||||
|
|
@ -136,7 +150,7 @@ bool ConferenceInfoProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft
|
|||
auto nowDate = QDate::currentDate();
|
||||
if (!l || !r) { // sort on date
|
||||
auto rdate = r ? r->getDateTimeUtc().date() : QDate::currentDate();
|
||||
return !l ? nowDate <= r->getDateTimeUtc().date() : l->getDateTimeUtc().date() < nowDate;
|
||||
return !l ? nowDate < r->getDateTimeUtc().date() : l->getDateTimeUtc().date() < nowDate;
|
||||
} else {
|
||||
return l->getDateTimeUtc() < r->getDateTimeUtc();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ class ConferenceInfoProxy : public LimitProxy, public AbstractObject {
|
|||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
|
||||
Q_PROPERTY(bool accountConnected READ getAccountConnected NOTIFY accountConnectedChanged)
|
||||
|
||||
public:
|
||||
enum ConferenceInfoFiltering { None = 0, Future = 1 };
|
||||
|
|
@ -43,15 +44,17 @@ public:
|
|||
~ConferenceInfoProxy();
|
||||
|
||||
bool haveCurrentDate() const;
|
||||
bool getAccountConnected() const;
|
||||
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE ConferenceInfoGui *getCurrentDateConfInfo(bool enableCancelledConference = false);
|
||||
Q_INVOKABLE int loadUntil(ConferenceInfoGui *confInfo);
|
||||
int loadUntil(QSharedPointer<ConferenceInfoCore> data);
|
||||
signals:
|
||||
void initialized();
|
||||
void haveCurrentDateChanged();
|
||||
void conferenceInfoCreated(ConferenceInfoGui *confInfo);
|
||||
void conferenceInfoUpdated(ConferenceInfoGui *confInfo);
|
||||
void accountConnectedChanged(bool connected);
|
||||
|
||||
private:
|
||||
QSharedPointer<ConferenceInfoList> mList;
|
||||
|
|
|
|||
63
Linphone/core/emoji/EmojiList.cpp
Normal file
63
Linphone/core/emoji/EmojiList.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "EmojiList.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/chat/message/content/ChatMessageContentGui.hpp"
|
||||
|
||||
#include <QMimeDatabase>
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EmojiList)
|
||||
|
||||
QSharedPointer<EmojiList> EmojiList::create() {
|
||||
auto model = QSharedPointer<EmojiList>(new EmojiList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
return model;
|
||||
}
|
||||
|
||||
EmojiList::EmojiList(QObject *parent) : AbstractListProxy<Reaction>(parent) {
|
||||
mustBeInMainThread(getClassName());
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
EmojiList::~EmojiList() {
|
||||
mustBeInMainThread("~" + getClassName());
|
||||
}
|
||||
|
||||
QList<Reaction> EmojiList::getReactions() {
|
||||
return mList;
|
||||
}
|
||||
|
||||
void EmojiList::setReactions(QList<Reaction> reactions) {
|
||||
resetData(reactions);
|
||||
}
|
||||
|
||||
QVariant EmojiList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole) return QVariant::fromValue(mList.at(row));
|
||||
return QVariant();
|
||||
}
|
||||
49
Linphone/core/emoji/EmojiList.hpp
Normal file
49
Linphone/core/emoji/EmojiList.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EMOJI_LIST_H_
|
||||
#define EMOJI_LIST_H_
|
||||
|
||||
#include "core/chat/message/ChatMessageCore.hpp"
|
||||
#include "core/proxy/AbstractListProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
#include <QLocale>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class EmojiList : public AbstractListProxy<Reaction>, public AbstractObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QSharedPointer<EmojiList> create();
|
||||
EmojiList(QObject *parent = Q_NULLPTR);
|
||||
~EmojiList();
|
||||
|
||||
QList<Reaction> getReactions();
|
||||
void setReactions(QList<Reaction> reactions);
|
||||
|
||||
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
private:
|
||||
QList<Reaction> mReactions;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
91
Linphone/core/emoji/EmojiModel.cpp
Normal file
91
Linphone/core/emoji/EmojiModel.cpp
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* MIT License
|
||||
|
||||
Copyright (c) 2023 AmirHosseinCH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "EmojiModel.hpp"
|
||||
#include "core/path/Paths.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
|
||||
EmojiModel::EmojiModel() {
|
||||
QFile file(QString(":/data/emoji/emoji.json"));
|
||||
auto open = file.open(QIODevice::ReadOnly);
|
||||
QByteArray data = file.readAll();
|
||||
file.close();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
QJsonObject rootObj = doc.object();
|
||||
for (auto category{rootObj.begin()}; category != rootObj.end(); ++category) {
|
||||
emojies[category.key()] = category.value().toArray();
|
||||
QJsonArray &emojiesData = emojies[category.key()];
|
||||
for (auto it{emojiesData.begin()}; it != emojiesData.end(); ++it) {
|
||||
QJsonObject emoji = it->toObject();
|
||||
QJsonArray allKeywords = emoji.value("keywords").toArray();
|
||||
for (auto k{allKeywords.begin()}; k != allKeywords.end(); ++k) {
|
||||
keywords[k->toString()].append(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int EmojiModel::count(QString category) {
|
||||
return emojies[category].size();
|
||||
}
|
||||
|
||||
QString EmojiModel::path(QString category, int index, int skinColor) {
|
||||
QJsonObject emoji = emojies[category][index].toObject();
|
||||
if (emoji.contains("types") && skinColor != -1) {
|
||||
QJsonArray types = emoji.value("types").toArray();
|
||||
return mIconsPath + types[skinColor].toString() + mIconsType;
|
||||
} else return mIconsPath + emoji.value("code").toString() + mIconsType;
|
||||
}
|
||||
|
||||
QVector<QString> EmojiModel::search(QString searchKey, int skinColor) {
|
||||
bool foundFirstItem{false};
|
||||
QVector<QString> searchResult;
|
||||
for (auto it{keywords.begin()}; it != keywords.end(); ++it) {
|
||||
if (it.key().startsWith(searchKey)) {
|
||||
QVector<QJsonObject> &emojiesData{it.value()};
|
||||
for (auto emoji{emojiesData.begin()}; emoji != emojiesData.end(); ++emoji) {
|
||||
if (emoji->contains("types") && skinColor != -1) {
|
||||
QJsonArray types = emoji->value("types").toArray();
|
||||
QString path = mIconsPath + types[skinColor].toString() + mIconsType;
|
||||
if (!searchResult.contains(path)) searchResult.append(path);
|
||||
} else {
|
||||
QString path = mIconsPath + emoji->value("code").toString() + mIconsType;
|
||||
if (!searchResult.contains(path)) searchResult.append(path);
|
||||
}
|
||||
}
|
||||
foundFirstItem = true;
|
||||
} else if (foundFirstItem) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
void EmojiModel::setIconsPath(QString path) {
|
||||
mIconsPath = path;
|
||||
}
|
||||
|
||||
void EmojiModel::setIconsType(QString type) {
|
||||
mIconsType = type;
|
||||
}
|
||||
54
Linphone/core/emoji/EmojiModel.hpp
Normal file
54
Linphone/core/emoji/EmojiModel.hpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* MIT License
|
||||
|
||||
Copyright (c) 2023 AmirHosseinCH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef EMOJIMODEL_H
|
||||
#define EMOJIMODEL_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QObject>
|
||||
|
||||
class EmojiModel : public QObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QString iconsPath WRITE setIconsPath MEMBER mIconsPath)
|
||||
Q_PROPERTY(QString iconsType WRITE setIconsType MEMBER mIconsType)
|
||||
public:
|
||||
EmojiModel();
|
||||
void setIconsPath(QString);
|
||||
void setIconsType(QString);
|
||||
public slots:
|
||||
int count(QString);
|
||||
QString path(QString, int, int = -1);
|
||||
QVector<QString> search(QString, int = -1);
|
||||
|
||||
private:
|
||||
QString mIconsPath;
|
||||
QString mIconsType;
|
||||
QMap<QString, QJsonArray> emojies;
|
||||
QMap<QString, QVector<QJsonObject>> keywords;
|
||||
};
|
||||
|
||||
#endif
|
||||
65
Linphone/core/emoji/EmojiProxy.cpp
Normal file
65
Linphone/core/emoji/EmojiProxy.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 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 "EmojiProxy.hpp"
|
||||
#include "EmojiList.hpp"
|
||||
#include "core/App.hpp"
|
||||
// #include "core/chat/message/ChatMessageGui.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EmojiProxy)
|
||||
|
||||
EmojiProxy::EmojiProxy(QObject *parent) : LimitProxy(parent) {
|
||||
mList = EmojiList::create();
|
||||
setSourceModel(mList.get());
|
||||
connect(mList.get(), &EmojiList::modelReset, this, &EmojiProxy::reactionsChanged);
|
||||
connect(this, &EmojiProxy::filterChanged, this, [this] { invalidate(); });
|
||||
}
|
||||
|
||||
EmojiProxy::~EmojiProxy() {
|
||||
}
|
||||
|
||||
QList<Reaction> EmojiProxy::getReactions() {
|
||||
return mList->getReactions();
|
||||
}
|
||||
|
||||
void EmojiProxy::setReactions(QList<Reaction> reactions) {
|
||||
mList->setReactions(reactions);
|
||||
}
|
||||
|
||||
QString EmojiProxy::getFilter() const {
|
||||
return mFilter;
|
||||
}
|
||||
|
||||
void EmojiProxy::setFilter(QString filter) {
|
||||
if (mFilter != filter) {
|
||||
mFilter = filter;
|
||||
emit filterChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool EmojiProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
|
||||
auto emoji = mList->getAt(sourceRow);
|
||||
return emoji.mBody.contains(mFilter);
|
||||
}
|
||||
|
||||
bool EmojiProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
|
||||
return true;
|
||||
}
|
||||
62
Linphone/core/emoji/EmojiProxy.hpp
Normal file
62
Linphone/core/emoji/EmojiProxy.hpp
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
/*
|
||||
* Copyright (c) 2010-2024 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 EMOJI_PROXY_H_
|
||||
#define EMOJI_PROXY_H_
|
||||
|
||||
#include "core/chat/message/ChatMessageCore.hpp"
|
||||
#include "core/emoji/EmojiModel.hpp"
|
||||
#include "core/proxy/LimitProxy.hpp"
|
||||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class EmojiList;
|
||||
|
||||
class EmojiProxy : public LimitProxy, public AbstractObject {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QList<Reaction> reactions READ getReactions WRITE setReactions NOTIFY reactionsChanged)
|
||||
Q_PROPERTY(QString filter READ getFilter WRITE setFilter NOTIFY filterChanged)
|
||||
|
||||
public:
|
||||
EmojiProxy(QObject *parent = Q_NULLPTR);
|
||||
~EmojiProxy();
|
||||
|
||||
QList<Reaction> getReactions();
|
||||
void setReactions(QList<Reaction> reactions);
|
||||
|
||||
QString getFilter() const;
|
||||
void setFilter(QString filter);
|
||||
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
|
||||
|
||||
signals:
|
||||
void reactionsChanged();
|
||||
void filterChanged();
|
||||
|
||||
protected:
|
||||
QString mFilter;
|
||||
QSharedPointer<EmojiList> mList;
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 <QtDebug>
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
using namespace std;
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(AbstractEventCountNotifier)
|
||||
|
||||
AbstractEventCountNotifier::AbstractEventCountNotifier(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
int AbstractEventCountNotifier::getEventCount() const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
int count = coreModel->getCore()->getMissedCallsCount();
|
||||
if (SettingsModel::getInstance()->getStandardChatEnabled() || SettingsModel::getInstance()->getSecureChatEnabled())
|
||||
count += coreModel->getCore()->getUnreadChatMessageCountFromActiveLocals();
|
||||
return count;
|
||||
}
|
||||
|
||||
int AbstractEventCountNotifier::getCurrentEventCount() const {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
int count = coreModel->getCore()->getMissedCallsCount();
|
||||
bool filtered = SettingsModel::getInstance()->isSystrayNotificationFiltered();
|
||||
bool global = SettingsModel::getInstance()->isSystrayNotificationGlobal();
|
||||
// if (global && !filtered)
|
||||
if (true) return getEventCount();
|
||||
else {
|
||||
auto currentAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (currentAccount) {
|
||||
count += currentAccount->getUnreadChatMessageCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
#define ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include "tool/AbstractObject.hpp"
|
||||
#include "tool/thread/SafeConnection.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace linphone {
|
||||
class ChatMessage;
|
||||
}
|
||||
|
||||
class CallModel;
|
||||
class ChatRoomModel;
|
||||
class HistoryModel;
|
||||
|
||||
class AbstractEventCountNotifier : public QObject, public AbstractObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AbstractEventCountNotifier(QObject *parent = Q_NULLPTR);
|
||||
|
||||
int getEventCount() const; // global
|
||||
int getCurrentEventCount() const; // Current account
|
||||
|
||||
protected:
|
||||
virtual void notifyEventCount(int n) = 0;
|
||||
|
||||
private:
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif // ABSTRACT_EVENT_COUNT_NOTIFIER_H_
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
#define EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
extern "C" void notifyEventCountMacOs(int n);
|
||||
|
||||
class EventCountNotifier : public AbstractEventCountNotifier {
|
||||
public:
|
||||
EventCountNotifier(QObject *parent = Q_NULLPTR) : AbstractEventCountNotifier(parent) {
|
||||
}
|
||||
|
||||
void notifyEventCount(int n) override {
|
||||
notifyEventCountMacOs(n);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // EVENT_COUNT_NOTIFIER_MAC_OS_H_
|
||||
30
Linphone/core/event-count-notifier/EventCountNotifierMacOs.m
Normal file
30
Linphone/core/event-count-notifier/EventCountNotifierMacOs.m
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* EventCountNotifierMacOs.m
|
||||
* Copyright (C) 2017-2018 Belledonne Communications, Grenoble, France
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* Created on: June 30, 2017
|
||||
* Author: Ghislain MARY
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
// =============================================================================
|
||||
|
||||
void notifyEventCountMacOs (int n) {
|
||||
NSString *badgeStr = (n > 0) ? [NSString stringWithFormat:@"%d", n] : @"";
|
||||
[[NSApp dockTile] setBadgeLabel:badgeStr];
|
||||
}
|
||||
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 <QIcon>
|
||||
#include <QPainter>
|
||||
#include <QSvgRenderer>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTimer>
|
||||
#include <QWindow>
|
||||
|
||||
#include "core/App.hpp"
|
||||
#include "model/core/CoreModel.hpp"
|
||||
#include "model/setting/SettingsModel.hpp"
|
||||
#include "tool/Constants.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
#include "EventCountNotifierSystemTrayIcon.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
namespace {
|
||||
constexpr int IconWidth = 256;
|
||||
constexpr int IconHeight = 256;
|
||||
|
||||
constexpr int IconCounterBackgroundRadius = 100;
|
||||
constexpr int IconCounterBlinkInterval = 1000;
|
||||
constexpr int IconCounterTextPixelSize = 144;
|
||||
} // namespace
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(EventCountNotifier)
|
||||
|
||||
QSharedPointer<EventCountNotifier> EventCountNotifier::create(QObject *parent) {
|
||||
auto sharedPointer = QSharedPointer<EventCountNotifier>(new EventCountNotifier(parent), &QObject::deleteLater);
|
||||
sharedPointer->setSelf(sharedPointer);
|
||||
sharedPointer->moveToThread(App::getInstance()->thread());
|
||||
return sharedPointer;
|
||||
}
|
||||
|
||||
EventCountNotifier::EventCountNotifier(QObject *parent) : AbstractEventCountNotifier(parent) {
|
||||
QSvgRenderer renderer((QString(Constants::WindowIconPath)));
|
||||
if (!renderer.isValid()) qFatal("Invalid SVG Image.");
|
||||
|
||||
QPixmap buf(IconWidth, IconHeight);
|
||||
buf.fill(QColor(Qt::transparent));
|
||||
|
||||
QPainter painter(&buf);
|
||||
renderer.render(&painter);
|
||||
|
||||
mBuf = new QPixmap(buf);
|
||||
mBufWithCounter = new QPixmap();
|
||||
|
||||
mBlinkTimer = new QTimer(this);
|
||||
mBlinkTimer->setInterval(IconCounterBlinkInterval);
|
||||
connect(mBlinkTimer, &QTimer::timeout, this, &EventCountNotifier::update);
|
||||
}
|
||||
|
||||
void EventCountNotifier::setSelf(QSharedPointer<EventCountNotifier> me) {
|
||||
}
|
||||
|
||||
EventCountNotifier::~EventCountNotifier() {
|
||||
delete mBuf;
|
||||
delete mBufWithCounter;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void EventCountNotifier::notifyEventCount(int n) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
n = n > 99 ? 99 : n;
|
||||
QSystemTrayIcon *sysTrayIcon = App::getInstance()->getSystemTrayIcon();
|
||||
if (!sysTrayIcon) return;
|
||||
|
||||
if (!n) {
|
||||
mBlinkTimer->stop();
|
||||
sysTrayIcon->setIcon(QIcon(*mBuf));
|
||||
return;
|
||||
}
|
||||
|
||||
*mBufWithCounter = *mBuf;
|
||||
QPainter p(mBufWithCounter);
|
||||
|
||||
const int width = mBufWithCounter->width();
|
||||
const int height = mBufWithCounter->height();
|
||||
|
||||
// Draw background.
|
||||
{
|
||||
p.setBrush(QColor(Utils::getDefaultStyleColor("main1_100")));
|
||||
p.drawEllipse(QPointF(width / 2, height / 2), IconCounterBackgroundRadius, IconCounterBackgroundRadius);
|
||||
}
|
||||
|
||||
// Draw text.
|
||||
{
|
||||
QFont font = p.font();
|
||||
font.setPixelSize(IconCounterTextPixelSize);
|
||||
|
||||
p.setFont(font);
|
||||
p.setPen(QPen(QColor(Utils::getDefaultStyleColor("main1_500_main"))));
|
||||
p.drawText(QRect(0, 0, width, height), Qt::AlignCenter, QString::number(n));
|
||||
}
|
||||
|
||||
// Change counter.
|
||||
mBlinkTimer->stop();
|
||||
auto coreModel = CoreModel::getInstance();
|
||||
if (!coreModel->isInitialized() || SettingsModel::getInstance()->isSystrayNotificationBlinkEnabled())
|
||||
mBlinkTimer->start();
|
||||
mDisplayCounter = true;
|
||||
update();
|
||||
}
|
||||
|
||||
void EventCountNotifier::update() {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
QSystemTrayIcon *sysTrayIcon = App::getInstance()->getSystemTrayIcon();
|
||||
if (sysTrayIcon) {
|
||||
sysTrayIcon->setIcon(QIcon(mDisplayCounter ? *mBufWithCounter : *mBuf));
|
||||
}
|
||||
mDisplayCounter = !mDisplayCounter;
|
||||
}
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
#define EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
|
||||
#include "AbstractEventCountNotifier.hpp"
|
||||
|
||||
// =============================================================================
|
||||
|
||||
class QTimer;
|
||||
|
||||
class EventCountNotifier : public AbstractEventCountNotifier {
|
||||
public:
|
||||
static QSharedPointer<EventCountNotifier> create(QObject *parent = Q_NULLPTR);
|
||||
EventCountNotifier(QObject *parent = Q_NULLPTR);
|
||||
void setSelf(QSharedPointer<EventCountNotifier> me);
|
||||
~EventCountNotifier();
|
||||
|
||||
void notifyEventCount(int n) override;
|
||||
|
||||
private:
|
||||
const QPixmap *mBuf = nullptr;
|
||||
QPixmap *mBufWithCounter = nullptr;
|
||||
QTimer *mBlinkTimer = nullptr;
|
||||
bool mDisplayCounter = false;
|
||||
QSharedPointer<SafeConnection<EventCountNotifier, CoreModel>> mCoreModelConnection;
|
||||
void update();
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
#endif // EVENT_COUNT_NOTIFIER_SYSTEM_TRAY_ICON_H_
|
||||
|
|
@ -48,8 +48,9 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
|
|||
mustBeInLinphoneThread(getClassName());
|
||||
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
|
||||
mFriendModel->setSelf(mFriendModel);
|
||||
mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
|
||||
mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
|
||||
auto presence = mFriendModel->getPresence(contact);
|
||||
auto note = mFriendModel->getPresenceNote(contact);
|
||||
App::postCoreAsync([this, presence, note]() { setPresence(presence, note); });
|
||||
mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
|
||||
mFullName = mFriendModel->getFullName();
|
||||
auto defaultAddress = contact->getAddress();
|
||||
|
|
@ -65,7 +66,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
|
|||
auto addresses = contact->getAddresses();
|
||||
for (auto &address : addresses) {
|
||||
mAddressList.append(Utils::createFriendAddressVariant(
|
||||
tr("sip_address"), Utils::coreStringToAppString(address->asStringUriOnly())));
|
||||
tr("sip_address"), Utils::coreStringToAppString(address->asStringUriOnly())));
|
||||
}
|
||||
mDefaultAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asStringUriOnly()) : QString();
|
||||
mDefaultFullAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asString()) : QString();
|
||||
|
|
@ -90,7 +91,8 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
|
|||
mStarred = contact->getStarred();
|
||||
mIsSaved = true;
|
||||
mIsStored = isStored;
|
||||
mIsLdap = ToolModel::friendIsInFriendList(ToolModel::getLdapFriendList(), contact);
|
||||
mIsLdap = ToolModel::friendIsInFriendList(ToolModel::getLdapFriendList(), contact) ||
|
||||
(sourceFlags & (int)linphone::MagicSearch::Source::LdapServers) != 0;
|
||||
mIsCardDAV = (sourceFlags & (int)linphone::MagicSearch::Source::RemoteCardDAV) != 0;
|
||||
mIsAppFriend = ToolModel::friendIsInFriendList(ToolModel::getAppFriendList(), contact);
|
||||
} else {
|
||||
|
|
@ -142,8 +144,7 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
|||
mFriendModelConnection->makeConnectToModel(
|
||||
&FriendModel::removed, [this]() { mFriendModelConnection->invokeToCore([this]() { removed(this); }); });
|
||||
mFriendModelConnection->makeConnectToModel(
|
||||
&FriendModel::presenceReceived,
|
||||
[this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) {
|
||||
&FriendModel::presenceReceived, [this](LinphoneEnums::Presence presence, QString presenceNote) {
|
||||
auto devices = mFriendModel->getDevices();
|
||||
QVariantList devicesList;
|
||||
for (auto &device : devices) {
|
||||
|
|
@ -153,14 +154,11 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
|||
Utils::coreStringToAppString(device->getAddress()->asString()),
|
||||
LinphoneEnums::fromLinphone(device->getSecurityLevel())));
|
||||
}
|
||||
mFriendModelConnection->invokeToCore(
|
||||
[this, consolidatedPresence, presenceTimestamp, devicesList]() {
|
||||
setConsolidatedPresence(consolidatedPresence);
|
||||
setPresenceTimestamp(presenceTimestamp);
|
||||
|
||||
setDevices(devicesList);
|
||||
updateVerifiedDevicesCount();
|
||||
});
|
||||
mFriendModelConnection->invokeToCore([this, presence, devicesList, presenceNote]() {
|
||||
setPresence(presence, presenceNote);
|
||||
setDevices(devicesList);
|
||||
updateVerifiedDevicesCount();
|
||||
});
|
||||
});
|
||||
mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) {
|
||||
mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); });
|
||||
|
|
@ -188,7 +186,7 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
|
|||
QList<QVariant> addr;
|
||||
for (auto &num : numbers) {
|
||||
addr.append(Utils::createFriendAddressVariant(
|
||||
tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly())));
|
||||
tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly())));
|
||||
}
|
||||
mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); });
|
||||
});
|
||||
|
|
@ -419,9 +417,10 @@ void FriendCore::appendAddress(const QString &addr) {
|
|||
QString interpretedFullAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asString()) : "";
|
||||
QString interpretedAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()) : "";
|
||||
mCoreModelConnection->invokeToCore([this, interpretedAddress, interpretedFullAddress]() {
|
||||
if (interpretedAddress.isEmpty()) Utils::showInformationPopup(tr("information_popup_error_title"),
|
||||
//: "Adresse invalide"
|
||||
tr("information_popup_invalid_address_message"), false);
|
||||
if (interpretedAddress.isEmpty())
|
||||
Utils::showInformationPopup(tr("information_popup_error_title"),
|
||||
//: "Adresse invalide"
|
||||
tr("information_popup_invalid_address_message"), false);
|
||||
else {
|
||||
mAddressList.append(Utils::createFriendAddressVariant(tr("sip_address"), interpretedAddress));
|
||||
if (mDefaultFullAddress.isEmpty()) mDefaultFullAddress = interpretedFullAddress;
|
||||
|
|
@ -507,30 +506,6 @@ void FriendCore::setDefaultAddress(const QString &address) {
|
|||
}
|
||||
}
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence FriendCore::getConsolidatedPresence() const {
|
||||
return mConsolidatedPresence;
|
||||
}
|
||||
|
||||
void FriendCore::setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mConsolidatedPresence != presence) {
|
||||
mConsolidatedPresence = presence;
|
||||
emit consolidatedPresenceChanged(mConsolidatedPresence);
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime FriendCore::getPresenceTimestamp() const {
|
||||
return mPresenceTimestamp;
|
||||
}
|
||||
|
||||
void FriendCore::setPresenceTimestamp(QDateTime presenceTimestamp) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mPresenceTimestamp != presenceTimestamp) {
|
||||
mPresenceTimestamp = presenceTimestamp;
|
||||
emit presenceTimestampChanged(mPresenceTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
QString FriendCore::getPictureUri() const {
|
||||
return mPictureUri;
|
||||
}
|
||||
|
|
@ -612,8 +587,8 @@ void FriendCore::writeFromModel(const std::shared_ptr<FriendModel> &model) {
|
|||
|
||||
QList<QVariant> addresses;
|
||||
for (auto &addr : model->getAddresses()) {
|
||||
addresses.append(
|
||||
Utils::createFriendAddressVariant(tr("sip_address"), Utils::coreStringToAppString(addr->asStringUriOnly())));
|
||||
addresses.append(Utils::createFriendAddressVariant(tr("sip_address"),
|
||||
Utils::coreStringToAppString(addr->asStringUriOnly())));
|
||||
}
|
||||
mAddressList = addresses;
|
||||
mDefaultAddress = model->getDefaultAddress();
|
||||
|
|
@ -759,3 +734,29 @@ bool FriendCore::getReadOnly() const {
|
|||
std::shared_ptr<FriendModel> FriendCore::getFriendModel() {
|
||||
return mFriendModel;
|
||||
}
|
||||
|
||||
void FriendCore::setPresence(LinphoneEnums::Presence presence, QString presenceNote) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
bool notify = false;
|
||||
if (presence != mPresence) {
|
||||
mPresence = presence;
|
||||
notify = true;
|
||||
}
|
||||
if (presenceNote != mPresenceNote) {
|
||||
mPresenceNote = presenceNote;
|
||||
notify = true;
|
||||
}
|
||||
if (notify) emit presenceChanged();
|
||||
}
|
||||
|
||||
QUrl FriendCore::getPresenceIcon() {
|
||||
return Utils::getPresenceIcon(mPresence);
|
||||
}
|
||||
|
||||
QColor FriendCore::getPresenceColor() {
|
||||
return Utils::getPresenceColor(mPresence);
|
||||
}
|
||||
|
||||
QString FriendCore::getPresenceStatus() {
|
||||
return Utils::getPresenceStatus(mPresence);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@
|
|||
#include "tool/thread/SafeSharedPointer.hpp"
|
||||
#include <linphone++/linphone.hh>
|
||||
|
||||
#include <QColor>
|
||||
#include <QDateTime>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSharedPointer>
|
||||
|
||||
|
|
@ -63,9 +63,11 @@ class FriendCore : public QObject, public AbstractObject {
|
|||
Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged)
|
||||
Q_PROPERTY(QString defaultFullAddress READ getDefaultFullAddress WRITE setDefaultFullAddress NOTIFY
|
||||
defaultFullAddressChanged)
|
||||
Q_PROPERTY(QDateTime presenceTimestamp READ getPresenceTimestamp NOTIFY presenceTimestampChanged)
|
||||
Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
|
||||
consolidatedPresenceChanged)
|
||||
Q_PROPERTY(LinphoneEnums::Presence presence MEMBER mPresence NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QUrl presenceIcon READ getPresenceIcon NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QColor presenceColor READ getPresenceColor NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QString presenceStatus READ getPresenceStatus NOTIFY presenceChanged)
|
||||
Q_PROPERTY(QString presenceNote MEMBER mPresenceNote NOTIFY presenceChanged)
|
||||
Q_PROPERTY(bool isSaved READ getIsSaved NOTIFY isSavedChanged)
|
||||
Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged)
|
||||
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
|
||||
|
|
@ -130,12 +132,6 @@ public:
|
|||
void setDevices(QVariantList devices);
|
||||
Q_INVOKABLE LinphoneEnums::SecurityLevel getSecurityLevelForAddress(const QString &address) const;
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence getConsolidatedPresence() const;
|
||||
void setConsolidatedPresence(LinphoneEnums::ConsolidatedPresence presence);
|
||||
|
||||
QDateTime getPresenceTimestamp() const;
|
||||
void setPresenceTimestamp(QDateTime presenceTimestamp);
|
||||
|
||||
bool getIsSaved() const;
|
||||
void setIsSaved(bool isSaved);
|
||||
|
||||
|
|
@ -146,8 +142,6 @@ public:
|
|||
void setPictureUri(const QString &uri);
|
||||
void onPictureUriChanged(QString uri);
|
||||
|
||||
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
|
||||
|
||||
bool isLdap() const;
|
||||
bool isAppFriend() const;
|
||||
bool isCardDAV() const;
|
||||
|
|
@ -159,6 +153,10 @@ public:
|
|||
Q_INVOKABLE void save();
|
||||
Q_INVOKABLE void undo();
|
||||
|
||||
QColor getPresenceColor();
|
||||
QString getPresenceStatus();
|
||||
QUrl getPresenceIcon();
|
||||
|
||||
protected:
|
||||
void resetPhoneNumbers(QList<QVariant> newList);
|
||||
void resetAddresses(QList<QVariant> newList);
|
||||
|
|
@ -173,8 +171,6 @@ signals:
|
|||
void addressChanged();
|
||||
void organizationChanged();
|
||||
void jobChanged();
|
||||
void consolidatedPresenceChanged(LinphoneEnums::ConsolidatedPresence level);
|
||||
void presenceTimestampChanged(QDateTime presenceTimestamp);
|
||||
void pictureUriChanged();
|
||||
void saved();
|
||||
void isSavedChanged(bool isSaved);
|
||||
|
|
@ -186,13 +182,16 @@ signals:
|
|||
void devicesChanged();
|
||||
void verifiedDevicesChanged();
|
||||
void lSetStarred(bool starred);
|
||||
void presenceChanged();
|
||||
|
||||
protected:
|
||||
void writeIntoModel(std::shared_ptr<FriendModel> model) const;
|
||||
void writeFromModel(const std::shared_ptr<FriendModel> &model);
|
||||
|
||||
LinphoneEnums::ConsolidatedPresence mConsolidatedPresence = LinphoneEnums::ConsolidatedPresence::Offline;
|
||||
QDateTime mPresenceTimestamp;
|
||||
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
|
||||
QColor mPresenceColor;
|
||||
QString mPresenceStatus;
|
||||
QString mPresenceNote = "";
|
||||
QString mGivenName;
|
||||
QString mFamilyName;
|
||||
QString mFullName;
|
||||
|
|
@ -214,6 +213,9 @@ protected:
|
|||
QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection;
|
||||
QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection;
|
||||
|
||||
private:
|
||||
void setPresence(LinphoneEnums::Presence presence, QString presenceNote);
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -64,22 +64,27 @@ void LoginPage::login(const QString &username,
|
|||
const QString &password,
|
||||
QString displayName,
|
||||
QString domain,
|
||||
LinphoneEnums::TransportType transportType) {
|
||||
LinphoneEnums::TransportType transportType,
|
||||
QString registrarUri,
|
||||
QString outboundProxyAddress,
|
||||
QString connectionId) {
|
||||
setErrorMessage("");
|
||||
App::postModelAsync([=]() {
|
||||
// Create on Model thread.
|
||||
AccountManager *accountManager = new AccountManager();
|
||||
connect(accountManager, &AccountManager::registrationStateChanged, this,
|
||||
[accountManager, this](linphone::RegistrationState state, QString message) mutable {
|
||||
[accountManager, this](linphone::RegistrationState state, linphone::Reason reason,
|
||||
QString message) mutable {
|
||||
// View thread
|
||||
setRegistrationState(state);
|
||||
mBadIds = reason == linphone::Reason::Forbidden;
|
||||
emit reasonChanged();
|
||||
switch (state) {
|
||||
case linphone::RegistrationState::Failed: {
|
||||
if (message.isEmpty())
|
||||
//: Erreur durant la connexion
|
||||
setErrorMessage(tr("default_account_connection_state_error_toast"));
|
||||
else
|
||||
setErrorMessage(message);
|
||||
if (message.isEmpty())
|
||||
//: Erreur durant la connexion, veuillez vérifier vos paramètres
|
||||
setErrorMessage(tr("default_account_connection_state_error_toast"));
|
||||
else setErrorMessage(message);
|
||||
if (accountManager) {
|
||||
accountManager->deleteLater();
|
||||
accountManager = nullptr;
|
||||
|
|
@ -110,9 +115,9 @@ void LoginPage::login(const QString &username,
|
|||
|
||||
QString error;
|
||||
if (!accountManager->login(username, password, displayName, domain, LinphoneEnums::toLinphone(transportType),
|
||||
&error)) {
|
||||
&error, registrarUri, outboundProxyAddress, connectionId)) {
|
||||
setErrorMessage(error);
|
||||
emit accountManager->registrationStateChanged(linphone::RegistrationState::None);
|
||||
emit accountManager->registrationStateChanged(linphone::RegistrationState::None, linphone::Reason::None);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,12 +35,16 @@ public:
|
|||
|
||||
Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged)
|
||||
Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged)
|
||||
Q_PROPERTY(bool badIds MEMBER mBadIds NOTIFY reasonChanged)
|
||||
|
||||
Q_INVOKABLE void login(const QString &username,
|
||||
const QString &password,
|
||||
QString displayName = QString(),
|
||||
QString domain = QString(),
|
||||
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tls);
|
||||
LinphoneEnums::TransportType transportType = LinphoneEnums::TransportType::Tls,
|
||||
QString registrarUri = QString(),
|
||||
QString outboundProxyAddress = QString(),
|
||||
QString connectionId = QString());
|
||||
|
||||
linphone::RegistrationState getRegistrationState() const;
|
||||
void setRegistrationState(linphone::RegistrationState status);
|
||||
|
|
@ -51,10 +55,12 @@ public:
|
|||
signals:
|
||||
void registrationStateChanged();
|
||||
void errorMessageChanged(QString error);
|
||||
void reasonChanged();
|
||||
|
||||
private:
|
||||
linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None;
|
||||
QString mErrorMessage;
|
||||
bool mBadIds = false;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,8 +33,10 @@
|
|||
|
||||
#include "core/App.hpp"
|
||||
#include "core/call/CallGui.hpp"
|
||||
#include "core/chat/ChatGui.hpp"
|
||||
#include "model/tool/ToolModel.hpp"
|
||||
#include "tool/LinphoneEnums.hpp"
|
||||
#include "tool/accessibility/AccessibilityHelper.hpp"
|
||||
#include "tool/providers/AvatarProvider.hpp"
|
||||
#include "tool/providers/ImageProvider.hpp"
|
||||
|
||||
|
|
@ -85,9 +87,9 @@ void setProperty(QObject &object, const char *property, const T &value) {
|
|||
// =============================================================================
|
||||
|
||||
const QHash<int, Notifier::Notification> Notifier::Notifications = {
|
||||
//{Notifier::ReceivedMessage, {Notifier::ReceivedMessage, "NotificationReceivedMessage.qml", 10}},
|
||||
{Notifier::ReceivedMessage, {Notifier::ReceivedMessage, "NotificationReceivedMessage.qml", 10}},
|
||||
//{Notifier::ReceivedFileMessage, {Notifier::ReceivedFileMessage, "NotificationReceivedFileMessage.qml", 10}},
|
||||
{Notifier::ReceivedCall, {Notifier::ReceivedCall, "NotificationReceivedCall.qml", 30}},
|
||||
{Notifier::ReceivedCall, {Notifier::ReceivedCall, "NotificationReceivedCall.qml", 30}}
|
||||
//{Notifier::NewVersionAvailable, {Notifier::NewVersionAvailable, "NotificationNewVersionAvailable.qml", 30}},
|
||||
//{Notifier::SnapshotWasTaken, {Notifier::SnapshotWasTaken, "NotificationSnapshotWasTaken.qml", 10}},
|
||||
//{Notifier::RecordingCompleted, {Notifier::RecordingCompleted, "NotificationRecordingCompleted.qml", 10}}
|
||||
|
|
@ -127,8 +129,8 @@ Notifier::~Notifier() {
|
|||
|
||||
bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) {
|
||||
mMutex->lock();
|
||||
Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber);
|
||||
if (mInstancesNumber == MaxNotificationsNumber) { // Check existing instances.
|
||||
// Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber);
|
||||
if (mInstancesNumber >= MaxNotificationsNumber) { // Check existing instances.
|
||||
qWarning() << QStringLiteral("Unable to create another notification.");
|
||||
mMutex->unlock();
|
||||
return false;
|
||||
|
|
@ -163,7 +165,6 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
|
|||
engine->deleteLater();
|
||||
exit(-1);
|
||||
} else {
|
||||
lDebug() << engine->rootObjects()[0];
|
||||
auto window = qobject_cast<QQuickWindow *>(obj);
|
||||
if (window) {
|
||||
window->setProperty(NotificationPropertyData, data);
|
||||
|
|
@ -171,28 +172,24 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
|
|||
// window->setProperty(it.key().toLatin1(), it.value());
|
||||
const int timeout = Notifications[type].getTimeout() * 1000;
|
||||
auto updateNotificationCoordinates = [this, window, screen](int width, int height) {
|
||||
int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
|
||||
auto screenHeightOffset =
|
||||
screen ? mScreenHeightOffset.value(screen->name()) : 0; // Access optimization
|
||||
QRect availableGeometry = screen->availableGeometry();
|
||||
int heightOffset = availableGeometry.y() +
|
||||
(availableGeometry.height() -
|
||||
height); //*screen->devicePixelRatio(); when using manual scaler
|
||||
|
||||
window->setX(availableGeometry.x() +
|
||||
(availableGeometry.width() -
|
||||
width)); //*screen->devicePixelRatio()); when using manual scaler
|
||||
window->setY(heightOffset - (*screenHeightOffset % heightOffset));
|
||||
window->setY(availableGeometry.y() + availableGeometry.height() - screenHeightOffset -
|
||||
height);
|
||||
};
|
||||
QObject::connect(window, &QQuickWindow::widthChanged,
|
||||
[window, updateNotificationCoordinates](int w) {
|
||||
updateNotificationCoordinates(w, window->height());
|
||||
});
|
||||
QObject::connect(window, &QQuickWindow::heightChanged,
|
||||
[window, updateNotificationCoordinates](int h) {
|
||||
updateNotificationCoordinates(window->width(), h);
|
||||
});
|
||||
updateNotificationCoordinates(window->width(), window->height());
|
||||
QObject::connect(window, &QQuickWindow::closing, window,
|
||||
[this, window] { deleteNotification(QVariant::fromValue(window)); });
|
||||
auto screenHeightOffset =
|
||||
screen ? mScreenHeightOffset.take(screen->name()) : 0; // Access optimization
|
||||
mScreenHeightOffset.insert(screen->name(), screenHeightOffset + window->height());
|
||||
QObject::connect(window, &QQuickWindow::closing, window, [this, window] {
|
||||
qDebug() << "closing notification";
|
||||
deleteNotification(QVariant::fromValue(window));
|
||||
});
|
||||
showNotification(window, timeout);
|
||||
lInfo() << QStringLiteral("Create notification:") << QVariant::fromValue(window);
|
||||
}
|
||||
|
|
@ -212,8 +209,6 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
|
|||
|
||||
void Notifier::showNotification(QObject *notification, int timeout) {
|
||||
// Display notification.
|
||||
QMetaObject::invokeMethod(notification, NotificationShowMethodName, Qt::DirectConnection);
|
||||
|
||||
QTimer *timer = new QTimer(notification);
|
||||
timer->setInterval(timeout);
|
||||
timer->setSingleShot(true);
|
||||
|
|
@ -285,63 +280,153 @@ void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
|
|||
auto account = ToolModel::findAccount(call->getToAddress());
|
||||
if (account) {
|
||||
auto accountModel = Utils::makeQObject_ptr<AccountModel>(account);
|
||||
accountModel->setSelf(accountModel);
|
||||
if (!accountModel->getNotificationsAllowed()) {
|
||||
qInfo()
|
||||
<< "Notifications have been disabled for this account - not creating a notification for incoming call";
|
||||
lInfo() << log().arg(
|
||||
"Notifications have been disabled for this account - not creating a notification for incoming call");
|
||||
if (accountModel->forwardToVoiceMailInDndPresence()) {
|
||||
lInfo() << log().arg("Transferring call to voicemail");
|
||||
auto voicemailAddress = linphone::Factory::get()->createAddress(
|
||||
Utils::appStringToCoreString(accountModel->getVoicemailAddress()));
|
||||
if (voicemailAddress) call->transferTo(voicemailAddress);
|
||||
}
|
||||
return;
|
||||
}
|
||||
accountModel->deleteLater();
|
||||
}
|
||||
|
||||
auto model = CallCore::create(call);
|
||||
auto gui = new CallGui(model);
|
||||
gui->moveToThread(App::getInstance()->thread());
|
||||
App::postCoreAsync([this, gui]() {
|
||||
auto callLog = call->getCallLog();
|
||||
auto displayName = callLog && callLog->getConferenceInfo()
|
||||
? Utils::coreStringToAppString(callLog->getConferenceInfo()->getSubject())
|
||||
: ToolModel::getDisplayName(call->getRemoteAddress());
|
||||
|
||||
// Accessibility alert
|
||||
//: New call from %1
|
||||
AccessibilityHelper::announceMessage(tr("new_call_alert_accessible_name").arg(displayName));
|
||||
|
||||
App::postCoreAsync([this, gui, displayName]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
QVariantMap map;
|
||||
|
||||
map["displayName"].setValue(displayName);
|
||||
map["call"].setValue(gui);
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedCall, map)
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
void Notifier::notifyReceivedMessages(const list<shared_ptr<linphone::ChatMessage>> &messages) {
|
||||
QVariantMap map;
|
||||
QString txt;
|
||||
if (messages.size() > 0) {
|
||||
shared_ptr<linphone::ChatMessage> message = messages.front();
|
||||
void Notifier::notifyReceivedMessages(const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const list<shared_ptr<linphone::ChatMessage>> &messages) {
|
||||
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
|
||||
|
||||
if (messages.size() == 1) {
|
||||
auto fileContent = message->getFileTransferInformation();
|
||||
if (!fileContent) {
|
||||
foreach (auto content, message->getContents()) {
|
||||
if (content->isText()) txt += content->getUtf8Text().c_str();
|
||||
}
|
||||
} else if (fileContent->isVoiceRecording())
|
||||
//: 'Voice message received!' : message to warn the user in a notofication for voice messages.
|
||||
txt = tr("new_voice_message");
|
||||
else txt = tr("new_file_message");
|
||||
if (txt.isEmpty() && message->hasConferenceInvitationContent())
|
||||
//: 'Conference invitation received!' : Notification about receiving an invitation to a conference.
|
||||
txt = tr("new_conference_invitation");
|
||||
} else
|
||||
//: 'New messages received!' Notification that warn the user of new messages.
|
||||
txt = tr("new_chat_room_messages");
|
||||
map["message"] = txt;
|
||||
shared_ptr<linphone::ChatRoom> chatRoom(message->getChatRoom());
|
||||
map["timelineModel"].setValue(
|
||||
CoreManager::getInstance()->getTimelineListModel()->getTimeline(chatRoom, true).get());
|
||||
if (messages.size() == 1) { // Display only sender on mono message.
|
||||
map["remoteAddress"] = Utils::coreStringToAppString(message->getFromAddress()->asStringUriOnly());
|
||||
map["fullremoteAddress"] = Utils::coreStringToAppString(message->getFromAddress()->asString());
|
||||
}
|
||||
map["localAddress"] = Utils::coreStringToAppString(message->getToAddress()->asStringUriOnly());
|
||||
map["fullLocalAddress"] = Utils::coreStringToAppString(message->getToAddress()->asString());
|
||||
map["window"].setValue(App::getInstance()->getMainWindow());
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedMessage, map)
|
||||
}
|
||||
if (room->getMuted()) return;
|
||||
|
||||
QString txt;
|
||||
QString remoteAddress;
|
||||
|
||||
if (messages.size() > 0) {
|
||||
|
||||
shared_ptr<linphone::ChatMessage> message = messages.front();
|
||||
auto receiverAccount = ToolModel::findAccount(message->getToAddress());
|
||||
if (receiverAccount) {
|
||||
auto senderAccount = ToolModel::findAccount(message->getFromAddress());
|
||||
auto currentAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (senderAccount && senderAccount->getContactAddress() && currentAccount->getContactAddress() &&
|
||||
senderAccount->getContactAddress()->weakEqual(currentAccount->getContactAddress())) {
|
||||
qDebug() << "sender is current account, return";
|
||||
return;
|
||||
}
|
||||
auto accountModel = Utils::makeQObject_ptr<AccountModel>(receiverAccount);
|
||||
if (!accountModel->getNotificationsAllowed()) {
|
||||
lInfo() << log().arg(
|
||||
"Notifications have been disabled for this account - not creating a notification for "
|
||||
"incoming message");
|
||||
return;
|
||||
}
|
||||
accountModel->deleteLater();
|
||||
}
|
||||
|
||||
auto getMessage = [this, &remoteAddress, &txt](const shared_ptr<linphone::ChatMessage> &message) {
|
||||
if (message->isRead()) return;
|
||||
auto remoteAddr = message->getFromAddress();
|
||||
// remoteAddr->clean();
|
||||
remoteAddress = Utils::coreStringToAppString(remoteAddr->asStringUriOnly());
|
||||
auto fileContent = message->getFileTransferInformation();
|
||||
if (!fileContent) {
|
||||
for (auto content : message->getContents()) {
|
||||
if (content->isText()) txt += content->getUtf8Text().c_str();
|
||||
}
|
||||
} else if (fileContent->isVoiceRecording())
|
||||
//: 'Voice message received!' : message to warn the user in a notofication for voice messages.
|
||||
txt = tr("new_voice_message");
|
||||
else txt = tr("new_file_message");
|
||||
if (txt.isEmpty() && message->hasConferenceInvitationContent())
|
||||
//: 'Conference invitation received!' : Notification about receiving an invitation to a conference.
|
||||
txt = tr("new_conference_invitation");
|
||||
};
|
||||
|
||||
if (messages.size() == 1) { // Display only sender on mono message.
|
||||
if (message->isRead()) return;
|
||||
getMessage(message);
|
||||
if (txt.isEmpty()) { // Do not notify message without content
|
||||
qDebug() << "empty notif, return";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int unreadCount = 0;
|
||||
for (auto &message : messages) {
|
||||
if (!message->isRead()) {
|
||||
++unreadCount;
|
||||
if (unreadCount == 1) getMessage(message);
|
||||
}
|
||||
}
|
||||
if (unreadCount == 0) return;
|
||||
if (unreadCount > 1)
|
||||
//: 'New messages received!' Notification that warn the user of new messages.
|
||||
txt = tr("new_chat_room_messages");
|
||||
}
|
||||
|
||||
// Play noitification sound
|
||||
auto settings = SettingsModel::getInstance();
|
||||
if (settings && !settings->dndEnabled()) {
|
||||
CoreModel::getInstance()->getCore()->playLocal(
|
||||
Utils::appStringToCoreString(settings->getChatNotificationSoundPath()));
|
||||
}
|
||||
|
||||
// If chat currently displayed, do not display notification
|
||||
auto currentlyDisplayedChat = App::getInstance()->getCurrentChat();
|
||||
auto mainWin = App::getInstance()->getMainWindow();
|
||||
if (currentlyDisplayedChat && mainWin->isActive()) {
|
||||
auto linphoneCurrent = currentlyDisplayedChat->mCore->getModel()->getMonitor();
|
||||
if (linphoneCurrent->getIdentifier() == room->getIdentifier()) {
|
||||
lInfo() << log().arg("Chat is currently displayed in the view, do not show notification");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto chatCore = ChatCore::create(room);
|
||||
|
||||
App::postCoreAsync([this, txt, chatCore, remoteAddress]() {
|
||||
mustBeInMainThread(getClassName());
|
||||
|
||||
// Accessibility alert
|
||||
//: New message on chatroom %1
|
||||
AccessibilityHelper::announceMessage(tr("new_message_alert_accessible_name").arg(chatCore->getTitle()));
|
||||
|
||||
QVariantMap map;
|
||||
map["message"] = txt;
|
||||
map["remoteAddress"] = remoteAddress;
|
||||
map["chatRoomName"] = chatCore->getTitle();
|
||||
map["chatRoomAddress"] = chatCore->getChatRoomAddress();
|
||||
map["avatarUri"] = chatCore->getAvatarUri();
|
||||
map["isGroupChat"] = chatCore->isGroupChat();
|
||||
map["chat"] = QVariant::fromValue(chatCore ? new ChatGui(chatCore) : nullptr);
|
||||
CREATE_NOTIFICATION(Notifier::ReceivedMessage, map)
|
||||
});
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
||||
void Notifier::notifyReceivedReactions(
|
||||
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const linphone::ChatMessageReaction>>>
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ public:
|
|||
~Notifier();
|
||||
|
||||
enum NotificationType {
|
||||
// ReceivedMessage,
|
||||
ReceivedMessage,
|
||||
// ReceivedFileMessage,
|
||||
ReceivedCall,
|
||||
ReceivedCall
|
||||
// NewVersionAvailable,
|
||||
// SnapshotWasTaken,
|
||||
// RecordingCompleted
|
||||
|
|
@ -52,8 +52,9 @@ public:
|
|||
// void notifyReceivedCall(Call *call);
|
||||
void notifyReceivedCall(const std::shared_ptr<linphone::Call> &call); // Call from Linphone
|
||||
|
||||
void notifyReceivedMessages(const std::shared_ptr<linphone::ChatRoom> &room,
|
||||
const std::list<std::shared_ptr<linphone::ChatMessage>> &messages);
|
||||
/*
|
||||
void notifyReceivedMessages(const std::list<std::shared_ptr<linphone::ChatMessage>> &messages);
|
||||
void notifyReceivedReactions(
|
||||
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const
|
||||
linphone::ChatMessageReaction>>> &reactions); void notifyReceivedFileMessage(const
|
||||
|
|
|
|||
|
|
@ -46,12 +46,16 @@ ParticipantCore::ParticipantCore(const std::shared_ptr<linphone::Participant> &p
|
|||
mParticipantModel->moveToThread(CoreModel::getInstance()->thread());
|
||||
if (participant) {
|
||||
mAdminStatus = participant->isAdmin();
|
||||
mSipAddress = Utils::coreStringToAppString(participant->getAddress()->asStringUriOnly());
|
||||
auto participantAddress = participant->getAddress();
|
||||
mUsername = Utils::coreStringToAppString(participantAddress->getUsername());
|
||||
mSipAddress = Utils::coreStringToAppString(participantAddress->asStringUriOnly());
|
||||
mIsMe = ToolModel::isMe(mSipAddress);
|
||||
mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime());
|
||||
mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getDisplayName());
|
||||
if (mDisplayName.isEmpty())
|
||||
mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getUsername());
|
||||
mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName());
|
||||
if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participantAddress);
|
||||
auto isFriend = ToolModel::findFriendByAddress(participantAddress);
|
||||
if (isFriend && isFriend->getCore()) mSecurityLevel = LinphoneEnums::fromLinphone(isFriend->getSecurityLevel());
|
||||
else mSecurityLevel = LinphoneEnums::SecurityLevel::None;
|
||||
for (auto &device : participant->getDevices()) {
|
||||
auto name = Utils::coreStringToAppString(device->getName());
|
||||
auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
|
||||
|
|
@ -75,7 +79,7 @@ void ParticipantCore::setSelf(QSharedPointer<ParticipantCore> me) {
|
|||
connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe);
|
||||
}
|
||||
|
||||
int ParticipantCore::getSecurityLevel() const {
|
||||
LinphoneEnums::SecurityLevel ParticipantCore::getSecurityLevel() const {
|
||||
return mSecurityLevel;
|
||||
}
|
||||
|
||||
|
|
@ -121,6 +125,17 @@ QString ParticipantCore::getDisplayName() const {
|
|||
return mDisplayName;
|
||||
}
|
||||
|
||||
void ParticipantCore::setUsername(const QString &name) {
|
||||
if (mUsername != name) {
|
||||
mUsername = name;
|
||||
emit usernameChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString ParticipantCore::getUsername() const {
|
||||
return mUsername;
|
||||
}
|
||||
|
||||
QDateTime ParticipantCore::getCreationTime() const {
|
||||
return mCreationTime;
|
||||
}
|
||||
|
|
@ -153,7 +168,7 @@ void ParticipantCore::setIsFocus(const bool &focus) {
|
|||
}
|
||||
}
|
||||
|
||||
void ParticipantCore::setSecurityLevel(int level) {
|
||||
void ParticipantCore::setSecurityLevel(LinphoneEnums::SecurityLevel level) {
|
||||
if (level != mSecurityLevel) {
|
||||
mSecurityLevel = level;
|
||||
emit securityLevelChanged();
|
||||
|
|
|
|||
|
|
@ -40,11 +40,12 @@ class ParticipantCore : public QObject, public AbstractObject {
|
|||
|
||||
Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged)
|
||||
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName NOTIFY displayNameChanged)
|
||||
Q_PROPERTY(QString username READ getUsername WRITE setUsername NOTIFY usernameChanged)
|
||||
Q_PROPERTY(bool isAdmin READ isAdmin WRITE setIsAdmin NOTIFY isAdminChanged)
|
||||
Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged)
|
||||
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT)
|
||||
Q_PROPERTY(bool focus READ isFocus CONSTANT)
|
||||
Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
|
||||
Q_PROPERTY(LinphoneEnums::SecurityLevel securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
|
||||
Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged)
|
||||
Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged)
|
||||
|
||||
|
|
@ -56,11 +57,12 @@ public:
|
|||
void setSelf(QSharedPointer<ParticipantCore> me);
|
||||
|
||||
QString getDisplayName() const;
|
||||
QString getUsername() const;
|
||||
QString getSipAddress() const;
|
||||
QDateTime getCreationTime() const;
|
||||
bool isAdmin() const;
|
||||
bool isFocus() const;
|
||||
int getSecurityLevel() const;
|
||||
LinphoneEnums::SecurityLevel getSecurityLevel() const;
|
||||
int getDeviceCount() const;
|
||||
|
||||
bool isMe() const;
|
||||
|
|
@ -69,10 +71,11 @@ public:
|
|||
|
||||
void setSipAddress(const QString &address);
|
||||
void setDisplayName(const QString &name);
|
||||
void setUsername(const QString &name);
|
||||
void setCreationTime(const QDateTime &date);
|
||||
void setIsAdmin(const bool &status);
|
||||
void setIsFocus(const bool &focus);
|
||||
void setSecurityLevel(int level);
|
||||
void setSecurityLevel(LinphoneEnums::SecurityLevel level);
|
||||
|
||||
QList<QVariant> getParticipantDevices();
|
||||
|
||||
|
|
@ -92,6 +95,7 @@ signals:
|
|||
void invitingChanged();
|
||||
void creationTimeChanged();
|
||||
void displayNameChanged();
|
||||
void usernameChanged();
|
||||
|
||||
void lStartInvitation(const int &secs = 30);
|
||||
void lSetIsAdmin(bool status);
|
||||
|
|
@ -107,11 +111,12 @@ private:
|
|||
QList<QVariant> mParticipantDevices;
|
||||
|
||||
QString mDisplayName;
|
||||
QString mUsername;
|
||||
QString mSipAddress;
|
||||
QDateTime mCreationTime;
|
||||
bool mAdminStatus;
|
||||
bool mIsFocus;
|
||||
int mSecurityLevel;
|
||||
LinphoneEnums::SecurityLevel mSecurityLevel;
|
||||
bool mIsMe;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
|
|
|
|||
|
|
@ -44,12 +44,13 @@ ParticipantDeviceCore::ParticipantDeviceCore(const std::shared_ptr<linphone::Par
|
|||
mustBeInLinphoneThread(getClassName());
|
||||
if (device) {
|
||||
mName = Utils::coreStringToAppString(device->getName());
|
||||
auto deviceAddress = device->getAddress()->clone();
|
||||
auto deviceAddress = device->getAddress();
|
||||
mUniqueAddress = Utils::coreStringToAppString(deviceAddress->asString());
|
||||
mAddress = Utils::coreStringToAppString(deviceAddress->asStringUriOnly());
|
||||
// the display name of the device himself may be the uncleaned sip uri
|
||||
// Use the participant name instead
|
||||
mDisplayName = Utils::coreStringToAppString(device->getParticipant()->getAddress()->getDisplayName());
|
||||
auto participant = device->getParticipant();
|
||||
mDisplayName = Utils::coreStringToAppString(participant ? participant->getAddress()->getDisplayName() : "");
|
||||
if (mDisplayName.isEmpty()) {
|
||||
mDisplayName = ToolModel::getDisplayName(deviceAddress);
|
||||
}
|
||||
|
|
|
|||
76
Linphone/core/participant/ParticipantInfoList.cpp
Normal file
76
Linphone/core/participant/ParticipantInfoList.cpp
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2024 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 "ParticipantInfoList.hpp"
|
||||
#include "core/App.hpp"
|
||||
#include "core/chat/ChatCore.hpp"
|
||||
#include "core/participant/ParticipantGui.hpp"
|
||||
#include "tool/Utils.hpp"
|
||||
|
||||
DEFINE_ABSTRACT_OBJECT(ParticipantInfoList)
|
||||
|
||||
QSharedPointer<ParticipantInfoList> ParticipantInfoList::create() {
|
||||
auto model = QSharedPointer<ParticipantInfoList>(new ParticipantInfoList(), &QObject::deleteLater);
|
||||
model->moveToThread(App::getInstance()->thread());
|
||||
return model;
|
||||
}
|
||||
|
||||
QSharedPointer<ParticipantInfoList> ParticipantInfoList::create(const QSharedPointer<ChatCore> &chatCore) {
|
||||
auto model = create();
|
||||
model->setChatCore(chatCore);
|
||||
return model;
|
||||
}
|
||||
|
||||
ParticipantInfoList::ParticipantInfoList(QObject *parent) : ListProxy(parent) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::CppOwnership);
|
||||
}
|
||||
|
||||
ParticipantInfoList::~ParticipantInfoList() {
|
||||
mList.clear();
|
||||
}
|
||||
|
||||
void ParticipantInfoList::setChatCore(const QSharedPointer<ChatCore> &chatCore) {
|
||||
mustBeInMainThread(log().arg(Q_FUNC_INFO));
|
||||
if (mChatCore) disconnect(mChatCore.get(), &ChatCore::participantsChanged, this, nullptr);
|
||||
mChatCore = chatCore;
|
||||
lDebug() << "[ParticipantInfoList] : set Chat " << mChatCore.get();
|
||||
clearData();
|
||||
if (mChatCore) {
|
||||
auto buildList = [this] {
|
||||
QStringList participantAddresses;
|
||||
QList<QSharedPointer<ParticipantGui>> participantList;
|
||||
auto participants = mChatCore->getParticipants();
|
||||
resetData();
|
||||
for (auto p : participants)
|
||||
add(p);
|
||||
};
|
||||
connect(mChatCore.get(), &ChatCore::participantsChanged, this, buildList);
|
||||
buildList();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant ParticipantInfoList::data(const QModelIndex &index, int role) const {
|
||||
int row = index.row();
|
||||
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant::fromValue(new ParticipantGui(mList[row].objectCast<ParticipantCore>()));
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue