Compare commits

..

8 commits

Author SHA1 Message Date
Sylvain Berfini
de99f1f69a Updated SDK 2025-05-16 09:48:14 +02:00
Gaelle Braud
6b02ebed39 update sdk 2025-05-14 10:06:47 +02:00
Gaelle Braud
490f5cdca1 fix #LINQT-1657 do not manipulate internal gains 2025-05-14 10:06:07 +02:00
Peio Rigaux
fb786c2a9d Fix windows signature return code, as we are using Invoke-Expression, and makes sure that this job doesn't prevent upload even when it fails 2025-05-13 18:04:32 +02:00
Gaelle Braud
23e32d1953 docker update : ubuntu 22.04, qt6.9.0
update gitlab ci file
2025-05-13 15:47:48 +02:00
Gaelle Braud
d025aaaeec changelog 2025-05-07 10:50:08 +02:00
Christophe Deschamps
faeed359fb German translations 2025-05-05 08:23:02 +00:00
Jehan Monnier
1e82f48839 Fix basic auth mode for oidc.
Make sure refresh token is optionnal
2025-04-30 13:14:19 +02:00
3871 changed files with 14328 additions and 175183 deletions

9
.gitignore vendored
View file

@ -52,12 +52,3 @@ linphone.spec
# VSCode # VSCode
linphone60*.log linphone60*.log
linphone61*.log linphone61*.log
linphone62*.log
# QT Creator
*.cflags
*.config
*.creator
*.cxxflags
*.files
*.includes

View file

@ -0,0 +1,171 @@
.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/

View file

@ -1,5 +1,5 @@
.factorize_ubuntu2204: &docker_image_platform_and_runner_tag .factorize_ubuntu2204: &docker_image_platform_and_runner_tag
tags: [ "docker-flat" ] tags: [ "docker" ]
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
ubuntu2204-ninja-gcc: ubuntu2204-ninja-gcc:
@ -36,7 +36,7 @@ ubuntu2204-ninja-clang:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $NIGHTLY_MASTER - if: $NIGHTLY_MASTER
variables: variables:
CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF CMAKE_OPTIONS: -DENABLE_DOC=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
CMAKE_GENERATOR: Ninja CMAKE_GENERATOR: Ninja
CC: clang CC: clang
CXX: clang++ CXX: clang++
@ -53,17 +53,41 @@ ubuntu2204-ninja-clang-small:
allow_failure: true allow_failure: true
extends: ubuntu2204-ninja-clang extends: ubuntu2204-ninja-clang
ubuntu2204-makefile-gcc-signed: ubuntu2204-makefile-gcc:
rules: rules:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $NIGHTLY_MASTER - if: $NIGHTLY_MASTER
- if: $DEPLOY_PLUGINS - if: $DEPLOY_PLUGINS
variables: 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 CMAKE_GENERATOR: Unix Makefiles
CC: gcc CC: gcc
CXX: g++ CXX: g++
ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS ADDITIONAL_BUILD_OPTIONS: -j$MAKEFILE_JOBS
extends: .linux-sign-build 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 <<: *docker_image_platform_and_runner_tag
################################################# #################################################
@ -71,41 +95,77 @@ ubuntu2204-makefile-gcc-signed:
################################################# #################################################
ubuntu2204-makefile-gcc-package: ubuntu2204-makefile-gcc-package:
tags: [ "docker-flat" ] stage: package
tags: [ "docker" ]
image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION image: gitlab.linphone.org:4567/bc/public/linphone-desktop/bc-dev-ubuntu-22-04-lts:$UBUNTU_2204_IMAGE_VERSION
needs: [] dependencies: []
rules: rules:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $NIGHTLY_MASTER - if: $NIGHTLY_MASTER
- if: $PACKAGE_LINUX - if: $PACKAGE_LINUX
- if: $DEPLOY_LINUX - if: $DEPLOY_LINUX
variables: 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 CMAKE_GENERATOR: Unix Makefiles
CC: gcc CC: gcc
CXX: g++ CXX: g++
extends: .linux-sign-package 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 # Deploy - Nightly
################################################# #################################################
ubuntu2204-makefile-gcc-deploy: ubuntu2204-makefile-gcc-deploy:
extends: .linux-deploy stage: deploy
needs: tags: [ "deploy" ]
- ubuntu2204-makefile-gcc-package needs:
only: - ubuntu2204-makefile-gcc-package
only:
variables: variables:
- $NIGHTLY_MASTER - $NIGHTLY_MASTER
- $DEPLOY_LINUX - $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: ubuntu2204-makefile-gcc-plugins-deploy:
stage: deploy stage: deploy
tags: [ "deploy-flat" ] tags: [ "deploy" ]
needs: needs:
- ubuntu2204-makefile-gcc - ubuntu2204-makefile-gcc
only: only:
variables: variables:
- $DEPLOY_PLUGINS - $DEPLOY_PLUGINS
script: script:
- rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/ - rsync -rlv --ignore-existing build/OUTPUT/plugins/app/*.so $DEPLOY_SERVER:$UPLOAD_ROOT_PATH/$LINUX_PLATFORM/$APP_FOLDER/plugins/

View file

@ -2,7 +2,7 @@
# BUILD # BUILD
################################################# #################################################
.common_linux: &common_linux | .build_all_linux_script: &build_all_linux_script |
cmake --version cmake --version
export CC=$CC export CC=$CC
export CXX=$CXX export CXX=$CXX
@ -11,68 +11,20 @@
echo $CMAKE_GENERATOR echo $CMAKE_GENERATOR
echo $DEFAULT_LINUX_CMAKE_OPTIONS echo $DEFAULT_LINUX_CMAKE_OPTIONS
echo $CMAKE_SANITIZER_OPTIONS echo $CMAKE_SANITIZER_OPTIONS
eval "$(qtchooser -qt=$QT_LINUX_VER-${QT_OPEN_SOURCE_DIRECTORY:-proprietary} -print-env)" cd build
eval "$(qtchooser -qt=$QT_LINUX_VER -print-env)"
export PATH=${QTTOOLDIR}:$PATH export PATH=${QTTOOLDIR}:$PATH
export Qt6_DIR=${QTLIBDIR}/cmake/Qt6 export Qt6_DIR=${QTLIBDIR}/cmake/Qt6
echo "Using Qt $QT_LINUX_VER at ${QTLIBDIR}" 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 .. -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 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: .linux-desktop:
stage: build stage: build
extends: .linux-prepare extends: .linux-prepare
script: script:
- *common_linux
- *build_all_linux_script - *build_all_linux_script
artifacts: artifacts:
paths: paths:
- build/OUTPUT - build/OUTPUT
expire_in: 1 week 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

View file

@ -26,7 +26,7 @@
.macosx-desktop: .macosx-desktop:
stage: build stage: build
tags: [ "macmini-m1-xcode15-flat" ] tags: [ "macos-min-xcode12.2" ]
rules: rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
- if: $CI_PIPELINE_SOURCE == "schedule" && $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 # WAIT for QT6 for arm64
macosx-ninja-package: macosx-ninja-package:
stage: package stage: package
tags: [ "macmini-m1-xcode15-flat" ] tags: [ "macos-min-xcode12.2" ]
needs: [] dependencies: []
rules: rules:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null - if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_MACOSX == null
@ -102,7 +102,7 @@ macosx-ninja-package:
- if: $PACKAGE_MACOSX - if: $PACKAGE_MACOSX
- if: $DEPLOY_MACOSX - if: $DEPLOY_MACOSX
variables: variables:
CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=OFF -DENABLE_G729=ON CMAKE_OPTIONS: -DPython3_ROOT_DIR=/opt/bc/pip-packages/ -DENABLE_APP_PACKAGING=ON -DENABLE_GPL_THIRD_PARTIES=ON -DENABLE_G729=ON
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$MACOSX_PLATFORM/$APP_FOLDER RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$MACOSX_PLATFORM/$APP_FOLDER
extends: macosx-ninja extends: macosx-ninja
script: script:
@ -117,7 +117,7 @@ macosx-ninja-package:
macosx-codesigning: macosx-codesigning:
stage: signing stage: signing
tags: [ "macmini-m1-xcode15-flat" ] tags: [ "macos-min-xcode12.2" ]
needs: needs:
- macosx-ninja-package - macosx-ninja-package
rules: rules:
@ -142,7 +142,7 @@ macosx-codesigning:
macosx-deploy: macosx-deploy:
stage: deploy stage: deploy
tags: [ "macmini-m1-xcode15-flat" ] tags: [ "macos-min-xcode12.2" ]
needs: needs:
- macosx-codesigning - macosx-codesigning
only: only:
@ -160,7 +160,7 @@ macosx-deploy:
macosx-makefile-plugins-deploy: macosx-makefile-plugins-deploy:
stage: deploy stage: deploy
tags: [ "macmini-m1-xcode15-flat" ] tags: [ "macos-min-xcode12.2" ]
needs: needs:
- macosx-makefile - macosx-makefile
only: only:

View file

@ -9,7 +9,7 @@
- if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null - if: $CI_PIPELINE_SOURCE == "merge_request_event" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null
- if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null - if: $CI_PIPELINE_SOURCE == "schedule" && $DOCKER_UPDATE == null && $SKIP_WINDOWS == null
variables: variables:
CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF CMAKE_OPTIONS: -DENABLE_UNIT_TESTS=ON -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
LINPHONESDK_PLATFORM: Desktop LINPHONESDK_PLATFORM: Desktop
OUTPUT_ZIP_FOLDER: win64 OUTPUT_ZIP_FOLDER: win64
MINGW_TYPE: mingw64 MINGW_TYPE: mingw64
@ -92,11 +92,11 @@
.windows-vs2022: .windows-vs2022:
extends: .windows-vs extends: .windows-vs
tags: [ "windows-powershell-vs-17-2022-flat" ] tags: [ "windows-powershell-vs-17-2022" ]
.windows-codesigning: .windows-codesigning:
extends: .prepare extends: .prepare
tags: [ "windows-powershell-vs-17-2022-apps-flat" ] tags: [ "windows-powershell-vs-17-2022-apps" ]
.windows-msbuild-variables: .windows-msbuild-variables:
variables: variables:
@ -177,7 +177,7 @@ win64-ninja-vs2022-scheduled-windows:
.vs-win64-package: .vs-win64-package:
stage: package stage: package
needs: [] dependencies: []
rules: rules:
- !reference [.rules-merge-request-manual, rules] - !reference [.rules-merge-request-manual, rules]
- if: $NIGHTLY_MASTER - if: $NIGHTLY_MASTER
@ -185,7 +185,7 @@ win64-ninja-vs2022-scheduled-windows:
- if: $PACKAGE_WINDOWS - if: $PACKAGE_WINDOWS
- if: $DEPLOY_WINDOWS - if: $DEPLOY_WINDOWS
variables: variables:
CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=OFF CMAKE_OPTIONS: -DENABLE_APP_PACKAGING=YES -DENABLE_G729=ON -DENABLE_PQCRYPTO=ON -DENABLE_GPL_THIRD_PARTIES=ON
RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER RELEASE_FILE: -DLINPHONE_SDK_MAKE_RELEASE_FILE_URL=$MAKE_RELEASE_FILE_URL/$WINDOWS_PLATFORM/$APP_FOLDER
win64-ninja-vs2022-package-windows: win64-ninja-vs2022-package-windows:
@ -232,15 +232,15 @@ win64-codesigning:
.win64-upload: .win64-upload:
stage: deploy stage: deploy
tags: [ "windows-powershell-flat" ] tags: [ "windows-powershell" ]
rules: rules:
- if: $NIGHTLY_MASTER - if: $NIGHTLY_MASTER
- if: $DEPLOY_WINDOWS - if: $DEPLOY_WINDOWS
script: script:
- rsync --perms --chmod=Fu=rw,Fg=r,Fo=r build-desktop/OUTPUT/Packages/*.exe ${DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/${APP_FOLDER} - scp -pr 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) { scp -pr 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}/ } - if ($MAKE_RELEASE_FILE_URL) { scp -pr build-desktop/OUTPUT/Packages/RELEASE ${MAIN_DEPLOY_SERVER}:${UPLOAD_ROOT_PATH}/${WINDOWS_PLATFORM}/ }
win64-ninja-vs2022-upload: win64-ninja-vs2022-upload:
extends: extends:
@ -250,7 +250,7 @@ win64-ninja-vs2022-upload:
.win64-plugins-upload: .win64-plugins-upload:
stage: deploy stage: deploy
tags: [ "windows-flat" ] tags: [ "windows" ]
rules: rules:
- if: $DEPLOY_PLUGINS - if: $DEPLOY_PLUGINS
script: script:

View file

@ -21,7 +21,13 @@ variables:
#CMAKE_OPTIONS: -DENABLE_LIME_X3DH=YES #CMAKE_OPTIONS: -DENABLE_LIME_X3DH=YES
# Docker image version # Docker image version
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 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
workflow: workflow:
@ -45,6 +51,7 @@ include:
- '.gitlab-ci-files/rules.yml' - '.gitlab-ci-files/rules.yml'
- '.gitlab-ci-files/linux-prepare.yml' - '.gitlab-ci-files/linux-prepare.yml'
- '.gitlab-ci-files/linux-desktop.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/linux-desktop-ubuntu-2204.yml'
- '.gitlab-ci-files/windows-desktop.yml' - '.gitlab-ci-files/windows-desktop.yml'
- '.gitlab-ci-files/macosx-desktop.yml' - '.gitlab-ci-files/macosx-desktop.yml'

View file

@ -31,9 +31,3 @@ 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. - 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 - Minimum supported Qt version is now 6.5.3
- Some settings have changed name and/or section in linphonerc file. - 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

View file

@ -60,6 +60,7 @@ project(linphoneqt)
include(GNUInstallDirs) include(GNUInstallDirs)
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
include(Linphone/application_info.cmake)
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 17)
if(LINPHONEAPP_INSTALL_PREFIX) if(LINPHONEAPP_INSTALL_PREFIX)
@ -71,11 +72,8 @@ endif()
set(CMAKE_INSTALL_PREFIX "${APPLICATION_OUTPUT_DIR}") set(CMAKE_INSTALL_PREFIX "${APPLICATION_OUTPUT_DIR}")
set(LINPHONEAPP_APPLICATION_NAME "Linphone" CACHE STRING "Application name" ) set(LINPHONEAPP_APPLICATION_NAME "Linphone6" CACHE STRING "Application name" )
set(LINPHONEAPP_EXECUTABLE_NAME "linphone" CACHE STRING "Executable name" ) set(LINPHONEAPP_EXECUTABLE_NAME "linphone6" 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 ) if( APPLE )
set(LINPHONEAPP_MACOS_ARCHS "arm64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]") set(LINPHONEAPP_MACOS_ARCHS "arm64" CACHE STRING "MacOS architectures to build: comma-separated list of values in [arm64, x86_64]")
@ -165,7 +163,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_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_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_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." OFF) add_option(OPTION_LIST ENABLE_QT_KEYCHAIN "Build QtKeychain to manage VFS from System key stores." ON)
add_option(OPTION_LIST ENABLE_QRCODE "Enable QRCode support" OFF)#Experimental 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_RELATIVE_PREFIX "Set Internal packages relative to the binary" ON)
add_option(OPTION_LIST ENABLE_SANITIZER "Enable sanitizer." OFF) add_option(OPTION_LIST ENABLE_SANITIZER "Enable sanitizer." OFF)
@ -187,9 +185,9 @@ add_option(OPTION_LIST ENABLE_SCREENSHARING "Enable screen sharing." ${ENABLE_VI
# QtKeychain # QtKeychain
add_option(OPTION_LIST LIBSECRET_SUPPORT "Build with libsecret support" OFF) # Need libsecret-devel add_option(OPTION_LIST LIBSECRET_SUPPORT "Build with libsecret support" OFF) # Need libsecret-devel
if(WIN32) if(WIN32)
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt6Keychain library name for a workaround with windeployqt" "EQt6Keychain") add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt5Keychain library name for a workaround with windeployqt" "EQt5Keychain")
else() else()
add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt6Keychain library name" "Qt6Keychain") add_cache(OPTION_LIST QTKEYCHAIN_TARGET_NAME "Override Qt5Keychain library name" "Qt5Keychain")
endif() endif()
if(WIN32) if(WIN32)
add_option(OPTION_LIST ENABLE_OPENSSL_EXPORT "Enable OpenSSL deployment" YES) add_option(OPTION_LIST ENABLE_OPENSSL_EXPORT "Enable OpenSSL deployment" YES)
@ -208,7 +206,7 @@ set(ENABLE_CSHARP_WRAPPER OFF CACHE BOOL "Build the CSharp wrapper for Liblinpho
set(ENABLE_THEORA OFF) set(ENABLE_THEORA OFF)
set(ENABLE_QT_GL ${ENABLE_VIDEO}) set(ENABLE_QT_GL ${ENABLE_VIDEO})
find_package(Qt6 REQUIRED COMPONENTS Core Quick Widgets) find_package(Qt6 REQUIRED COMPONENTS Core)
if(NOT Qt6_FOUND) if(NOT Qt6_FOUND)
message(FATAL_ERROR "Minimum supported Qt6!") message(FATAL_ERROR "Minimum supported Qt6!")
@ -229,11 +227,18 @@ endif()
if(NOT APPLE OR MONO_ARCH) if(NOT APPLE OR MONO_ARCH)
add_custom_target(linphone-deps) add_custom_target(linphone-deps)
if(NOT LINPHONE_QT_ONLY) if(NOT LINPHONE_QT_ONLY)
function(add_external) function(add_external)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here
add_subdirectory("external") add_subdirectory("external")
endfunction() endfunction()
add_external() add_external()
if(ENABLE_QT_KEYCHAIN)
function(add_linphone_keychain)
#add_subdirectory("external/qtkeychain")
endfunction()
add_linphone_keychain()
endif()
endif() endif()
function(add_linphone_app) function(add_linphone_app)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) # Prevent project from overriding the options we just set here
@ -265,16 +270,4 @@ else()
include(cmake/TasksMacos.cmake) include(cmake/TasksMacos.cmake)
endif() 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/") file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/cmake/hook/pre-commit" DESTINATION "${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/")

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16) cmake_minimum_required(VERSION 3.16)
project(Linphone VERSION 6.2.0 LANGUAGES CXX) project(Linphone VERSION 6.0.0 LANGUAGES CXX)
################################################################ ################################################################
# PACKAGES # PACKAGES
@ -19,10 +19,10 @@ endforeach()
set(TARGET_NAME Linphone) set(TARGET_NAME Linphone)
set(APP_TARGETS ${LinphoneCxx_TARGET} set(APP_TARGETS ${LinphoneCxx_TARGET}
${Mediastreamer2_TARGET}#MediastreamerUtils ${Mediastreamer2_TARGET}#MediastreamerUtils
${LibLinphone_TARGET})#Liblinphone ${LibLinphone_TARGET})#MediastreamerUtils
set(QT_DEFAULT_MAJOR_VERSION 6) set(QT_DEFAULT_MAJOR_VERSION 6)
set(QT_PACKAGES Quick Qml Widgets Svg Multimedia Test NetworkAuth Concurrent)# Search Core at first for initialize Qt scripts for next find_packages. set(QT_PACKAGES Core 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) if (UNIX AND NOT APPLE)
list(APPEND QT_PACKAGES DBus) list(APPEND QT_PACKAGES DBus)
endif() endif()
@ -98,11 +98,15 @@ endif()
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/config.h")
if(${Qt6_VERSION} VERSION_LESS "6.10.0") if(${Qt6_VERSION} VERSION_LESS "6.3.0")
message( FATAL_ERROR "Linphone requires Qt 6.10.0 or newer. Exiting CMake." ) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
else()
qt6_standard_project_setup()
endif() endif()
qt6_standard_project_setup()
################################################################ ################################################################
@ -123,7 +127,7 @@ add_subdirectory(core)
set(LANGUAGES_DIRECTORY "data/languages") set(LANGUAGES_DIRECTORY "data/languages")
set(I18N_FILENAME i18n.qrc) set(I18N_FILENAME i18n.qrc)
set(LANGUAGES en fr de) set(LANGUAGES en fr_FR de)
# Add languages support. # Add languages support.
add_subdirectory("${LANGUAGES_DIRECTORY}" "data/languages") add_subdirectory("${LANGUAGES_DIRECTORY}" "data/languages")
@ -170,12 +174,6 @@ qt6_add_qml_module(Linphone
RESOURCES data/fonts.qrc 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}) qt6_add_resources(Linphone "resources" PREFIX "/" FILES ${_LINPHONEAPP_RC_FILES})
set_property(TARGET Linphone PROPERTY POSITION_INDEPENDENT_CODE ON) #Need by Qt set_property(TARGET Linphone PROPERTY POSITION_INDEPENDENT_CODE ON) #Need by Qt
@ -201,7 +199,6 @@ set_target_properties(${TARGET_NAME} PROPERTIES
if(MSVC) if(MSVC)
set_target_properties(${TARGET_NAME} PROPERTIES PDB_NAME "${EXECUTABLE_NAME}_app") set_target_properties(${TARGET_NAME} PROPERTIES PDB_NAME "${EXECUTABLE_NAME}_app")
endif() endif()
set_target_properties(${TARGET_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(WIN32) if(WIN32)
if(ENABLE_SCREENSHARING) if(ENABLE_SCREENSHARING)
@ -217,7 +214,6 @@ foreach(T ${APP_TARGETS})
target_link_libraries(${TARGET_NAME} PUBLIC ${T}) target_link_libraries(${TARGET_NAME} PUBLIC ${T})
endforeach() endforeach()
target_link_libraries(${TARGET_NAME} PRIVATE Qt6::Core)
foreach(T ${QT_PACKAGES}) foreach(T ${QT_PACKAGES})
target_link_libraries(${TARGET_NAME} PRIVATE Qt6::${T}) target_link_libraries(${TARGET_NAME} PRIVATE Qt6::${T})
endforeach() endforeach()

View file

@ -22,6 +22,7 @@
#include "App.hpp" #include "App.hpp"
#include <QAction>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDirIterator> #include <QDirIterator>
#include <QFileSelector> #include <QFileSelector>
@ -52,19 +53,9 @@
#include "core/call/CallList.hpp" #include "core/call/CallList.hpp"
#include "core/call/CallProxy.hpp" #include "core/call/CallProxy.hpp"
#include "core/camera/CameraGui.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/ConferenceGui.hpp"
#include "core/conference/ConferenceInfoGui.hpp" #include "core/conference/ConferenceInfoGui.hpp"
#include "core/conference/ConferenceInfoProxy.hpp" #include "core/conference/ConferenceInfoProxy.hpp"
#include "core/emoji/EmojiProxy.hpp"
#include "core/fps-counter/FPSCounter.hpp" #include "core/fps-counter/FPSCounter.hpp"
#include "core/friend/FriendCore.hpp" #include "core/friend/FriendCore.hpp"
#include "core/friend/FriendGui.hpp" #include "core/friend/FriendGui.hpp"
@ -73,50 +64,34 @@
#include "core/notifier/Notifier.hpp" #include "core/notifier/Notifier.hpp"
#include "core/participant/ParticipantDeviceProxy.hpp" #include "core/participant/ParticipantDeviceProxy.hpp"
#include "core/participant/ParticipantGui.hpp" #include "core/participant/ParticipantGui.hpp"
#include "core/participant/ParticipantInfoProxy.hpp"
#include "core/participant/ParticipantProxy.hpp" #include "core/participant/ParticipantProxy.hpp"
#include "core/payload-type/PayloadTypeCore.hpp" #include "core/payload-type/PayloadTypeCore.hpp"
#include "core/payload-type/PayloadTypeGui.hpp" #include "core/payload-type/PayloadTypeGui.hpp"
#include "core/payload-type/PayloadTypeProxy.hpp" #include "core/payload-type/PayloadTypeProxy.hpp"
#include "core/phone-number/PhoneNumber.hpp" #include "core/phone-number/PhoneNumber.hpp"
#include "core/phone-number/PhoneNumberProxy.hpp" #include "core/phone-number/PhoneNumberProxy.hpp"
#include "core/recorder/RecorderGui.hpp"
#include "core/register/RegisterPage.hpp" #include "core/register/RegisterPage.hpp"
#include "core/screen/ScreenList.hpp" #include "core/screen/ScreenList.hpp"
#include "core/screen/ScreenProxy.hpp" #include "core/screen/ScreenProxy.hpp"
#include "core/search/MagicSearchProxy.hpp" #include "core/search/MagicSearchProxy.hpp"
#include "core/setting/SettingsCore.hpp" #include "core/setting/SettingsCore.hpp"
#include "core/singleapplication/singleapplication.h" #include "core/singleapplication/singleapplication.h"
#include "core/sound-player/SoundPlayerGui.hpp"
#include "core/timezone/TimeZoneProxy.hpp" #include "core/timezone/TimeZoneProxy.hpp"
#include "core/translator/DefaultTranslatorCore.hpp" #include "core/translator/DefaultTranslatorCore.hpp"
#include "core/variant/VariantList.hpp" #include "core/variant/VariantList.hpp"
#include "core/videoSource/VideoSourceDescriptorGui.hpp" #include "core/videoSource/VideoSourceDescriptorGui.hpp"
#include "model/friend/FriendsManager.hpp"
#include "model/object/VariantObject.hpp" #include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp" #include "model/tool/ToolModel.hpp"
#include "tool/Constants.hpp" #include "tool/Constants.hpp"
#include "tool/EnumsToString.hpp" #include "tool/EnumsToString.hpp"
#include "tool/Utils.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/native/DesktopTools.hpp"
#include "tool/providers/AvatarProvider.hpp" #include "tool/providers/AvatarProvider.hpp"
#include "tool/providers/EmojiProvider.hpp"
#include "tool/providers/ImageProvider.hpp" #include "tool/providers/ImageProvider.hpp"
#include "tool/providers/ScreenProvider.hpp" #include "tool/providers/ScreenProvider.hpp"
#include "tool/providers/ThumbnailProvider.hpp"
#include "tool/request/CallbackHelper.hpp" #include "tool/request/CallbackHelper.hpp"
#include "tool/request/RequestDialog.hpp" #include "tool/request/RequestDialog.hpp"
#include "tool/thread/Thread.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) DEFINE_ABSTRACT_OBJECT(App)
@ -267,7 +242,9 @@ void App::setAutoStart(bool enabled) {
void App::setAutoStart(bool enabled) { void App::setAutoStart(bool enabled) {
QSettings settings(AutoStartSettingsFilePath, QSettings::NativeFormat); QSettings settings(AutoStartSettingsFilePath, QSettings::NativeFormat);
if (enabled) settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath())); QString parameters;
if (!mSettings->getExitOnClose()) parameters = " --minimized";
if (enabled) settings.setValue(EXECUTABLE_NAME, QDir::toNativeSeparators(applicationFilePath()) + parameters);
else settings.remove(EXECUTABLE_NAME); else settings.remove(EXECUTABLE_NAME);
mAutoStart = enabled; mAutoStart = enabled;
@ -282,14 +259,10 @@ void App::setAutoStart(bool enabled) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
App::App(int &argc, char *argv[]) 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. // Do not use APPLICATION_NAME here.
// The EXECUTABLE_NAME will be used in qt standard paths. It's our goal. // 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); QThread::currentThread()->setPriority(QThread::HighPriority);
qDebug() << "app thread is" << QThread::currentThread();
lDebug() << "Starting app with Qt version" << qVersion();
QCoreApplication::setApplicationName(EXECUTABLE_NAME); QCoreApplication::setApplicationName(EXECUTABLE_NAME);
QApplication::setOrganizationDomain(EXECUTABLE_NAME); QApplication::setOrganizationDomain(EXECUTABLE_NAME);
QCoreApplication::setApplicationVersion(APPLICATION_SEMVER); QCoreApplication::setApplicationVersion(APPLICATION_SEMVER);
@ -306,7 +279,7 @@ App::App(int &argc, char *argv[])
.arg(applicationVersion()) .arg(applicationVersion())
.arg(Utils::getOsProduct()) .arg(Utils::getOsProduct())
.arg(qVersion()); .arg(qVersion());
lInfo() << "at " << QDir().absolutePath();
mCurrentDate = QDate::currentDate(); mCurrentDate = QDate::currentDate();
mAutoStart = autoStartEnabled(); mAutoStart = autoStartEnabled();
mDateUpdateTimer.setInterval(60000); mDateUpdateTimer.setInterval(60000);
@ -318,12 +291,7 @@ App::App(int &argc, char *argv[])
emit currentDateChanged(); emit currentDateChanged();
} }
}); });
mEventCountNotifier = new EventCountNotifier(this);
mDateUpdateTimer.start(); mDateUpdateTimer.start();
#ifdef Q_OS_LINUX
exportDesktopFile();
#endif
} }
App::~App() { App::~App() {
@ -337,7 +305,7 @@ void App::setSelf(QSharedPointer<App>(me)) {
auto callCore = CallCore::create(call); auto callCore = CallCore::create(call);
mCoreModelConnection->invokeToCore([this, callCore] { mCoreModelConnection->invokeToCore([this, callCore] {
auto callGui = new CallGui(callCore); auto callGui = new CallGui(callCore);
auto win = getOrCreateCallsWindow(QVariant::fromValue(callGui)); auto win = getCallsWindow(QVariant::fromValue(callGui));
Utils::smartShowWindow(win); Utils::smartShowWindow(win);
auto mainwin = getMainWindow(); auto mainwin = getMainWindow();
QMetaObject::invokeMethod(mainwin, "callCreated"); QMetaObject::invokeMethod(mainwin, "callCreated");
@ -381,106 +349,21 @@ void App::setSelf(QSharedPointer<App>(me)) {
} }
}); });
mCoreModelConnection->makeConnectToModel(&CoreModel::authenticationRequested, &App::onAuthenticationRequested); 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. // Synchronize state for because linphoneCore was ran before any connections.
mCoreModelConnection->invokeToModel([this]() { mCoreModelConnection->invokeToModel([this]() {
auto state = CoreModel::getInstance()->getCore()->getGlobalState(); auto state = CoreModel::getInstance()->getCore()->getGlobalState();
mCoreModelConnection->invokeToCore([this, state] { setCoreStarted(state == linphone::GlobalState::On); }); 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 = SafeConnection<App, CliModel>::create(me, CliModel::getInstance());
mCliModelConnection->makeConnectToCore(&App::receivedMessage, [this](int, const QByteArray &byteArray) { mCliModelConnection->makeConnectToCore(&App::receivedMessage, [this](int, const QByteArray &byteArray) {
QString command(byteArray); QString command(byteArray);
if (command.isEmpty()) { if (command.isEmpty()) {
lInfo() << log().arg("Check with CliModel for commands"); lDebug() << log().arg("Check with CliModel for commands");
mCliModelConnection->invokeToModel([]() { CliModel::getInstance()->runProcess(); }); mCliModelConnection->invokeToModel([]() { CliModel::getInstance()->runProcess(); });
} else { } else {
lInfo() << log().arg("Received command from other application: `%1`.").arg(command); qInfo() << QStringLiteral("Received command from other application: `%1`.").arg(command);
mCliModelConnection->invokeToModel([command]() { CliModel::getInstance()->executeCommand(command); }); mCliModelConnection->invokeToModel([command]() { CliModel::getInstance()->executeCommand(command); });
} }
}); });
@ -493,22 +376,13 @@ App *App::getInstance() {
return dynamic_cast<App *>(QApplication::instance()); return dynamic_cast<App *>(QApplication::instance());
} }
Thread *App::getLinphoneThread() { QThread *App::getLinphoneThread() {
return App::getInstance()->mLinphoneThread; return App::getInstance()->mLinphoneThread;
} }
Notifier *App::getNotifier() const { Notifier *App::getNotifier() const {
return mNotifier; return mNotifier;
} }
EventCountNotifier *App::getEventCountNotifier() {
return mEventCountNotifier;
}
int App::getEventCount() const {
return mEventCountNotifier ? mEventCountNotifier->getEventCount() : 0;
}
//----------------------------------------------------------- //-----------------------------------------------------------
// Initializations // Initializations
//----------------------------------------------------------- //-----------------------------------------------------------
@ -548,12 +422,10 @@ void App::init() {
} }
void App::initCore() { void App::initCore() {
mustBeInMainThread(log().arg(Q_FUNC_INFO));
// Core. Manage the logger so it must be instantiate at first. // Core. Manage the logger so it must be instantiate at first.
CoreModel::create("", mLinphoneThread); CoreModel::create("", mLinphoneThread);
if (mParser->isSet("verbose")) QtLogger::enableVerbose(true); if (mParser->isSet("verbose")) QtLogger::enableVerbose(true);
if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true); if (mParser->isSet("qt-logs-only")) QtLogger::enableQtOnly(true);
qDebug() << "linphone thread is" << mLinphoneThread;
QMetaObject::invokeMethod( QMetaObject::invokeMethod(
mLinphoneThread->getThreadId(), mLinphoneThread->getThreadId(),
[this, settings = mSettings]() mutable { [this, settings = mSettings]() mutable {
@ -611,12 +483,10 @@ void App::initCore() {
initCppInterfaces(); initCppInterfaces();
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider()); mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
mEngine->addImageProvider(EmojiProvider::ProviderId, new EmojiProvider());
mEngine->addImageProvider(AvatarProvider::ProviderId, new AvatarProvider()); mEngine->addImageProvider(AvatarProvider::ProviderId, new AvatarProvider());
mEngine->addImageProvider(ScreenProvider::ProviderId, new ScreenProvider()); mEngine->addImageProvider(ScreenProvider::ProviderId, new ScreenProvider());
mEngine->addImageProvider(WindowProvider::ProviderId, new WindowProvider()); mEngine->addImageProvider(WindowProvider::ProviderId, new WindowProvider());
mEngine->addImageProvider(WindowIconProvider::ProviderId, new WindowIconProvider()); mEngine->addImageProvider(WindowIconProvider::ProviderId, new WindowIconProvider());
mEngine->addImageProvider(ThumbnailProvider::ProviderId, new ThumbnailProvider());
// Enable notifications. // Enable notifications.
mNotifier = new Notifier(mEngine); mNotifier = new Notifier(mEngine);
@ -627,14 +497,6 @@ void App::initCore() {
mAccountList->setInitialized(false); mAccountList->setInitialized(false);
mAccountList->lUpdate(true); 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()); if (!mCallList) setCallList(CallList::create());
else mCallList->lUpdate(); else mCallList->lUpdate();
if (!mSettings) { if (!mSettings) {
@ -660,7 +522,7 @@ void App::initCore() {
setLocale(settings->getConfigLocale()); setLocale(settings->getConfigLocale());
setAutoStart(settings->getAutoStart()); setAutoStart(settings->getAutoStart());
setQuitOnLastWindowClosed(settings->getExitOnClose()); setQuitOnLastWindowClosed(settings->getExitOnClose());
} }
const QUrl url("qrc:/qt/qml/Linphone/view/Page/Window/Main/MainWindow.qml"); const QUrl url("qrc:/qt/qml/Linphone/view/Page/Window/Main/MainWindow.qml");
QObject::connect( QObject::connect(
mEngine, &QQmlApplicationEngine::objectCreated, this, mEngine, &QQmlApplicationEngine::objectCreated, this,
@ -672,45 +534,18 @@ void App::initCore() {
} }
auto window = qobject_cast<QQuickWindow *>(obj); auto window = qobject_cast<QQuickWindow *>(obj);
setMainWindow(window); setMainWindow(window);
#if defined(__APPLE__) #ifndef __APPLE__
setMacOSDockActions();
#else
// Enable TrayIconSystem. // Enable TrayIconSystem.
if (!QSystemTrayIcon::isSystemTrayAvailable()) if (!QSystemTrayIcon::isSystemTrayAvailable())
qWarning("System tray not found on this system."); qWarning("System tray not found on this system.");
else setSysTrayIcon(); else setSysTrayIcon();
#endif // if defined(__APPLE__) #endif // ifndef __APPLE__
static bool firstOpen = true; static bool firstOpen = true;
if (!firstOpen || !mParser->isSet("minimized")) { if (!firstOpen || !mParser->isSet("minimized")) {
lDebug() << log().arg("Openning window"); lDebug() << log().arg("Openning window");
if (window) window->show(); window->show();
} else lInfo() << log().arg("Stay minimized"); } else lInfo() << log().arg("Stay minimized");
firstOpen = false; 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); Qt::QueuedConnection);
@ -722,6 +557,7 @@ void App::initCore() {
} }
static inline bool installLocale(App &app, QTranslator &translator, const QLocale &locale) { static inline bool installLocale(App &app, QTranslator &translator, const QLocale &locale) {
auto appPath = QStandardPaths::ApplicationsLocation;
bool ok = translator.load(locale.name(), Constants::LanguagePath); bool ok = translator.load(locale.name(), Constants::LanguagePath);
ok = ok && app.installTranslator(&translator); ok = ok && app.installTranslator(&translator);
if (ok) QLocale::setDefault(locale); if (ok) QLocale::setDefault(locale);
@ -729,6 +565,7 @@ static inline bool installLocale(App &app, QTranslator &translator, const QLocal
} }
void App::initLocale() { void App::initLocale() {
// Try to use preferred locale. // Try to use preferred locale.
QString locale; QString locale;
@ -736,28 +573,28 @@ void App::initLocale() {
mLocale = QLocale(QLocale::English); mLocale = QLocale(QLocale::English);
if (!installLocale(*this, *mDefaultTranslatorCore, mLocale)) qFatal("Unable to install default translator."); if (!installLocale(*this, *mDefaultTranslatorCore, mLocale)) qFatal("Unable to install default translator.");
// if (installLocale(*this, *mTranslatorCore, getLocale())) { // if (installLocale(*this, *mTranslatorCore, getLocale())) {
// qDebug() << "installed locale" << getLocale().name(); // qDebug() << "installed locale" << getLocale().name();
// return; // return;
// } // }
// Try to use system locale. // Try to use system locale.
// #ifdef Q_OS_MACOS // #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 this workaround if there is still an issue about detecting wrong language from system on Mac. Qt doesn't use
// use the current system language on QLocale::system(). So we need to get it from user settings and overwrite // the current system language on QLocale::system(). So we need to get it from user settings and overwrite its
// its Locale. // Locale.
// QSettings settings; // QSettings settings;
// QString preferredLanguage = settings.value("AppleLanguages").toStringList().first(); // QString preferredLanguage = settings.value("AppleLanguages").toStringList().first();
// QStringList qtLocale = QLocale::system().name().split('_'); // QStringList qtLocale = QLocale::system().name().split('_');
// if(qtLocale[0] != preferredLanguage){ // if(qtLocale[0] != preferredLanguage){
// qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " << // qInfo() << "Override Qt language from " << qtLocale[0] << " to the preferred language : " <<
// preferredLanguage; qtLocale[0] = preferredLanguage; // preferredLanguage; qtLocale[0] = preferredLanguage;
// } // }
// QLocale sysLocale = QLocale(qtLocale.join('_')); // QLocale sysLocale = QLocale(qtLocale.join('_'));
// #else // #else
QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use QLocale sysLocale(QLocale::system().name()); // Use Locale from name because Qt has a bug where it didn't use the
// the QLocale::language (aka : translator.language != // QLocale::language (aka : translator.language != locale.language) on
// locale.language) on Mac. #endif // Mac. #endif
if (installLocale(*this, *mTranslatorCore, sysLocale)) { if (installLocale(*this, *mTranslatorCore, sysLocale)) {
qDebug() << "installed sys locale" << sysLocale.name(); qDebug() << "installed sys locale" << sysLocale.name();
setLocale(sysLocale.name()); setLocale(sysLocale.name());
@ -795,18 +632,10 @@ void App::initCppInterfaces() {
"SettingsCpp", 1, 0, "SettingsCpp", "SettingsCpp", 1, 0, "SettingsCpp",
[this](QQmlEngine *engine, QJSEngine *) -> QObject * { return mSettings.get(); }); [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<PhoneNumberProxy>(Constants::MainQmlUri, 1, 0, "PhoneNumberProxy");
qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject"); qmlRegisterType<VariantObject>(Constants::MainQmlUri, 1, 0, "VariantObject");
qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList"); qmlRegisterType<VariantList>(Constants::MainQmlUri, 1, 0, "VariantList");
qmlRegisterType<ParticipantInfoProxy>(Constants::MainQmlUri, 1, 0, "ParticipantInfoProxy");
qmlRegisterType<ParticipantProxy>(Constants::MainQmlUri, 1, 0, "ParticipantProxy"); qmlRegisterType<ParticipantProxy>(Constants::MainQmlUri, 1, 0, "ParticipantProxy");
qmlRegisterType<ParticipantGui>(Constants::MainQmlUri, 1, 0, "ParticipantGui"); qmlRegisterType<ParticipantGui>(Constants::MainQmlUri, 1, 0, "ParticipantGui");
qmlRegisterType<ConferenceInfoProxy>(Constants::MainQmlUri, 1, 0, "ConferenceInfoProxy"); qmlRegisterType<ConferenceInfoProxy>(Constants::MainQmlUri, 1, 0, "ConferenceInfoProxy");
@ -823,16 +652,6 @@ void App::initCppInterfaces() {
qmlRegisterType<CallHistoryProxy>(Constants::MainQmlUri, 1, 0, "CallHistoryProxy"); qmlRegisterType<CallHistoryProxy>(Constants::MainQmlUri, 1, 0, "CallHistoryProxy");
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui"); qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy"); 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", qmlRegisterUncreatableType<ConferenceCore>(Constants::MainQmlUri, 1, 0, "ConferenceCore",
QLatin1String("Uncreatable")); QLatin1String("Uncreatable"));
qmlRegisterType<ConferenceGui>(Constants::MainQmlUri, 1, 0, "ConferenceGui"); qmlRegisterType<ConferenceGui>(Constants::MainQmlUri, 1, 0, "ConferenceGui");
@ -842,11 +661,6 @@ void App::initCppInterfaces() {
qmlRegisterType<MagicSearchList>(Constants::MainQmlUri, 1, 0, "MagicSearchList"); qmlRegisterType<MagicSearchList>(Constants::MainQmlUri, 1, 0, "MagicSearchList");
qmlRegisterType<CameraGui>(Constants::MainQmlUri, 1, 0, "CameraGui"); qmlRegisterType<CameraGui>(Constants::MainQmlUri, 1, 0, "CameraGui");
qmlRegisterType<FPSCounter>(Constants::MainQmlUri, 1, 0, "FPSCounter"); 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"); qmlRegisterType<TimeZoneProxy>(Constants::MainQmlUri, 1, 0, "TimeZoneProxy");
@ -887,14 +701,6 @@ void App::initFonts() {
allFamilies << QFontDatabase::applicationFontFamilies(id); 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 #ifdef Q_OS_LINUX
QDirIterator itFonts(":/linux/font/", QDirIterator::Subdirectories); QDirIterator itFonts(":/linux/font/", QDirIterator::Subdirectories);
while (itFonts.hasNext()) { while (itFonts.hasNext()) {
@ -942,10 +748,8 @@ void App::clean() {
} }
void App::restart() { void App::restart() {
mCoreModelConnection->invokeToModel([this]() { mCoreModelConnection->invokeToModel([this]() {
FriendsManager::getInstance()->clearMaps();
CoreModel::getInstance()->getCore()->stop(); CoreModel::getInstance()->getCore()->stop();
mCoreModelConnection->invokeToCore([this]() { mCoreModelConnection->invokeToCore([this]() {
mIsRestarting = true;
closeCallsWindow(); closeCallsWindow();
setMainWindow(nullptr); setMainWindow(nullptr);
mEngine->clearComponentCache(); mEngine->clearComponentCache();
@ -971,37 +775,34 @@ void App::createCommandParser() {
//: "A free and open source SIP video-phone." //: "A free and open source SIP video-phone."
mParser->setApplicationDescription(tr("application_description")); mParser->setApplicationDescription(tr("application_description"));
//: "Send an order to the application towards a command line" //: "Send an order to the application towards a command line"
mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME), mParser->addPositionalArgument("command", tr("command_line_arg_order").replace("%1", APPLICATION_NAME), "[command]");
"[command]");
mParser->addOptions({ mParser->addOptions({
//: "Show this help" //: "Show this help"
{{"h", "help"}, tr("command_line_option_show_help")}, {{"h", "help"}, tr("command_line_option_show_help")},
//{"cli-help", tr("commandLineOptionCliHelp").replace("%1", APPLICATION_NAME)}, //{"cli-help", tr("commandLineOptionCliHelp").replace("%1", APPLICATION_NAME)},
//:"Show app version" //:"Show app version"
{{"v", "version"}, tr("command_line_option_show_app_version")}, {{"v", "version"}, tr("command_line_option_show_app_version")},
//{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME), //{"config", tr("command_line_option_config").replace("%1", EXECUTABLE_NAME), tr("command_line_option_config_arg")},
// tr("command_line_option_config_arg")},
{"fetch-config", {"fetch-config",
//: "Specify the linphone configuration file to be fetched. It will be merged with the current //: "Specify the linphone configuration file to be fetched. It will be merged with the current configuration."
//: configuration." tr("command_line_option_config_to_fetch")
tr("command_line_option_config_to_fetch").replace("%1", EXECUTABLE_NAME), .replace("%1", EXECUTABLE_NAME),
//: "URL, path or file" //: "URL, path or file"
tr("command_line_option_config_to_fetch_arg")}, tr("command_line_option_config_to_fetch_arg")},
//{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME), //{{"c", "call"}, tr("command_line_option_call").replace("%1", EXECUTABLE_NAME), tr("command_line_option_call_arg")},
// 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" //: "Log to stdout some debug information while running"
{{"V", "verbose"}, tr("command_line_option_log_to_stdout")}, {{"V", "verbose"}, tr("command_line_option_log_to_stdout")},
//: "Print only logs from the application" //: "Print only logs from the application"
{"qt-logs-only", tr("command_line_option_print_app_logs_only")}, {"qt-logs-only", tr("command_line_option_print_app_logs_only")},
}); });
} }
// Should be call only at first start // Should be call only at first start
@ -1054,9 +855,9 @@ bool App::notify(QObject *receiver, QEvent *event) {
try { try {
done = QApplication::notify(receiver, event); done = QApplication::notify(receiver, event);
} catch (const std::exception &ex) { } catch (const std::exception &ex) {
lFatal() << log().arg("Exception has been catch in notify: %1").arg(ex.what()); lCritical() << log().arg("Exception has been catch in notify: %1").arg(ex.what());
} catch (...) { } catch (...) {
lFatal() << log().arg("Generic exeption has been catch in notify"); lCritical() << log().arg("Generic exeption has been catch in notify");
} }
if (event->type() == QEvent::MouseButtonPress) { if (event->type() == QEvent::MouseButtonPress) {
auto window = findParentWindow(receiver); auto window = findParentWindow(receiver);
@ -1070,38 +871,7 @@ bool App::notify(QObject *receiver, QEvent *event) {
return done; return done;
} }
void App::handleAppActivity() { QQuickWindow *App::getCallsWindow(QVariant callGui) {
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()); mustBeInMainThread(getClassName());
if (!mCallsWindow) { if (!mCallsWindow) {
const QUrl callUrl("qrc:/qt/qml/Linphone/view/Page/Window/Call/CallsWindow.qml"); const QUrl callUrl("qrc:/qt/qml/Linphone/view/Page/Window/Call/CallsWindow.qml");
@ -1136,7 +906,6 @@ QQuickWindow *App::getOrCreateCallsWindow(QVariant callGui) {
} }
// window->setParent(mMainWindow); // window->setParent(mMainWindow);
mCallsWindow = window; mCallsWindow = window;
connect(mCallsWindow, &QQuickWindow::activeChanged, this, &App::handleAppActivity);
} }
if (!callGui.isNull() && callGui.isValid()) mCallsWindow->setProperty("call", callGui); if (!callGui.isNull() && callGui.isValid()) mCallsWindow->setProperty("call", callGui);
return mCallsWindow; return mCallsWindow;
@ -1147,7 +916,7 @@ void App::setCallsWindowProperty(const char *id, QVariant property) {
} }
void App::closeCallsWindow() { void App::closeCallsWindow() {
if (mCallsWindow && mCallList && !mCallList->getHaveCall()) { if (mCallsWindow) {
mCallsWindow->close(); mCallsWindow->close();
mCallsWindow->deleteLater(); mCallsWindow->deleteLater();
mCallsWindow = nullptr; mCallsWindow = nullptr;
@ -1159,11 +928,8 @@ QQuickWindow *App::getMainWindow() const {
} }
void App::setMainWindow(QQuickWindow *data) { void App::setMainWindow(QQuickWindow *data) {
if (mMainWindow) disconnect(mMainWindow, &QQuickWindow::activeChanged, this, nullptr);
if (mMainWindow != data) { if (mMainWindow != data) {
mMainWindow = data; mMainWindow = data;
connect(mMainWindow, &QQuickWindow::activeChanged, this, &App::handleAppActivity);
handleAppActivity();
emit mainWindowChanged(); emit mainWindowChanged();
} }
} }
@ -1371,16 +1137,6 @@ bool App::event(QEvent *event) {
} else if (event->type() == QEvent::ApplicationStateChange) { } else if (event->type() == QEvent::ApplicationStateChange) {
auto state = static_cast<QApplicationStateChangeEvent *>(event); auto state = static_cast<QApplicationStateChangeEvent *>(event);
if (state->applicationState() == Qt::ApplicationActive) Utils::smartShowWindow(getLastActiveWindow()); 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); return SingleApplication::event(event);
@ -1393,7 +1149,6 @@ bool App::event(QEvent *event) {
//----------------------------------------------------------- //-----------------------------------------------------------
void App::setSysTrayIcon() { void App::setSysTrayIcon() {
qDebug() << "setSysTrayIcon";
QQuickWindow *root = getMainWindow(); QQuickWindow *root = getMainWindow();
QSystemTrayIcon *systemTrayIcon = QSystemTrayIcon *systemTrayIcon =
(mSystemTrayIcon ? mSystemTrayIcon (mSystemTrayIcon ? mSystemTrayIcon
@ -1409,7 +1164,7 @@ void App::setSysTrayIcon() {
//: "Afficher" //: "Afficher"
restoreAction->setText(visible ? tr("hide_action") : tr("show_action")); restoreAction->setText(visible ? tr("hide_action") : tr("show_action"));
}; };
setRestoreActionText(root ? root->isVisible() : false); setRestoreActionText(root->isVisible());
connect(root, &QWindow::visibleChanged, restoreAction, setRestoreActionText); connect(root, &QWindow::visibleChanged, restoreAction, setRestoreActionText);
root->connect(restoreAction, &QAction::triggered, this, [this, restoreAction](bool checked) { root->connect(restoreAction, &QAction::triggered, this, [this, restoreAction](bool checked) {
@ -1425,9 +1180,6 @@ void App::setSysTrayIcon() {
QAction *quitAction = new QAction(tr("quit_action"), root); QAction *quitAction = new QAction(tr("quit_action"), root);
root->connect(quitAction, &QAction::triggered, this, &App::quit); root->connect(quitAction, &QAction::triggered, this, &App::quit);
//: "Mark all as read"
QAction *markAllReadAction = createMarkAsReadAction(root);
// trayIcon: Left click actions. // trayIcon: Left click actions.
QMenu *menu = mSystemTrayIcon ? mSystemTrayIcon->contextMenu() : new QMenu(); QMenu *menu = mSystemTrayIcon ? mSystemTrayIcon->contextMenu() : new QMenu();
menu->clear(); menu->clear();
@ -1437,13 +1189,6 @@ void App::setSysTrayIcon() {
menu->addAction(restoreAction); menu->addAction(restoreAction);
menu->addSeparator(); 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); menu->addAction(quitAction);
if (!mSystemTrayIcon) { if (!mSystemTrayIcon) {
systemTrayIcon->setContextMenu(menu); // This is a Qt bug. We cannot call setContextMenu more than once. So systemTrayIcon->setContextMenu(menu); // This is a Qt bug. We cannot call setContextMenu more than once. So
@ -1463,24 +1208,6 @@ void App::setSysTrayIcon() {
if (!QSystemTrayIcon::isSystemTrayAvailable()) qInfo() << "System tray is not available"; 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. // Locale TODO - App only in French now.
//----------------------------------------------------------- //-----------------------------------------------------------
@ -1522,48 +1249,3 @@ QString App::getSdkVersion() {
return tr('unknown'); return tr('unknown');
#endif #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;
}

View file

@ -18,14 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <QAction>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QSharedPointer> #include <QSharedPointer>
#include "core/account/AccountProxy.hpp" #include "core/account/AccountProxy.hpp"
#include "core/call/CallProxy.hpp" #include "core/call/CallProxy.hpp"
#include "core/chat/ChatGui.hpp"
#include "core/setting/SettingsCore.hpp" #include "core/setting/SettingsCore.hpp"
#include "core/singleapplication/singleapplication.h" #include "core/singleapplication/singleapplication.h"
#include "model/cli/CliModel.hpp" #include "model/cli/CliModel.hpp"
@ -33,7 +31,6 @@
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
class CallGui; class CallGui;
class ChatGui;
class Thread; class Thread;
class Notifier; class Notifier;
class QQuickWindow; class QQuickWindow;
@ -46,22 +43,17 @@ class App : public SingleApplication, public AbstractObject {
Q_PROPERTY(AccountList *accounts READ getAccounts NOTIFY accountsChanged) Q_PROPERTY(AccountList *accounts READ getAccounts NOTIFY accountsChanged)
Q_PROPERTY(CallList *calls READ getCalls NOTIFY callsChanged) Q_PROPERTY(CallList *calls READ getCalls NOTIFY callsChanged)
Q_PROPERTY(QString shortApplicationVersion READ getShortApplicationVersion CONSTANT) Q_PROPERTY(QString shortApplicationVersion READ getShortApplicationVersion CONSTANT)
Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT)
Q_PROPERTY(QString gitBranchName READ getGitBranchName CONSTANT) Q_PROPERTY(QString gitBranchName READ getGitBranchName CONSTANT)
Q_PROPERTY(QString sdkVersion READ getSdkVersion CONSTANT) Q_PROPERTY(QString sdkVersion READ getSdkVersion CONSTANT)
Q_PROPERTY(ChatGui *currentChat READ getCurrentChat WRITE setCurrentChat NOTIFY currentChatChanged)
public: public:
App(int &argc, char *argv[]); App(int &argc, char *argv[]);
~App(); ~App();
void setSelf(QSharedPointer<App>(me)); void setSelf(QSharedPointer<App>(me));
static App *getInstance(); static App *getInstance();
static Thread *getLinphoneThread(); static QThread *getLinphoneThread();
Notifier *getNotifier() const; Notifier *getNotifier() const;
EventCountNotifier *getEventCountNotifier();
int getEventCount() const;
// App::postModelAsync(<lambda>) => run lambda in model thread and continue. // App::postModelAsync(<lambda>) => run lambda in model thread and continue.
// App::postModelSync(<lambda>) => run lambda in current thread and block connection. // App::postModelSync(<lambda>) => run lambda in current thread and block connection.
template <typename Func, typename... Args> template <typename Func, typename... Args>
@ -127,10 +119,6 @@ public:
void restart(); void restart();
bool autoStartEnabled(); bool autoStartEnabled();
void setSysTrayIcon(); void setSysTrayIcon();
QSystemTrayIcon *getSystemTrayIcon() const {
return mSystemTrayIcon;
}
void updateSysTrayCount(int n);
QLocale getLocale(); QLocale getLocale();
void onLoggerInitialized(); void onLoggerInitialized();
@ -139,9 +127,7 @@ public:
bool getCoreStarted() const; bool getCoreStarted() const;
void setCoreStarted(bool started); void setCoreStarted(bool started);
QQuickWindow *getCallsWindow(); QQuickWindow *getCallsWindow(QVariant callGui = QVariant());
Q_INVOKABLE void handleAppActivity();
QQuickWindow *getOrCreateCallsWindow(QVariant callGui = QVariant());
void setCallsWindowProperty(const char *id, QVariant property); void setCallsWindowProperty(const char *id, QVariant property);
void closeCallsWindow(); void closeCallsWindow();
@ -167,14 +153,6 @@ public:
QString getShortApplicationVersion(); QString getShortApplicationVersion();
QString getGitBranchName(); QString getGitBranchName();
QString getSdkVersion(); 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 #ifdef Q_OS_LINUX
Q_INVOKABLE void exportDesktopFile(); Q_INVOKABLE void exportDesktopFile();
@ -194,30 +172,22 @@ signals:
void mainWindowChanged(); void mainWindowChanged();
void coreStartedChanged(bool coreStarted); void coreStartedChanged(bool coreStarted);
void accountsChanged(); void accountsChanged();
void defaultAccountChanged();
void callsChanged(); void callsChanged();
void currentDateChanged(); void currentDateChanged();
void currentChatChanged();
// void executeCommand(QString command); // void executeCommand(QString command);
private: private:
void createCommandParser(); void createCommandParser();
QAction *createMarkAsReadAction(QQuickWindow *window);
void setMacOSDockActions(); // Should only be called on MacOS
void setAutoStart(bool enabled); void setAutoStart(bool enabled);
void setLocale(QString configLocale); void setLocale(QString configLocale);
QCommandLineParser *mParser = nullptr; QCommandLineParser *mParser = nullptr;
Thread *mLinphoneThread = nullptr; Thread *mLinphoneThread = nullptr;
Notifier *mNotifier = nullptr; Notifier *mNotifier = nullptr;
EventCountNotifier *mEventCountNotifier = nullptr;
QSystemTrayIcon *mSystemTrayIcon = nullptr; QSystemTrayIcon *mSystemTrayIcon = nullptr;
QQuickWindow *mMainWindow = nullptr; QQuickWindow *mMainWindow = nullptr;
QQuickWindow *mCallsWindow = nullptr; QQuickWindow *mCallsWindow = nullptr;
QQuickWindow *mLastActiveWindow = 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<SettingsCore> mSettings;
QSharedPointer<AccountList> mAccountList; QSharedPointer<AccountList> mAccountList;
QSharedPointer<CallList> mCallList; QSharedPointer<CallList> mCallList;
@ -225,14 +195,11 @@ private:
QSharedPointer<SafeConnection<App, CliModel>> mCliModelConnection; QSharedPointer<SafeConnection<App, CliModel>> mCliModelConnection;
bool mAutoStart = false; bool mAutoStart = false;
bool mCoreStarted = false; bool mCoreStarted = false;
bool mIsRestarting = false;
bool mPossiblyLookForAddedAccount = false;
QLocale mLocale = QLocale::system(); QLocale mLocale = QLocale::system();
DefaultTranslatorCore *mTranslatorCore = nullptr; DefaultTranslatorCore *mTranslatorCore = nullptr;
DefaultTranslatorCore *mDefaultTranslatorCore = nullptr; DefaultTranslatorCore *mDefaultTranslatorCore = nullptr;
QTimer mDateUpdateTimer; QTimer mDateUpdateTimer;
QDate mCurrentDate; QDate mCurrentDate;
float mScreenRatio = 1;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -19,28 +19,6 @@ list(APPEND _LINPHONEAPP_SOURCES
core/camera/CameraGui.cpp core/camera/CameraGui.cpp
core/camera/CameraDummy.cpp core/camera/CameraDummy.cpp
core/camera/PreviewManager.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/fps-counter/FPSCounter.cpp
core/friend/FriendCore.cpp core/friend/FriendCore.cpp
core/friend/FriendGui.cpp core/friend/FriendGui.cpp
@ -86,18 +64,10 @@ list(APPEND _LINPHONEAPP_SOURCES
core/participant/ParticipantDeviceProxy.cpp core/participant/ParticipantDeviceProxy.cpp
core/participant/ParticipantList.cpp core/participant/ParticipantList.cpp
core/participant/ParticipantProxy.cpp core/participant/ParticipantProxy.cpp
core/participant/ParticipantInfoList.cpp
core/participant/ParticipantInfoProxy.cpp
core/screen/ScreenList.cpp core/screen/ScreenList.cpp
core/screen/ScreenProxy.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/VideoSourceDescriptorCore.cpp
core/videoSource/VideoSourceDescriptorGui.cpp core/videoSource/VideoSourceDescriptorGui.cpp
@ -129,9 +99,5 @@ else() # Use QDBus for Linux
core/singleapplication/SingleApplicationDBusPrivate.hpp core/singleapplication/SingleApplicationDBusPrivate.hpp
core/singleapplication/SingleApplicationDBus.cpp) core/singleapplication/SingleApplicationDBus.cpp)
endif() 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) set(_LINPHONEAPP_SOURCES ${_LINPHONEAPP_SOURCES} PARENT_SCOPE)

View file

@ -43,18 +43,18 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
auto address = account->getContactAddress(); auto address = account->getContactAddress();
mContactAddress = address ? Utils::coreStringToAppString(account->getContactAddress()->asStringUriOnly()) : ""; mContactAddress = address ? Utils::coreStringToAppString(account->getContactAddress()->asStringUriOnly()) : "";
auto params = account->getParams()->clone(); auto params = account->getParams()->clone();
auto identityAddress = params->getIdentityAddress(); auto identityAddress = params->getIdentityAddress()->clone();
mIdentityAddress = identityAddress ? Utils::coreStringToAppString(identityAddress->asStringUriOnly()) : ""; mIdentityAddress = identityAddress ? Utils::coreStringToAppString(identityAddress->asStringUriOnly()) : "";
mPictureUri = Utils::coreStringToAppString(params->getPictureUri()); mPictureUri = Utils::coreStringToAppString(params->getPictureUri());
mRegistrationState = LinphoneEnums::fromLinphone(account->getState()); mRegistrationState = LinphoneEnums::fromLinphone(account->getState());
mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account; mIsDefaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount() == account;
mUnreadNotifications = account->getMissedCallsCount() + account->getUnreadChatMessageCount(); // mUnreadNotifications = account->getUnreadChatMessageCount() + account->getMissedCallsCount(); // TODO
mUnreadNotifications = account->getMissedCallsCount();
mDisplayName = Utils::coreStringToAppString(identityAddress->getDisplayName()); mDisplayName = Utils::coreStringToAppString(identityAddress->getDisplayName());
if (mDisplayName.isEmpty()) { if (mDisplayName.isEmpty()) {
mDisplayName = ToolModel::getDisplayName(identityAddress); mDisplayName = ToolModel::getDisplayName(identityAddress);
auto copyAddress = identityAddress->clone(); identityAddress->setDisplayName(Utils::appStringToCoreString(mDisplayName));
copyAddress->setDisplayName(Utils::appStringToCoreString(mDisplayName)); params->setIdentityAddress(identityAddress);
params->setIdentityAddress(copyAddress);
account->setParams(params); account->setParams(params);
} }
mRegisterEnabled = params->registerEnabled(); mRegisterEnabled = params->registerEnabled();
@ -65,11 +65,9 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
<< "TLS" << "TLS"
<< "DTLS"; << "DTLS";
mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(params->getTransport())); mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(params->getTransport()));
mRegistrarUri = mServerAddress =
params->getServerAddress() ? Utils::coreStringToAppString(params->getServerAddress()->asString()) : ""; params->getServerAddress() ? Utils::coreStringToAppString(params->getServerAddress()->asString()) : "";
auto routesAddresses = params->getRoutesAddresses(); mOutboundProxyEnabled = params->outboundProxyEnabled();
mOutboundProxyUri =
routesAddresses.empty() ? "" : Utils::coreStringToAppString(routesAddresses.front()->asString());
auto policy = params->getNatPolicy() ? params->getNatPolicy() : account->getCore()->createNatPolicy(); auto policy = params->getNatPolicy() ? params->getNatPolicy() : account->getCore()->createNatPolicy();
mStunServer = Utils::coreStringToAppString(policy->getStunServer()); mStunServer = Utils::coreStringToAppString(policy->getStunServer());
mIceEnabled = policy->iceEnabled(); mIceEnabled = policy->iceEnabled();
@ -84,19 +82,10 @@ AccountCore::AccountCore(const std::shared_ptr<linphone::Account> &account) : QO
? Utils::coreStringToAppString(params->getAudioVideoConferenceFactoryAddress()->asString()) ? Utils::coreStringToAppString(params->getAudioVideoConferenceFactoryAddress()->asString())
: ""; : "";
mLimeServerUrl = Utils::coreStringToAppString(params->getLimeServerUrl()); mLimeServerUrl = Utils::coreStringToAppString(params->getLimeServerUrl());
mCcmpServerUrl = Utils::coreStringToAppString(params->getCcmpServerUrl());
// Add listener // Add listener
mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK mAccountModel = Utils::makeQObject_ptr<AccountModel>(account); // OK
mAccountModel->setSelf(mAccountModel); 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(); mNotificationsAllowed = mAccountModel->getNotificationsAllowed();
mDialPlan = Utils::createDialPlanVariant("", " "); mDialPlan = Utils::createDialPlanVariant("", " ");
mDialPlans << mDialPlan; mDialPlans << mDialPlan;
@ -139,8 +128,8 @@ AccountCore::AccountCore(const AccountCore &accountCore) {
mVoicemailAddress = accountCore.mVoicemailAddress; mVoicemailAddress = accountCore.mVoicemailAddress;
mTransport = accountCore.mTransport; mTransport = accountCore.mTransport;
mTransports = accountCore.mTransports; mTransports = accountCore.mTransports;
mRegistrarUri = accountCore.mRegistrarUri; mServerAddress = accountCore.mServerAddress;
mOutboundProxyUri = accountCore.mOutboundProxyUri; mOutboundProxyEnabled = accountCore.mOutboundProxyEnabled;
mStunServer = accountCore.mStunServer; mStunServer = accountCore.mStunServer;
mIceEnabled = accountCore.mIceEnabled; mIceEnabled = accountCore.mIceEnabled;
mAvpfEnabled = accountCore.mAvpfEnabled; mAvpfEnabled = accountCore.mAvpfEnabled;
@ -149,7 +138,6 @@ AccountCore::AccountCore(const AccountCore &accountCore) {
mConferenceFactoryAddress = accountCore.mConferenceFactoryAddress; mConferenceFactoryAddress = accountCore.mConferenceFactoryAddress;
mAudioVideoConferenceFactoryAddress = accountCore.mAudioVideoConferenceFactoryAddress; mAudioVideoConferenceFactoryAddress = accountCore.mAudioVideoConferenceFactoryAddress;
mLimeServerUrl = accountCore.mLimeServerUrl; mLimeServerUrl = accountCore.mLimeServerUrl;
mCcmpServerUrl = accountCore.mCcmpServerUrl;
} }
void AccountCore::setSelf(QSharedPointer<AccountCore> me) { void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
@ -160,12 +148,6 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->invokeToCore( mAccountModelConnection->invokeToCore(
[this, account, state, message]() { onRegistrationStateChanged(account, state, message); }); [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 // From Model
mAccountModelConnection->makeConnectToModel(&AccountModel::defaultAccountChanged, [this](bool isDefault) { mAccountModelConnection->makeConnectToModel(&AccountModel::defaultAccountChanged, [this](bool isDefault) {
mAccountModelConnection->invokeToCore([this, isDefault]() { onDefaultAccountChanged(isDefault); }); mAccountModelConnection->invokeToCore([this, isDefault]() { onDefaultAccountChanged(isDefault); });
@ -205,11 +187,11 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->invokeToCore( mAccountModelConnection->invokeToCore(
[this, value]() { onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); }); [this, value]() { onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(value))); });
}); });
mAccountModelConnection->makeConnectToModel(&AccountModel::registrarUriChanged, [this](QString value) { mAccountModelConnection->makeConnectToModel(&AccountModel::serverAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onRegistrarUriChanged(value); }); mAccountModelConnection->invokeToCore([this, value]() { onServerAddressChanged(value); });
}); });
mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyUriChanged, [this](QString value) { mAccountModelConnection->makeConnectToModel(&AccountModel::outboundProxyEnabledChanged, [this](bool value) {
mAccountModelConnection->invokeToCore([this, value]() { onOutboundProxyUriChanged(value); }); mAccountModelConnection->invokeToCore([this, value]() { onOutboundProxyEnabledChanged(value); });
}); });
mAccountModelConnection->makeConnectToModel(&AccountModel::stunServerChanged, [this](QString value) { mAccountModelConnection->makeConnectToModel(&AccountModel::stunServerChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onStunServerChanged(value); }); mAccountModelConnection->invokeToCore([this, value]() { onStunServerChanged(value); });
@ -238,23 +220,9 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) { mAccountModelConnection->makeConnectToModel(&AccountModel::limeServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onLimeServerUrlChanged(value); }); mAccountModelConnection->invokeToCore([this, value]() { onLimeServerUrlChanged(value); });
}); });
mAccountModelConnection->makeConnectToModel(&AccountModel::ccmpServerUrlChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { onCcmpServerUrlChanged(value); });
});
mAccountModelConnection->makeConnectToModel( mAccountModelConnection->makeConnectToModel(
&AccountModel::removed, [this]() { mAccountModelConnection->invokeToCore([this]() { emit removed(); }); }); &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 // From GUI
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) { mAccountModelConnection->makeConnectToCore(&AccountCore::lSetPictureUri, [this](QString uri) {
mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); }); mAccountModelConnection->invokeToModel([this, uri]() { mAccountModel->setPictureUri(uri); });
@ -265,17 +233,19 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToCore(&AccountCore::lResetMissedCalls, [this]() { mAccountModelConnection->makeConnectToCore(&AccountCore::lResetMissedCalls, [this]() {
mAccountModelConnection->invokeToModel([this]() { mAccountModel->resetMissedCallsCount(); }); 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->makeConnectToCore(&AccountCore::lRefreshNotifications, [this]() {
mAccountModelConnection->invokeToModel([this]() { mAccountModel->refreshUnreadNotifications(); }); 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->makeConnectToCore(&AccountCore::lSetDisplayName, [this](QString displayName) {
mAccountModelConnection->invokeToModel([this, displayName]() { mAccountModel->setDisplayName(displayName); }); mAccountModelConnection->invokeToModel([this, displayName]() { mAccountModel->setDisplayName(displayName); });
}); });
@ -290,13 +260,6 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) { mAccountModelConnection->makeConnectToCore(&AccountCore::lSetNotificationsAllowed, [this](bool value) {
mAccountModelConnection->invokeToModel([this, value]() { mAccountModel->setNotificationsAllowed(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, DEFINE_CORE_GET_CONNECT(mAccountModelConnection, AccountCore, AccountModel, mAccountModel, int, voicemailCount,
VoicemailCount) VoicemailCount)
@ -306,14 +269,6 @@ void AccountCore::setSelf(QSharedPointer<AccountCore> me) {
mAccountModelConnection->makeConnectToModel(&AccountModel::voicemailAddressChanged, [this](QString value) { mAccountModelConnection->makeConnectToModel(&AccountModel::voicemailAddressChanged, [this](QString value) {
mAccountModelConnection->invokeToCore([this, value]() { setVoicemailAddress(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) { void AccountCore::reset(const AccountCore &accountCore) {
@ -323,8 +278,8 @@ void AccountCore::reset(const AccountCore &accountCore) {
setMwiServerAddress(accountCore.mMwiServerAddress); setMwiServerAddress(accountCore.mMwiServerAddress);
setVoicemailAddress(accountCore.mVoicemailAddress); setVoicemailAddress(accountCore.mVoicemailAddress);
setTransport(accountCore.mTransport); setTransport(accountCore.mTransport);
setRegistrarUri(accountCore.mRegistrarUri); setServerAddress(accountCore.mServerAddress);
setOutboundProxyUri(accountCore.mOutboundProxyUri); setOutboundProxyEnabled(accountCore.mOutboundProxyEnabled);
setStunServer(accountCore.mStunServer); setStunServer(accountCore.mStunServer);
setIceEnabled(accountCore.mIceEnabled); setIceEnabled(accountCore.mIceEnabled);
setAvpfEnabled(accountCore.mAvpfEnabled); setAvpfEnabled(accountCore.mAvpfEnabled);
@ -333,7 +288,6 @@ void AccountCore::reset(const AccountCore &accountCore) {
setConferenceFactoryAddress(accountCore.mConferenceFactoryAddress); setConferenceFactoryAddress(accountCore.mConferenceFactoryAddress);
setAudioVideoConferenceFactoryAddress(accountCore.mAudioVideoConferenceFactoryAddress); setAudioVideoConferenceFactoryAddress(accountCore.mAudioVideoConferenceFactoryAddress);
setLimeServerUrl(accountCore.mLimeServerUrl); setLimeServerUrl(accountCore.mLimeServerUrl);
setCcmpServerUrl(accountCore.mCcmpServerUrl);
} }
const std::shared_ptr<AccountModel> &AccountCore::getModel() const { const std::shared_ptr<AccountModel> &AccountCore::getModel() const {
@ -393,8 +347,8 @@ void AccountCore::setUnreadMessageNotifications(int unread) {
void AccountCore::onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account, void AccountCore::onRegistrationStateChanged(const std::shared_ptr<linphone::Account> &account,
linphone::RegistrationState state, linphone::RegistrationState state,
const std::string &message) { const std::string &message) {
lDebug() << log().arg(Q_FUNC_INFO) << (int)state;
mRegistrationState = LinphoneEnums::fromLinphone(state); mRegistrationState = LinphoneEnums::fromLinphone(state);
qDebug() << log().arg(Q_FUNC_INFO) << mRegistrationState;
emit registrationStateChanged(Utils::coreStringToAppString(message)); emit registrationStateChanged(Utils::coreStringToAppString(message));
} }
@ -469,30 +423,6 @@ 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 { QString AccountCore::getHumanReadableRegistrationStateExplained() const {
switch (mRegistrationState) { switch (mRegistrationState) {
case LinphoneEnums::RegistrationState::Ok: case LinphoneEnums::RegistrationState::Ok:
@ -541,12 +471,12 @@ QString AccountCore::getTransport() {
return mTransport; return mTransport;
} }
QString AccountCore::getRegistrarUri() { QString AccountCore::getServerAddress() {
return mRegistrarUri; return mServerAddress;
} }
QString AccountCore::getOutboundProxyUri() { bool AccountCore::getOutboundProxyEnabled() {
return mOutboundProxyUri; return mOutboundProxyEnabled;
} }
QString AccountCore::getStunServer() { QString AccountCore::getStunServer() {
@ -581,10 +511,6 @@ QString AccountCore::getLimeServerUrl() {
return mLimeServerUrl; return mLimeServerUrl;
} }
QString AccountCore::getCcmpServerUrl() {
return mCcmpServerUrl;
}
void AccountCore::setMwiServerAddress(QString value) { void AccountCore::setMwiServerAddress(QString value) {
if (mMwiServerAddress != value) { if (mMwiServerAddress != value) {
mMwiServerAddress = value; mMwiServerAddress = value;
@ -603,24 +529,32 @@ void AccountCore::setVoicemailAddress(QString value) {
void AccountCore::setTransport(QString value) { void AccountCore::setTransport(QString value) {
if (mTransport != value) { if (mTransport != value) {
mTransport = value; mAccountModelConnection->invokeToModel([this, value] {
emit transportChanged(); mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
LinphoneEnums::TransportType transport;
LinphoneEnums::fromString(value, &transport);
mAccountModel->setTransport(LinphoneEnums::toLinphone(transport), false);
});
setIsSaved(false); setIsSaved(false);
} }
} }
void AccountCore::setRegistrarUri(QString value) { void AccountCore::setServerAddress(QString value) {
if (mRegistrarUri != value) { if (mServerAddress != value) {
mRegistrarUri = value; mAccountModelConnection->invokeToModel([this, value, transportString = mTransport] {
emit registrarUriChanged(); LinphoneEnums::TransportType transport;
LinphoneEnums::fromString(transportString, &transport);
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
mAccountModel->setServerAddress(value, LinphoneEnums::toLinphone(transport), false);
});
setIsSaved(false); setIsSaved(false);
} }
} }
void AccountCore::setOutboundProxyUri(QString value) { void AccountCore::setOutboundProxyEnabled(bool value) {
if (mOutboundProxyUri != value) { if (mOutboundProxyEnabled != value) {
mOutboundProxyUri = value; mOutboundProxyEnabled = value;
emit outboundProxyUriChanged(); emit outboundProxyEnabledChanged();
setIsSaved(false); setIsSaved(false);
} }
} }
@ -689,14 +623,6 @@ void AccountCore::setLimeServerUrl(QString value) {
} }
} }
void AccountCore::setCcmpServerUrl(QString value) {
if (mCcmpServerUrl != value) {
mCcmpServerUrl = value;
emit ccmpServerUrlChanged();
setIsSaved(false);
}
}
bool AccountCore::isSaved() const { bool AccountCore::isSaved() const {
return mIsSaved; return mIsSaved;
} }
@ -736,20 +662,19 @@ void AccountCore::onTransportChanged(QString value) {
} }
} }
void AccountCore::onRegistrarUriChanged(QString value) { void AccountCore::onServerAddressChanged(QString value) {
if (value != mRegistrarUri) { if (value != mServerAddress) {
mRegistrarUri = value; mServerAddress = value;
emit registrarUriChanged(); emit serverAddressChanged();
} }
} }
void AccountCore::onOutboundProxyUriChanged(QString value) { void AccountCore::onOutboundProxyEnabledChanged(bool value) {
if (value != mOutboundProxyUri) { if (value != mOutboundProxyEnabled) {
mOutboundProxyUri = value; mOutboundProxyEnabled = value;
emit outboundProxyUriChanged(); emit outboundProxyEnabledChanged();
} }
} }
void AccountCore::onStunServerChanged(QString value) { void AccountCore::onStunServerChanged(QString value) {
if (value != mStunServer) { if (value != mStunServer) {
mStunServer = value; mStunServer = value;
@ -809,21 +734,14 @@ 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 { void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO); mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
model->setMwiServerAddress(mMwiServerAddress); model->setMwiServerAddress(mMwiServerAddress);
LinphoneEnums::TransportType transport; LinphoneEnums::TransportType transport;
LinphoneEnums::fromString(mTransport, &transport); LinphoneEnums::fromString(mTransport, &transport);
model->setTransport(LinphoneEnums::toLinphone(transport), true); model->setTransport(LinphoneEnums::toLinphone(transport), true);
model->setRegistrarUri(mRegistrarUri); model->setServerAddress(mServerAddress, LinphoneEnums::toLinphone(transport), true);
model->setOutboundProxyUri(mOutboundProxyUri); model->setOutboundProxyEnabled(mOutboundProxyEnabled);
model->setStunServer(mStunServer); model->setStunServer(mStunServer);
model->setIceEnabled(mIceEnabled); model->setIceEnabled(mIceEnabled);
model->setAvpfEnabled(mAvpfEnabled); model->setAvpfEnabled(mAvpfEnabled);
@ -832,28 +750,27 @@ void AccountCore::writeIntoModel(std::shared_ptr<AccountModel> model) const {
model->setConferenceFactoryAddress(mConferenceFactoryAddress); model->setConferenceFactoryAddress(mConferenceFactoryAddress);
model->setAudioVideoConferenceFactoryAddress(mAudioVideoConferenceFactoryAddress); model->setAudioVideoConferenceFactoryAddress(mAudioVideoConferenceFactoryAddress);
model->setLimeServerUrl(mLimeServerUrl); model->setLimeServerUrl(mLimeServerUrl);
model->setCcmpServerUrl(mCcmpServerUrl);
model->setVoicemailAddress(mVoicemailAddress); model->setVoicemailAddress(mVoicemailAddress);
} }
void AccountCore::writeFromModel(const std::shared_ptr<AccountModel> &model) { void AccountCore::writeFromModel(const std::shared_ptr<AccountModel> &model) {
mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO); mustBeInLinphoneThread(getClassName() + Q_FUNC_INFO);
setUnreadCallNotifications(model->getMissedCallsCount());
setUnreadMessageNotifications(model->getUnreadMessagesCount()); mUnreadCallNotifications = model->getMissedCallsCount();
onMwiServerAddressChanged(model->getMwiServerAddress()); mUnreadMessageNotifications = model->getUnreadMessagesCount();
onTransportChanged(LinphoneEnums::toString(LinphoneEnums::fromLinphone(model->getTransport()))); mMwiServerAddress = model->getMwiServerAddress();
onRegistrarUriChanged(model->getRegistrarUri()); mTransport = LinphoneEnums::toString(LinphoneEnums::fromLinphone(model->getTransport()));
onOutboundProxyUriChanged(model->getOutboundProxyUri()); mServerAddress = model->getServerAddress();
onStunServerChanged(model->getStunServer()); mOutboundProxyEnabled = model->getOutboundProxyEnabled();
onIceEnabledChanged(model->getIceEnabled()); mStunServer = model->getStunServer();
onAvpfEnabledChanged(model->getAvpfEnabled()); mIceEnabled = model->getIceEnabled();
onBundleModeEnabledChanged(model->getBundleModeEnabled()); mAvpfEnabled = model->getAvpfEnabled();
onExpireChanged(model->getExpire()); mBundleModeEnabled = model->getBundleModeEnabled();
onConferenceFactoryAddressChanged(model->getConferenceFactoryAddress()); mExpire = model->getExpire();
onAudioVideoConferenceFactoryAddressChanged(model->getAudioVideoConferenceFactoryAddress()); mConferenceFactoryAddress = model->getConferenceFactoryAddress();
onLimeServerUrlChanged(model->getLimeServerUrl()); mAudioVideoConferenceFactoryAddress = model->getAudioVideoConferenceFactoryAddress();
onCcmpServerUrlChanged(model->getCcmpServerUrl()); mLimeServerUrl = model->getLimeServerUrl();
onVoicemailAddressChanged(model->getVoicemailAddress()); mVoicemailAddress = model->getVoicemailAddress();
} }
void AccountCore::save() { void AccountCore::save() {
@ -885,38 +802,3 @@ 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;
}

View file

@ -58,9 +58,9 @@ public:
QString mwiServerAddress READ getMwiServerAddress WRITE setMwiServerAddress NOTIFY mwiServerAddressChanged) QString mwiServerAddress READ getMwiServerAddress WRITE setMwiServerAddress NOTIFY mwiServerAddressChanged)
Q_PROPERTY(QStringList transports READ getTransports CONSTANT) Q_PROPERTY(QStringList transports READ getTransports CONSTANT)
Q_PROPERTY(QString transport READ getTransport WRITE setTransport NOTIFY transportChanged) Q_PROPERTY(QString transport READ getTransport WRITE setTransport NOTIFY transportChanged)
Q_PROPERTY(QString registrarUri READ getRegistrarUri WRITE setRegistrarUri NOTIFY registrarUriChanged) Q_PROPERTY(QString serverAddress READ getServerAddress WRITE setServerAddress NOTIFY serverAddressChanged)
Q_PROPERTY( Q_PROPERTY(bool outboundProxyEnabled READ getOutboundProxyEnabled WRITE setOutboundProxyEnabled NOTIFY
QString outboundProxyUri READ getOutboundProxyUri WRITE setOutboundProxyUri NOTIFY outboundProxyUriChanged) outboundProxyEnabledChanged)
Q_PROPERTY(QString stunServer READ getStunServer WRITE setStunServer NOTIFY stunServerChanged) Q_PROPERTY(QString stunServer READ getStunServer WRITE setStunServer NOTIFY stunServerChanged)
Q_PROPERTY(bool iceEnabled READ getIceEnabled WRITE setIceEnabled NOTIFY iceEnabledChanged) Q_PROPERTY(bool iceEnabled READ getIceEnabled WRITE setIceEnabled NOTIFY iceEnabledChanged)
Q_PROPERTY(bool avpfEnabled READ getAvpfEnabled WRITE setAvpfEnabled NOTIFY avpfEnabledChanged) Q_PROPERTY(bool avpfEnabled READ getAvpfEnabled WRITE setAvpfEnabled NOTIFY avpfEnabledChanged)
@ -75,16 +75,6 @@ public:
Q_PROPERTY(bool isSaved READ isSaved WRITE setIsSaved NOTIFY isSavedChanged) Q_PROPERTY(bool isSaved READ isSaved WRITE setIsSaved NOTIFY isSavedChanged)
Q_PROPERTY( Q_PROPERTY(
QString voicemailAddress READ getVoicemailAddress WRITE setVoicemailAddress NOTIFY voicemailAddressChanged) 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) DECLARE_CORE_GET(int, voicemailCount, VoicemailCount)
static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account); static QSharedPointer<AccountCore> create(const std::shared_ptr<linphone::Account> &account);
@ -124,8 +114,6 @@ public:
void onDialPlanChanged(QVariantMap internationalPrefix); void onDialPlanChanged(QVariantMap internationalPrefix);
QString getHumanReadableRegistrationState() const; QString getHumanReadableRegistrationState() const;
QString getHumanReadableRegistrationStateExplained() const; QString getHumanReadableRegistrationStateExplained() const;
QColor getRegistrationColor() const;
QUrl getRegistrationIcon() const;
bool getRegisterEnabled() const; bool getRegisterEnabled() const;
void onRegisterEnabledChanged(bool enabled); void onRegisterEnabledChanged(bool enabled);
@ -133,8 +121,8 @@ public:
QString getMwiServerAddress(); QString getMwiServerAddress();
QString getTransport(); QString getTransport();
QStringList getTransports(); QStringList getTransports();
QString getRegistrarUri(); QString getServerAddress();
QString getOutboundProxyUri(); bool getOutboundProxyEnabled();
QString getStunServer(); QString getStunServer();
bool getIceEnabled(); bool getIceEnabled();
bool getAvpfEnabled(); bool getAvpfEnabled();
@ -144,12 +132,11 @@ public:
QString getAudioVideoConferenceFactoryAddress(); QString getAudioVideoConferenceFactoryAddress();
QString getLimeServerUrl(); QString getLimeServerUrl();
QString getVoicemailAddress(); QString getVoicemailAddress();
QString getCcmpServerUrl();
void setMwiServerAddress(QString value); void setMwiServerAddress(QString value);
void setTransport(QString value); void setTransport(QString value);
void setRegistrarUri(QString value); void setServerAddress(QString value);
void setOutboundProxyUri(QString value); void setOutboundProxyEnabled(bool value);
void setStunServer(QString value); void setStunServer(QString value);
void setIceEnabled(bool value); void setIceEnabled(bool value);
void setAvpfEnabled(bool value); void setAvpfEnabled(bool value);
@ -159,7 +146,6 @@ public:
void setAudioVideoConferenceFactoryAddress(QString value); void setAudioVideoConferenceFactoryAddress(QString value);
void setLimeServerUrl(QString value); void setLimeServerUrl(QString value);
void setVoicemailAddress(QString value); void setVoicemailAddress(QString value);
void setCcmpServerUrl(QString value);
bool isSaved() const; bool isSaved() const;
void setIsSaved(bool saved); void setIsSaved(bool saved);
@ -168,8 +154,8 @@ public:
void onMwiServerAddressChanged(QString value); void onMwiServerAddressChanged(QString value);
void onVoicemailAddressChanged(QString value); void onVoicemailAddressChanged(QString value);
void onTransportChanged(QString value); void onTransportChanged(QString value);
void onRegistrarUriChanged(QString value); void onServerAddressChanged(QString value);
void onOutboundProxyUriChanged(QString value); void onOutboundProxyEnabledChanged(bool value);
void onStunServerChanged(QString value); void onStunServerChanged(QString value);
void onIceEnabledChanged(bool value); void onIceEnabledChanged(bool value);
void onAvpfEnabledChanged(bool value); void onAvpfEnabledChanged(bool value);
@ -178,26 +164,15 @@ public:
void onConferenceFactoryAddressChanged(QString value); void onConferenceFactoryAddressChanged(QString value);
void onAudioVideoConferenceFactoryAddressChanged(QString value); void onAudioVideoConferenceFactoryAddressChanged(QString value);
void onLimeServerUrlChanged(QString value); void onLimeServerUrlChanged(QString value);
void onCcmpServerUrlChanged(QString value);
DECLARE_CORE_GET(bool, showMwi, ShowMwi) DECLARE_CORE_GET(bool, showMwi, ShowMwi)
Q_INVOKABLE void save(); Q_INVOKABLE void save();
Q_INVOKABLE void undo(); 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: signals:
void pictureUriChanged(); void pictureUriChanged();
void registrationStateChanged(const QString &message); void registrationStateChanged(const QString &message);
void conferenceInformationUpdated();
void defaultAccountChanged(bool isDefault); void defaultAccountChanged(bool isDefault);
void unreadNotificationsChanged(int unread); void unreadNotificationsChanged(int unread);
void unreadCallNotificationsChanged(int unread); void unreadCallNotificationsChanged(int unread);
@ -210,8 +185,8 @@ signals:
void notificationsAllowedChanged(); void notificationsAllowedChanged();
void mwiServerAddressChanged(); void mwiServerAddressChanged();
void transportChanged(); void transportChanged();
void registrarUriChanged(); void serverAddressChanged();
void outboundProxyUriChanged(); void outboundProxyEnabledChanged();
void stunServerChanged(); void stunServerChanged();
void iceEnabledChanged(); void iceEnabledChanged();
void avpfEnabledChanged(); void avpfEnabledChanged();
@ -223,22 +198,16 @@ signals:
void removed(); void removed();
void isSavedChanged(); void isSavedChanged();
void voicemailAddressChanged(); void voicemailAddressChanged();
void presenceChanged();
void ccmpServerUrlChanged();
void setValueFailed(const QString &error);
// Account requests // Account requests
void lSetPictureUri(QString pictureUri); void lSetPictureUri(QString pictureUri);
void lSetDefaultAccount(); void lSetDefaultAccount();
void lResetMissedCalls(); void lResetMissedCalls();
void lResetUnreadMessages();
void lRefreshNotifications(); void lRefreshNotifications();
void lSetDisplayName(QString displayName); void lSetDisplayName(QString displayName);
void lSetDialPlan(QVariantMap internationalPrefix); void lSetDialPlan(QVariantMap internationalPrefix);
void lSetRegisterEnabled(bool enabled); void lSetRegisterEnabled(bool enabled);
void lSetNotificationsAllowed(bool value); void lSetNotificationsAllowed(bool value);
void lSetPresence(LinphoneEnums::Presence presence, bool userInitiated = true, bool resetToAuto = false);
protected: protected:
void writeIntoModel(std::shared_ptr<AccountModel> model) const; void writeIntoModel(std::shared_ptr<AccountModel> model) const;
@ -262,8 +231,8 @@ private:
QString mMwiServerAddress; QString mMwiServerAddress;
QString mTransport; QString mTransport;
QStringList mTransports; QStringList mTransports;
QString mRegistrarUri; QString mServerAddress;
QString mOutboundProxyUri; bool mOutboundProxyEnabled;
QString mStunServer; QString mStunServer;
bool mIceEnabled; bool mIceEnabled;
bool mAvpfEnabled; bool mAvpfEnabled;
@ -273,14 +242,8 @@ private:
QString mAudioVideoConferenceFactoryAddress; QString mAudioVideoConferenceFactoryAddress;
QString mLimeServerUrl; QString mLimeServerUrl;
QString mVoicemailAddress; QString mVoicemailAddress;
QString mCcmpServerUrl;
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined;
LinphoneEnums::Presence mExplicitPresence;
QString mPresenceNote;
int mMaxPresenceNoteSize;
bool mIsSaved = true; bool mIsSaved = true;
std::shared_ptr<AccountModel> mAccountModel; std::shared_ptr<AccountModel> mAccountModel;
QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection; QSharedPointer<SafeConnection<AccountCore, AccountModel>> mAccountModelConnection;
QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<AccountCore, CoreModel>> mCoreModelConnection;

View file

@ -69,14 +69,16 @@ void AccountDeviceList::setAccount(const QSharedPointer<AccountCore> &accountCor
mAccountCore = accountCore; mAccountCore = accountCore;
lDebug() << log().arg("Set account model") << mAccountCore.get(); lDebug() << log().arg("Set account model") << mAccountCore.get();
// oldConnect.unlock(); // oldConnect.unlock();
if (mAccountCore) refreshDevices(); refreshDevices();
// } // }
} }
} }
void AccountDeviceList::refreshDevices() { void AccountDeviceList::refreshDevices() {
mustBeInMainThread(log().arg(Q_FUNC_INFO)); mustBeInMainThread(log().arg(Q_FUNC_INFO));
resetData(); beginResetModel();
clearData();
endResetModel();
if (mAccountCore) { if (mAccountCore) {
auto requestDeviceList = [this] { auto requestDeviceList = [this] {
if (!mAccountManagerServicesModelConnection) return; if (!mAccountManagerServicesModelConnection) return;
@ -148,14 +150,14 @@ void AccountDeviceList::setSelf(QSharedPointer<AccountDeviceList> me) {
&AccountManagerServicesModel::requestError, &AccountManagerServicesModel::requestError,
[this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode, [this](const std::shared_ptr<const linphone::AccountManagerServicesRequest> &request, int statusCode,
const std::string &errorMessage, const std::string &errorMessage,
const std::shared_ptr<const linphone::Dictionary> &parameterErrors) { const std::shared_ptr<const linphone::Dictionary> &parameterErrors) {
lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType()); lDebug() << "REQUEST ERROR" << errorMessage << "/" << int(request->getType());
QString message = QString::fromStdString(errorMessage); QString message = QString::fromStdString(errorMessage);
if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) { if (request->getType() == linphone::AccountManagerServicesRequest::Type::GetDevicesList) {
//: "Erreur lors de la récupération des appareils" //: "Erreur lors de la récupération des appareils"
message = tr("manage_account_no_device_found_error_message"); message = tr("manage_account_no_device_found_error_message");
} }
emit requestError(message); emit requestError(message);
}); });
mAccountManagerServicesModelConnection->makeConnectToModel( mAccountManagerServicesModelConnection->makeConnectToModel(
&AccountManagerServicesModel::devicesListFetched, &AccountManagerServicesModel::devicesListFetched,

View file

@ -21,9 +21,9 @@
#ifndef ACCOUNT_DEVICE_LIST_H_ #ifndef ACCOUNT_DEVICE_LIST_H_
#define ACCOUNT_DEVICE_LIST_H_ #define ACCOUNT_DEVICE_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "AccountDeviceCore.hpp" #include "AccountDeviceCore.hpp"
#include "core/account/AccountGui.hpp" #include "core/account/AccountGui.hpp"
#include "core/proxy/ListProxy.hpp"
#include "model/account/AccountManagerServicesModel.hpp" #include "model/account/AccountManagerServicesModel.hpp"
#include "tool/AbstractObject.hpp" #include "tool/AbstractObject.hpp"
#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeConnection.hpp"

View file

@ -61,11 +61,6 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
auto model = AccountCore::create(it); auto model = AccountCore::create(it);
if (it == defaultAccount) defaultAccountCore = model; if (it == defaultAccount) defaultAccountCore = model;
accounts->push_back(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]() { mModelConnection->invokeToCore([this, accounts, defaultAccountCore, isInitialization]() {
mustBeInMainThread(getClassName()); mustBeInMainThread(getClassName());
@ -73,14 +68,8 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
setHaveAccount(accounts->size() > 0); setHaveAccount(accounts->size() > 0);
setDefaultAccount(defaultAccountCore); setDefaultAccount(defaultAccountCore);
if (isInitialization) setInitialized(true); 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; delete accounts;
}); });
// Update notification count at startup
if (isInitialization) emit unreadNotificationsChanged();
}); });
}); });
mModelConnection->makeConnectToModel( mModelConnection->makeConnectToModel(
@ -99,8 +88,7 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
// with the open id account // with the open id account
mModelConnection->makeConnectToModel(&CoreModel::bearerAccountAdded, [this] { mModelConnection->makeConnectToModel(&CoreModel::bearerAccountAdded, [this] {
setInitialized(false); setInitialized(false);
emit lUpdate(true); emit lUpdate(true); });
});
mModelConnection->makeConnectToModel( mModelConnection->makeConnectToModel(
&CoreModel::globalStateChanged, &CoreModel::globalStateChanged,
@ -170,18 +158,6 @@ 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 { QVariant AccountList::data(const QModelIndex &index, int role) const {
int row = index.row(); int row = index.row();
if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant(); if (!index.isValid() || row < 0 || row >= mList.count()) return QVariant();

View file

@ -51,8 +51,6 @@ public:
bool isInitialized() const; bool isInitialized() const;
void setInitialized(bool init); 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; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals: signals:
@ -60,7 +58,6 @@ signals:
void haveAccountChanged(); void haveAccountChanged();
void defaultAccountChanged(); void defaultAccountChanged();
void initializedChanged(bool init); void initializedChanged(bool init);
void unreadNotificationsChanged();
private: private:
bool mHaveAccount = false; bool mHaveAccount = false;

View file

@ -73,11 +73,8 @@ void CarddavCore::remove() {
void CarddavCore::setSelf(QSharedPointer<CarddavCore> me) { void CarddavCore::setSelf(QSharedPointer<CarddavCore> me) {
mCarddavModelConnection = SafeConnection<CarddavCore, CarddavModel>::create(me, mCarddavModel); mCarddavModelConnection = SafeConnection<CarddavCore, CarddavModel>::create(me, mCarddavModel);
mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success, QString message) { mCarddavModelConnection->makeConnectToModel(&CarddavModel::saved, [this](bool success) {
mCarddavModelConnection->invokeToCore([this, success, message]() { mCarddavModelConnection->invokeToCore([this, success]() { emit saved(success); });
if (success) emit App::getInstance() -> getSettings()->cardDAVAddressBookSynchronized();
emit saved(success, message);
});
}); });
} }

View file

@ -50,7 +50,7 @@ public:
DECLARE_CORE_MEMBER(bool, storeNewFriendsInIt, StoreNewFriendsInIt) DECLARE_CORE_MEMBER(bool, storeNewFriendsInIt, StoreNewFriendsInIt)
signals: signals:
void saved(bool success, QString message); void saved(bool success);
private: private:
std::shared_ptr<CarddavModel> mCarddavModel; std::shared_ptr<CarddavModel> mCarddavModel;

View file

@ -46,7 +46,8 @@ CallHistoryCore::CallHistoryCore(const std::shared_ptr<linphone::CallLog> &callL
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
mCallHistoryModel = std::make_shared<CallHistoryModel>(callLog); mCallHistoryModel = std::make_shared<CallHistoryModel>(callLog);
auto addr = callLog->getRemoteAddress(); auto addr = callLog->getRemoteAddress()->clone();
addr->clean();
mStatus = LinphoneEnums::fromLinphone(callLog->getStatus()); mStatus = LinphoneEnums::fromLinphone(callLog->getStatus());
mDate = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000); mDate = QDateTime::fromMSecsSinceEpoch(callLog->getStartDate() * 1000);
mIsOutgoing = callLog->getDir() == linphone::Call::Dir::Outgoing; mIsOutgoing = callLog->getDir() == linphone::Call::Dir::Outgoing;
@ -128,16 +129,14 @@ void CallHistoryCore::setSelf(QSharedPointer<CallHistoryCore> me) {
mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved, &CallHistoryCore::onRemoved); mCoreModelConnection->makeConnectToModel(&CoreModel::friendRemoved, &CallHistoryCore::onRemoved);
// Update display name when display name has been requested from magic search cause not found in linphone friends // 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) // (required to get the right display name if ldap friends cleared)
// This replace the display name set by a user by a default one, use the linphone address to mCoreModelConnection->makeConnectToModel(&CoreModel::magicSearchResultReceived, [this, remoteAddress = mRemoteAddress] {
// get a correct display name auto displayName = ToolModel::getDisplayName(remoteAddress);
// mCoreModelConnection->makeConnectToModel(&CoreModel::magicSearchResultReceived, mCoreModelConnection->invokeToCore([this, displayName]() {
// [this, remoteAddress = mRemoteAddress] { mDisplayName = displayName;
// auto displayName = ToolModel::getDisplayName(remoteAddress); emit displayNameChanged();
// mCoreModelConnection->invokeToCore([this, displayName]() { });
// mDisplayName = displayName; });
// emit displayNameChanged();
// });
// });
} }
ConferenceInfoGui *CallHistoryCore::getConferenceInfoGui() const { ConferenceInfoGui *CallHistoryCore::getConferenceInfoGui() const {

View file

@ -57,12 +57,10 @@ void CallHistoryList::setSelf(QSharedPointer<CallHistoryList> me) {
mModelConnection = SafeConnection<CallHistoryList, CoreModel>::create(me, CoreModel::getInstance()); mModelConnection = SafeConnection<CallHistoryList, CoreModel>::create(me, CoreModel::getInstance());
mModelConnection->makeConnectToCore(&CallHistoryList::lUpdate, [this]() { mModelConnection->makeConnectToCore(&CallHistoryList::lUpdate, [this]() {
clearData();
emit listAboutToBeReset();
mModelConnection->invokeToModel([this]() { mModelConnection->invokeToModel([this]() {
mustBeInLinphoneThread(getClassName());
// Avoid copy to lambdas // Avoid copy to lambdas
QList<QSharedPointer<CallHistoryCore>> *callLogs = new QList<QSharedPointer<CallHistoryCore>>(); QList<QSharedPointer<CallHistoryCore>> *callLogs = new QList<QSharedPointer<CallHistoryCore>>();
mustBeInLinphoneThread(getClassName());
std::list<std::shared_ptr<linphone::CallLog>> linphoneCallLogs; std::list<std::shared_ptr<linphone::CallLog>> linphoneCallLogs;
if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) { if (auto account = CoreModel::getInstance()->getCore()->getDefaultAccount()) {
linphoneCallLogs = account->getCallLogs(); linphoneCallLogs = account->getCallLogs();

View file

@ -62,7 +62,6 @@ signals:
void lUpdate(); void lUpdate();
void lRemoveEntriesForAddress(QString address); void lRemoveEntriesForAddress(QString address);
void lRemoveAllEntries(); void lRemoveAllEntries();
void listAboutToBeReset();
private: private:
// Check the state from CallHistoryCore: sender() must be a CallHistoryCore. // Check the state from CallHistoryCore: sender() must be a CallHistoryCore.

View file

@ -27,7 +27,6 @@ DEFINE_ABSTRACT_OBJECT(CallHistoryProxy)
CallHistoryProxy::CallHistoryProxy(QObject *parent) : LimitProxy(parent) { CallHistoryProxy::CallHistoryProxy(QObject *parent) : LimitProxy(parent) {
mHistoryList = CallHistoryList::create(); mHistoryList = CallHistoryList::create();
connect(mHistoryList.get(), &CallHistoryList::listAboutToBeReset, this, &CallHistoryProxy::listAboutToBeReset);
setSourceModels(new SortFilterList(mHistoryList.get(), Qt::DescendingOrder)); setSourceModels(new SortFilterList(mHistoryList.get(), Qt::DescendingOrder));
connect(App::getInstance(), &App::currentDateChanged, this, [this] { emit mHistoryList->lUpdate(); }); connect(App::getInstance(), &App::currentDateChanged, this, [this] { emit mHistoryList->lUpdate(); });
} }
@ -57,7 +56,7 @@ bool CallHistoryProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QMo
QRegularExpression::CaseInsensitiveOption | QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption); QRegularExpression::UseUnicodePropertiesOption);
auto callLog = getItemAtSource<CallHistoryList, CallHistoryCore>(sourceRow); auto callLog = getItemAtSource<CallHistoryList, CallHistoryCore>(sourceRow);
show = callLog && (callLog->mDisplayName.contains(search) || callLog->mRemoteAddress.contains(search)); show = callLog->mDisplayName.contains(search) || callLog->mRemoteAddress.contains(search);
} }
return show; return show;
} }

View file

@ -41,9 +41,6 @@ public:
Q_INVOKABLE void removeEntriesWithFilter(QString filter); Q_INVOKABLE void removeEntriesWithFilter(QString filter);
Q_INVOKABLE void reload(); Q_INVOKABLE void reload();
signals:
void listAboutToBeReset();
protected: protected:
QSharedPointer<CallHistoryList> mHistoryList; QSharedPointer<CallHistoryList> mHistoryList;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010-2026 Belledonne Communications SARL. * Copyright (c) 2010-2024 Belledonne Communications SARL.
* *
* This file is part of linphone-desktop * This file is part of linphone-desktop
* (see https://www.linphone.org). * (see https://www.linphone.org).
@ -28,8 +28,6 @@
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeConnection.hpp"
#include <QQuickWindow>
DEFINE_ABSTRACT_OBJECT(CallCore) DEFINE_ABSTRACT_OBJECT(CallCore)
/***********************************************************************/ /***********************************************************************/
@ -109,17 +107,18 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
mCallModel->setSelf(mCallModel); mCallModel->setSelf(mCallModel);
mDuration = call->getDuration(); mDuration = call->getDuration();
mIsStarted = mDuration > 0; mIsStarted = mDuration > 0;
auto callParams = call->getParams(); mMicrophoneMuted = call->getMicrophoneMuted();
auto videoDirection = callParams->getVideoDirection(); mSpeakerMuted = call->getSpeakerMuted();
auto videoDirection = call->getParams()->getVideoDirection();
mLocalVideoEnabled = mLocalVideoEnabled =
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv; videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
mCameraEnabled = callParams->cameraEnabled();
auto remoteParams = call->getRemoteParams(); auto remoteParams = call->getRemoteParams();
videoDirection = remoteParams ? remoteParams->getVideoDirection() : linphone::MediaDirection::Inactive; videoDirection = remoteParams ? remoteParams->getVideoDirection() : linphone::MediaDirection::Inactive;
mRemoteVideoEnabled = mRemoteVideoEnabled =
videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv; videoDirection == linphone::MediaDirection::SendOnly || videoDirection == linphone::MediaDirection::SendRecv;
mState = LinphoneEnums::fromLinphone(call->getState()); mState = LinphoneEnums::fromLinphone(call->getState());
auto remoteAddress = call->getCallLog()->getRemoteAddress(); auto remoteAddress = call->getCallLog()->getRemoteAddress()->clone();
remoteAddress->clean();
mRemoteAddress = Utils::coreStringToAppString(remoteAddress->asStringUriOnly()); mRemoteAddress = Utils::coreStringToAppString(remoteAddress->asStringUriOnly());
mRemoteUsername = Utils::coreStringToAppString(remoteAddress->getUsername()); mRemoteUsername = Utils::coreStringToAppString(remoteAddress->getUsername());
auto linphoneFriend = ToolModel::findFriendByAddress(remoteAddress); auto linphoneFriend = ToolModel::findFriendByAddress(remoteAddress);
@ -137,7 +136,7 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
mTransferState = LinphoneEnums::fromLinphone(call->getTransferState()); mTransferState = LinphoneEnums::fromLinphone(call->getTransferState());
mLocalToken = Utils::coreStringToAppString(mCallModel->getLocalAtuhenticationToken()); mLocalToken = Utils::coreStringToAppString(mCallModel->getLocalAtuhenticationToken());
mRemoteTokens = mCallModel->getRemoteAtuhenticationTokens(); mRemoteTokens = mCallModel->getRemoteAtuhenticationTokens();
mEncryption = LinphoneEnums::fromLinphone(callParams->getMediaEncryption()); mEncryption = LinphoneEnums::fromLinphone(call->getParams()->getMediaEncryption());
auto tokenVerified = call->getAuthenticationTokenVerified(); auto tokenVerified = call->getAuthenticationTokenVerified();
mIsMismatch = call->getZrtpCacheMismatchFlag(); mIsMismatch = call->getZrtpCacheMismatchFlag();
mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) || mIsSecured = (mEncryption == LinphoneEnums::MediaEncryption::Zrtp && tokenVerified) ||
@ -159,12 +158,10 @@ CallCore::CallCore(const std::shared_ptr<linphone::Call> &call) : QObject(nullpt
if (mIsConference) { if (mIsConference) {
mConference = ConferenceCore::create(conference); mConference = ConferenceCore::create(conference);
} }
mMicrophoneMuted = conference ? conference->getMicrophoneMuted() : call->getMicrophoneMuted();
mSpeakerMuted = call->getSpeakerMuted();
mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused || mPaused = mState == LinphoneEnums::CallState::Pausing || mState == LinphoneEnums::CallState::Paused ||
mState == LinphoneEnums::CallState::PausedByRemote; mState == LinphoneEnums::CallState::PausedByRemote;
mRecording = callParams && callParams->isRecording(); mRecording = call->getParams() && call->getParams()->isRecording();
mRemoteRecording = call->getRemoteParams() && call->getRemoteParams()->isRecording(); mRemoteRecording = call->getRemoteParams() && call->getRemoteParams()->isRecording();
auto settingsModel = SettingsModel::getInstance(); auto settingsModel = SettingsModel::getInstance();
mMicrophoneVolume = call->getRecordVolume(); mMicrophoneVolume = call->getRecordVolume();
@ -197,8 +194,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mCallModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) { mCallModelConnection->makeConnectToModel(&CallModel::speakerMutedChanged, [this](bool isMuted) {
mCallModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); }); mCallModelConnection->invokeToCore([this, isMuted]() { setSpeakerMuted(isMuted); });
}); });
mCallModelConnection->makeConnectToCore(&CallCore::lSetCameraEnabled, [this](bool enabled) { mCallModelConnection->makeConnectToCore(&CallCore::lSetLocalVideoEnabled, [this](bool enabled) {
mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setCameraEnabled(enabled); }); mCallModelConnection->invokeToModel([this, enabled]() { mCallModel->setLocalVideoEnabled(enabled); });
}); });
mCallModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() { mCallModelConnection->makeConnectToCore(&CallCore::lStartRecording, [this]() {
mCallModelConnection->invokeToModel([this]() { mCallModel->startRecording(); }); mCallModelConnection->invokeToModel([this]() { mCallModel->startRecording(); });
@ -208,15 +205,14 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
}); });
mCallModelConnection->makeConnectToModel( mCallModelConnection->makeConnectToModel(
&CallModel::recordingChanged, [this](const std::shared_ptr<linphone::Call> &call, bool recording) { &CallModel::recordingChanged, [this](const std::shared_ptr<linphone::Call> &call, bool recording) {
auto recordFile = QString::fromStdString(mCallModel->getRecordFile()); mCallModelConnection->invokeToCore([this, recording]() {
mCallModelConnection->invokeToCore([this, recording, recordFile]() {
setRecording(recording); setRecording(recording);
if (recording == false) { if (recording == false) {
//: "Enregistrement terminé" //: "Enregistrement terminé"
Utils::showInformationPopup(tr("call_record_end_message"), Utils::showInformationPopup(tr("call_record_end_message"),
//: "L'appel a été enregistré dans le fichier : %1" //: "L'appel a été enregistré dans le fichier : %1"
tr("call_record_saved_in_file_message").arg(recordFile), true, tr("call_record_saved_in_file_message").arg(QString::fromStdString(mCallModel->getRecordFile())),
App::getInstance()->getOrCreateCallsWindow()); true, App::getInstance()->getCallsWindow());
} }
}); });
}); });
@ -248,9 +244,6 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mCallModelConnection->makeConnectToModel(&CallModel::localVideoEnabledChanged, [this](bool enabled) { mCallModelConnection->makeConnectToModel(&CallModel::localVideoEnabledChanged, [this](bool enabled) {
mCallModelConnection->invokeToCore([this, enabled]() { setLocalVideoEnabled(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->makeConnectToModel(&CallModel::durationChanged, [this](int duration) {
mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); }); mCallModelConnection->invokeToCore([this, duration]() { setDuration(duration); });
}); });
@ -268,7 +261,6 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
bool isConf = call && call->getConference() != nullptr; bool isConf = call && call->getConference() != nullptr;
auto subject = call->getConference() ? Utils::coreStringToAppString(call->getConference()->getSubject()) : ""; auto subject = call->getConference() ? Utils::coreStringToAppString(call->getConference()->getSubject()) : "";
mCallModelConnection->invokeToCore([this, state, subject, isConf]() { mCallModelConnection->invokeToCore([this, state, subject, isConf]() {
lDebug() << log().arg("::onStateChanged") << LinphoneEnums::fromLinphone(state);
setRecordable(state == linphone::Call::State::StreamsRunning); setRecordable(state == linphone::Call::State::StreamsRunning);
setPaused(state == linphone::Call::State::Paused || state == linphone::Call::State::PausedByRemote); setPaused(state == linphone::Call::State::Paused || state == linphone::Call::State::PausedByRemote);
if (mConference) mConference->setSubject(subject); if (mConference) mConference->setSubject(subject);
@ -316,8 +308,8 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
[this, call, encryption, tokenVerified, localToken, remoteTokens, isCaseMismatch]() { [this, call, encryption, tokenVerified, localToken, remoteTokens, isCaseMismatch]() {
setLocalToken(localToken); setLocalToken(localToken);
setRemoteTokens(remoteTokens); setRemoteTokens(remoteTokens);
setIsMismatch(isCaseMismatch); setIsMismatch(isCaseMismatch);
setTokenVerified(tokenVerified); setTokenVerified(tokenVerified);
setEncryption(encryption); setEncryption(encryption);
}); });
auto mediaEncryption = call->getParams()->getMediaEncryption(); auto mediaEncryption = call->getParams()->getMediaEncryption();
@ -329,7 +321,7 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
zrtpStats.mHashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo()); zrtpStats.mHashAlgorithm = Utils::coreStringToAppString(stats->getZrtpHashAlgo());
zrtpStats.mAuthenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo()); zrtpStats.mAuthenticationAlgorithm = Utils::coreStringToAppString(stats->getZrtpAuthTagAlgo());
zrtpStats.mSasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo()); zrtpStats.mSasAlgorithm = Utils::coreStringToAppString(stats->getZrtpSasAlgo());
zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum(); zrtpStats.mIsPostQuantum = stats->isZrtpKeyAgreementAlgoPostQuantum();
mCallModelConnection->invokeToCore([this, zrtpStats]() { setZrtpStats(zrtpStats); }); mCallModelConnection->invokeToCore([this, zrtpStats]() { setZrtpStats(zrtpStats); });
} }
}); });
@ -351,8 +343,6 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
}); });
mCallModelConnection->makeConnectToModel(&CallModel::conferenceChanged, [this]() { mCallModelConnection->makeConnectToModel(&CallModel::conferenceChanged, [this]() {
auto conference = mCallModel->getMonitor()->getConference(); 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; QSharedPointer<ConferenceCore> core = conference ? ConferenceCore::create(conference) : nullptr;
mCallModelConnection->invokeToCore([this, core]() { setConference(core); }); mCallModelConnection->invokeToCore([this, core]() { setConference(core); });
}); });
@ -398,23 +388,23 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
auto codecType = playloadType ? playloadType->getMimeType() : ""; auto codecType = playloadType ? playloadType->getMimeType() : "";
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0; auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
audioStats.mCodec = audioStats.mCodec =
//: "Codec: %1 / %2 kHz" //: "Codec: %1 / %2 kHz"
tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate); tr("call_stats_codec_label").arg(Utils::coreStringToAppString(codecType)).arg(codecRate);
auto linAudioStats = call->getAudioStats(); auto linAudioStats = call->getAudioStats();
if (linAudioStats) { if (linAudioStats) {
//: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s" //: "Bande passante : %1 %2 kbits/s %3 %4 kbits/s"
audioStats.mBandwidth = tr("call_stats_bandwidth_label") audioStats.mBandwidth = tr("call_stats_bandwidth_label")
.arg("") .arg("")
.arg(round(linAudioStats->getUploadBandwidth())) .arg(round(linAudioStats->getUploadBandwidth()))
.arg("") .arg("")
.arg(round(linAudioStats->getDownloadBandwidth())); .arg(round(linAudioStats->getDownloadBandwidth()));
//: "Taux de perte: %1% %2%" //: "Taux de perte: %1% %2%"
audioStats.mLossRate = tr("call_stats_loss_rate_label") audioStats.mLossRate = tr("call_stats_loss_rate_label")
.arg(linAudioStats->getSenderLossRate()) .arg(linAudioStats->getSenderLossRate())
.arg(linAudioStats->getReceiverLossRate()); .arg(linAudioStats->getReceiverLossRate());
//: "Tampon de gigue: %1 ms" //: "Tampon de gigue: %1 ms"
audioStats.mJitterBufferSize = audioStats.mJitterBufferSize =
tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs()); tr("call_stats_jitter_buffer_label").arg(linAudioStats->getJitterBufferSizeMs());
} }
setAudioStats(audioStats); setAudioStats(audioStats);
} else if (stats->getType() == linphone::StreamType::Video) { } else if (stats->getType() == linphone::StreamType::Video) {
@ -424,15 +414,15 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
auto codecType = playloadType ? playloadType->getMimeType() : ""; auto codecType = playloadType ? playloadType->getMimeType() : "";
auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0; auto codecRate = playloadType ? playloadType->getClockRate() / 1000 : 0;
videoStats.mCodec = 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(); auto linVideoStats = call->getVideoStats();
if (stats) { if (stats) {
videoStats.mBandwidth = tr("call_stats_bandwidth_label") videoStats.mBandwidth = tr("call_stats_bandwidth_label")
.arg("") .arg("")
.arg(round(linVideoStats->getUploadBandwidth())) .arg(round(linVideoStats->getUploadBandwidth()))
.arg("") .arg("")
.arg(round(linVideoStats->getDownloadBandwidth())); .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->getSenderLossRate())
.arg(linVideoStats->getReceiverLossRate()); .arg(linVideoStats->getReceiverLossRate());
} }
@ -440,55 +430,17 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
params->getSentVideoDefinition() ? params->getSentVideoDefinition()->getName() : ""; params->getSentVideoDefinition() ? params->getSentVideoDefinition()->getName() : "";
auto receivedResolution = auto receivedResolution =
params->getReceivedVideoDefinition() ? params->getReceivedVideoDefinition()->getName() : ""; params->getReceivedVideoDefinition() ? params->getReceivedVideoDefinition()->getName() : "";
//: "Définition vidéo : %1 %2 %3 %4" //: "Définition vidéo : %1 %2 %3 %4"
videoStats.mResolution = tr("call_stats_resolution_label") videoStats.mResolution = tr("call_stats_resolution_label")
.arg("", Utils::coreStringToAppString(sentResolution), "", .arg("", Utils::coreStringToAppString(sentResolution), "",
Utils::coreStringToAppString(receivedResolution)); Utils::coreStringToAppString(receivedResolution));
auto sentFps = params->getSentFramerate(); auto sentFps = params->getSentFramerate();
auto receivedFps = params->getReceivedFramerate(); auto receivedFps = params->getReceivedFramerate();
//: "FPS : %1 %2 %3 %4" //: "FPS : %1 %2 %3 %4"
videoStats.mFps = tr("call_stats_fps_label").arg("").arg(sentFps).arg("").arg(receivedFps); videoStats.mFps = tr("call_stats_fps_label").arg("").arg(sentFps).arg("").arg(receivedFps);
setVideoStats(videoStats); 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); if (mShouldFindRemoteFriend) findRemoteFriend(me);
} }
@ -605,18 +557,6 @@ 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 { bool CallCore::getPaused() const {
return mPaused; return mPaused;
} }

View file

@ -117,8 +117,8 @@ public:
Q_PROPERTY(QStringList remoteTokens WRITE setRemoteTokens MEMBER mRemoteTokens NOTIFY remoteTokensChanged) Q_PROPERTY(QStringList remoteTokens WRITE setRemoteTokens MEMBER mRemoteTokens NOTIFY remoteTokensChanged)
Q_PROPERTY( Q_PROPERTY(
bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged) bool remoteVideoEnabled READ getRemoteVideoEnabled WRITE setRemoteVideoEnabled NOTIFY remoteVideoEnabledChanged)
Q_PROPERTY(bool localVideoEnabled READ getLocalVideoEnabled NOTIFY localVideoEnabledChanged) Q_PROPERTY(
Q_PROPERTY(bool cameraEnabled READ getCameraEnabled WRITE lSetCameraEnabled NOTIFY cameraEnabledChanged) bool localVideoEnabled READ getLocalVideoEnabled WRITE lSetLocalVideoEnabled NOTIFY localVideoEnabledChanged)
Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged) Q_PROPERTY(bool recording READ getRecording WRITE setRecording NOTIFY recordingChanged)
Q_PROPERTY(bool remoteRecording READ getRemoteRecording WRITE setRemoteRecording NOTIFY remoteRecordingChanged) Q_PROPERTY(bool remoteRecording READ getRemoteRecording WRITE setRemoteRecording NOTIFY remoteRecordingChanged)
Q_PROPERTY(bool recordable READ getRecordable WRITE setRecordable NOTIFY recordableChanged) Q_PROPERTY(bool recordable READ getRecordable WRITE setRecordable NOTIFY recordableChanged)
@ -201,9 +201,6 @@ public:
bool getLocalVideoEnabled() const; bool getLocalVideoEnabled() const;
void setLocalVideoEnabled(bool enabled); void setLocalVideoEnabled(bool enabled);
bool getCameraEnabled() const;
void setCameraEnabled(bool enabled);
bool getRecording() const; bool getRecording() const;
void setRecording(bool recording); void setRecording(bool recording);
@ -258,7 +255,6 @@ signals:
void remoteTokensChanged(); void remoteTokensChanged();
void remoteVideoEnabledChanged(bool remoteVideoEnabled); void remoteVideoEnabledChanged(bool remoteVideoEnabled);
void localVideoEnabledChanged(); void localVideoEnabledChanged();
void cameraEnabledChanged();
void recordingChanged(); void recordingChanged();
void remoteRecordingChanged(); void remoteRecordingChanged();
void recordableChanged(); void recordableChanged();
@ -279,7 +275,7 @@ signals:
void lTerminateAllCalls(); // Hangup all calls void lTerminateAllCalls(); // Hangup all calls
void lSetSpeakerMuted(bool muted); void lSetSpeakerMuted(bool muted);
void lSetMicrophoneMuted(bool isMuted); void lSetMicrophoneMuted(bool isMuted);
void lSetCameraEnabled(bool enabled); void lSetLocalVideoEnabled(bool enabled);
void lSetVideoEnabled(bool enabled); void lSetVideoEnabled(bool enabled);
void lSetPaused(bool paused); void lSetPaused(bool paused);
void lTransferCall(QString address); void lTransferCall(QString address);
@ -335,7 +331,6 @@ private:
bool mSpeakerMuted = false; bool mSpeakerMuted = false;
bool mMicrophoneMuted = false; bool mMicrophoneMuted = false;
bool mLocalVideoEnabled = false; bool mLocalVideoEnabled = false;
bool mCameraEnabled = false;
bool mVideoEnabled = false; bool mVideoEnabled = false;
bool mPaused = false; bool mPaused = false;
bool mRemoteVideoEnabled = false; bool mRemoteVideoEnabled = false;

View file

@ -22,7 +22,6 @@
#include "CallCore.hpp" #include "CallCore.hpp"
#include "CallGui.hpp" #include "CallGui.hpp"
#include "core/App.hpp" #include "core/App.hpp"
#include "model/tool/ToolModel.hpp"
#include <QSharedPointer> #include <QSharedPointer>
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
@ -97,32 +96,40 @@ void CallList::setSelf(QSharedPointer<CallList> me) {
bool enablingVideo = false; bool enablingVideo = false;
if (currentCall) enablingVideo = currentCall->getCurrentParams()->videoEnabled(); if (currentCall) enablingVideo = currentCall->getCurrentParams()->videoEnabled();
if (!conference) { if (!conference) {
auto parameters = core->createConferenceParams(conference);
auto audioVideoConfFactoryUri = auto audioVideoConfFactoryUri =
core->getDefaultAccount()->getParams()->getAudioVideoConferenceFactoryAddress(); core->getDefaultAccount()->getParams()->getAudioVideoConferenceFactoryAddress();
QString subject = audioVideoConfFactoryUri if (audioVideoConfFactoryUri) {
//: Remote group call parameters->setConferenceFactoryAddress(audioVideoConfFactoryUri);
? tr("remote_group_call") parameters->setSubject("Meeting");
//: "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 { } else {
conference->addParticipants(currentCalls); 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);
} }
} }
// 1) Add running calls
if (runningCallsToAdd.size() > 0) {
conference->addParticipants(runningCallsToAdd);
}
// emit lUpdate(); // emit lUpdate();
}); });
}); });
mModelConnection->makeConnectToModel(&CoreModel::firstCallStarted, mModelConnection->makeConnectToModel(&CoreModel::firstCallStarted,
[this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); }); [this]() { mModelConnection->invokeToCore([this]() { lUpdate(); }); });
mModelConnection->makeConnectToModel(&CoreModel::lastCallEnded, [this]() { mModelConnection->makeConnectToModel(&CoreModel::lastCallEnded, [this]() {
mModelConnection->invokeToCore([this]() { mModelConnection->invokeToCore([this]() {
setHaveCall(false); setHaveCall(false);
@ -151,8 +158,12 @@ CallGui *CallList::getCurrentCall() const {
else return nullptr; else return nullptr;
} }
void CallList::setCurrentCall(CallGui *callGui) { void CallList::setCurrentCall(CallGui* callGui) {
setCurrentCallCore(callGui ? callGui->mCore : nullptr); auto callCore = callGui ? callGui->mCore : nullptr;
if (mCurrentCall != callCore) {
mCurrentCall = callCore;
emit currentCallChanged();
}
} }
void CallList::setCurrentCallCore(QSharedPointer<CallCore> call) { void CallList::setCurrentCallCore(QSharedPointer<CallCore> call) {
@ -173,21 +184,16 @@ void CallList::setHaveCall(bool haveCall) {
} }
} }
QSharedPointer<CallCore> CallList::getNextCall() { QSharedPointer<CallCore> CallList::getNextCall() const {
QSharedPointer<CallCore> call;
auto currentCall = getCurrentCallCore(); auto currentCall = getCurrentCallCore();
for (auto &item : getSharedList<CallCore>()) { for (auto it = mList.rbegin(); !call && it != mList.rend(); ++it) {
if (item != currentCall) return item; if (*it != currentCall) {
call = it->objectCast<CallCore>();
}
} }
return nullptr;
}
QSharedPointer<CallCore> CallList::getFirstIncommingPendingCall() { return call;
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() { void CallList::onStateChanged() {
@ -196,26 +202,21 @@ void CallList::onStateChanged() {
case LinphoneEnums::CallState::StreamsRunning: case LinphoneEnums::CallState::StreamsRunning:
case LinphoneEnums::CallState::Resuming: { case LinphoneEnums::CallState::Resuming: {
auto sharedCall = get(call); auto sharedCall = get(call);
setCurrentCallCore(sharedCall ? sharedCall.objectCast<CallCore>() : nullptr); setCurrentCallCore(sharedCall.objectCast<CallCore>());
break; break;
} }
case LinphoneEnums::CallState::Released: { case LinphoneEnums::CallState::Released: {
auto sharedCall = get(call); auto sharedCall = get(call);
if (sharedCall) { auto currentCall = getCurrentCallCore();
auto currentCall = getCurrentCallCore(); // Update current call
sharedCall->disconnect(this); if (sharedCall == currentCall) {
// Update current call // Unpause the next call. The current call will change on resume.
if (currentCall == sharedCall) { // Assumption: All calls that are not the current are paused.
auto nextCall = getNextCall(); auto nextCall = getNextCall();
if (nextCall) { if (nextCall) nextCall->lSetPaused(false);
// 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; break;
} }
default: { default: {

View file

@ -33,7 +33,7 @@ class CoreModel;
class CallList : public ListProxy, public AbstractObject { class CallList : public ListProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged) Q_PROPERTY(CallGui* currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
public: public:
static QSharedPointer<CallList> create(); static QSharedPointer<CallList> create();
// Create a CallCore and make connections to List. // Create a CallCore and make connections to List.
@ -45,7 +45,7 @@ public:
CallGui *getCurrentCall() const; // Used for Ui CallGui *getCurrentCall() const; // Used for Ui
QSharedPointer<CallCore> getCurrentCallCore() const; QSharedPointer<CallCore> getCurrentCallCore() const;
void setCurrentCall(CallGui *callGui); void setCurrentCall(CallGui* callGui);
void setCurrentCallCore(QSharedPointer<CallCore> call); void setCurrentCallCore(QSharedPointer<CallCore> call);
bool getHaveCall() const; bool getHaveCall() const;
@ -53,9 +53,7 @@ public:
// Get the next call after the current one. Used to switch the current call. // 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. // At the moment, it select the last call in the list.
QSharedPointer<CallCore> getNextCall(); QSharedPointer<CallCore> getNextCall() const;
QSharedPointer<CallCore> getFirstIncommingPendingCall();
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals: signals:

View file

@ -25,32 +25,20 @@
DEFINE_ABSTRACT_OBJECT(CallProxy) DEFINE_ABSTRACT_OBJECT(CallProxy)
CallProxy::CallProxy() : SortFilterProxy() { CallProxy::CallProxy(QObject *parent) : LimitProxy(parent) {
mShowCurrentCall = true;
} }
CallProxy::~CallProxy() { CallProxy::~CallProxy() {
} }
CallGui *CallProxy::getCurrentCall() { CallGui *CallProxy::getCurrentCall() {
auto model = qobject_cast<CallList *>(sourceModel()); auto model = getListModel<CallList>();
if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall(); if (!mCurrentCall && model) mCurrentCall = model->getCurrentCall();
return mCurrentCall; 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) { void CallProxy::setCurrentCall(CallGui *call) {
qobject_cast<CallList *>(sourceModel())->setCurrentCall(call); getListModel<CallList>()->setCurrentCall(call);
} }
// Reset the default account to let UI build its new object if needed. // Reset the default account to let UI build its new object if needed.
@ -60,12 +48,12 @@ void CallProxy::resetCurrentCall() {
} }
bool CallProxy::getHaveCall() const { bool CallProxy::getHaveCall() const {
auto model = qobject_cast<CallList *>(sourceModel()); auto model = getListModel<CallList>();
return model ? model->getHaveCall() : false; return model ? model->getHaveCall() : false;
} }
void CallProxy::setSourceModel(QAbstractItemModel *model) { void CallProxy::setSourceModel(QAbstractItemModel *model) {
auto oldCallList = qobject_cast<CallList *>(sourceModel()); auto oldCallList = getListModel<CallList>();
if (oldCallList) { if (oldCallList) {
disconnect(oldCallList); disconnect(oldCallList);
} }
@ -75,24 +63,24 @@ void CallProxy::setSourceModel(QAbstractItemModel *model) {
connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection); connect(newCallList, &CallList::haveCallChanged, this, &CallProxy::haveCallChanged, Qt::QueuedConnection);
connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll); connect(this, &CallProxy::lMergeAll, newCallList, &CallList::lMergeAll);
} }
QSortFilterProxyModel::setSourceModel(model); setSourceModels(new SortFilterList(model, Qt::AscendingOrder));
} }
bool CallProxy::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { bool CallProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
bool show = (mFilterText.isEmpty() || mFilterText == "*"); 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) { if (!show) {
QRegularExpression search(QRegularExpression::escape(mFilterText), QRegularExpression search(QRegularExpression::escape(mFilterText),
QRegularExpression::CaseInsensitiveOption | QRegularExpression::CaseInsensitiveOption |
QRegularExpression::UseUnicodePropertiesOption); QRegularExpression::UseUnicodePropertiesOption);
auto call = qobject_cast<CallList *>(sourceModel())->getAt<CallCore>(sourceRow);
show = call->getRemoteAddress().contains(search); show = call->getRemoteAddress().contains(search);
} }
return show; return show;
} }
bool CallProxy::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const { bool CallProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const {
auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row()); auto l = getItemAtSource<CallList, CallCore>(sourceLeft.row());
auto r = getItemAtSource<CallList, CallCore>(sourceRight.row()); auto r = getItemAtSource<CallList, CallCore>(sourceRight.row());

View file

@ -28,14 +28,15 @@
// ============================================================================= // =============================================================================
class CallProxy : public SortFilterProxy, public AbstractObject { class CallProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged) Q_PROPERTY(CallGui *currentCall READ getCurrentCall WRITE setCurrentCall NOTIFY currentCallChanged)
Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged) Q_PROPERTY(bool haveCall READ getHaveCall NOTIFY haveCallChanged)
Q_PROPERTY(bool showCurrentCall READ showCurrentCall WRITE setShowCurrentCall NOTIFY showCurrentCallChanged)
public: public:
CallProxy(); DECLARE_SORTFILTER_CLASS()
CallProxy(QObject *parent = Q_NULLPTR);
~CallProxy(); ~CallProxy();
// Get a new object from List or give the stored one. // Get a new object from List or give the stored one.
@ -47,23 +48,15 @@ public:
bool getHaveCall() const; bool getHaveCall() const;
void setShowCurrentCall(bool show);
bool showCurrentCall() const;
void setSourceModel(QAbstractItemModel *sourceModel) override; 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: signals:
void lMergeAll(); void lMergeAll();
void currentCallChanged(); void currentCallChanged();
void haveCallChanged(); void haveCallChanged();
void showCurrentCallChanged();
protected: protected:
CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List CallGui *mCurrentCall = nullptr; // When null, a new UI object is build from List
bool mShowCurrentCall = false;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -71,12 +71,10 @@ QQuickFramebufferObject::Renderer *PreviewManager::subscribe(const CameraGui *ca
App::postModelBlock([&renderer, isFirst = (itCandidate == mCandidates.begin()), App::postModelBlock([&renderer, isFirst = (itCandidate == mCandidates.begin()),
name = itCandidate->first->getQmlName()]() { name = itCandidate->first->getQmlName()]() {
renderer = renderer =
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId( (QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId();
nullptr);
if (!renderer) { // TODO debug if (!renderer) { // TODO debug
renderer = renderer =
(QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId( (QQuickFramebufferObject::Renderer *)CoreModel::getInstance()->getCore()->createNativePreviewWindowId();
nullptr);
} }
if (isFirst) { if (isFirst) {
lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer; lDebug() << "[PreviewManager] " << name << " Set Native Preview Id with " << renderer;

View file

@ -1,686 +0,0 @@
/*
* 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);
});
}
}
}
}

View file

@ -1,236 +0,0 @@
/*
* 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

View file

@ -1,38 +0,0 @@
/*
* 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();
}

View file

@ -1,41 +0,0 @@
/*
* 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

View file

@ -1,209 +0,0 @@
/*
* 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();
}

View file

@ -1,60 +0,0 @@
/*
* 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

View file

@ -1,81 +0,0 @@
/*
* 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;
}

View file

@ -1,50 +0,0 @@
/*
* 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

View file

@ -1,127 +0,0 @@
/*
* 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();
}

View file

@ -1,61 +0,0 @@
/*
* 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

View file

@ -1,65 +0,0 @@
/*
* 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;
}

View file

@ -1,56 +0,0 @@
/*
* 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

View file

@ -1,694 +0,0 @@
/*
* 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);
}

View file

@ -1,246 +0,0 @@
/*
* 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_

View file

@ -1,39 +0,0 @@
/*
* 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();
}

View file

@ -1,41 +0,0 @@
/*
* 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

View file

@ -1,173 +0,0 @@
/*
* 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;
}
}

View file

@ -1,96 +0,0 @@
/*
* 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_

View file

@ -1,38 +0,0 @@
/*
* 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();
}

View file

@ -1,41 +0,0 @@
/*
* 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

View file

@ -1,391 +0,0 @@
/*
* 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;
}

View file

@ -1,88 +0,0 @@
/*
* 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

View file

@ -1,208 +0,0 @@
/*
* 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);
}
}

View file

@ -1,102 +0,0 @@
/*
* 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

View file

@ -1,272 +0,0 @@
/*
* 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;
}

View file

@ -1,138 +0,0 @@
/*
* 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_

View file

@ -1,38 +0,0 @@
/*
* 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();
}

View file

@ -1,41 +0,0 @@
/*
* 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

View file

@ -1,227 +0,0 @@
/*
* 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();
}

View file

@ -1,64 +0,0 @@
/*
* 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

View file

@ -1,103 +0,0 @@
/*
* 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;
}

View file

@ -1,66 +0,0 @@
/*
* 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

View file

@ -1,61 +0,0 @@
/*
* 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();
}

View file

@ -1,51 +0,0 @@
/*
* 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

View file

@ -1,65 +0,0 @@
/*
* 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;
}

View file

@ -1,62 +0,0 @@
/*
* 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

View file

@ -47,12 +47,7 @@ ConferenceCore::ConferenceCore(const std::shared_ptr<linphone::Conference> &conf
mIsLocalScreenSharing = mConferenceModel->isLocalScreenSharing(); mIsLocalScreenSharing = mConferenceModel->isLocalScreenSharing();
mIsScreenSharingEnabled = mConferenceModel->isScreenSharingEnabled(); mIsScreenSharingEnabled = mConferenceModel->isScreenSharingEnabled();
mIsRecording = conference->isRecording(); mIsRecording = conference->isRecording();
if (conference->getCurrentParams()) mIsChatEnabled = conference->getCurrentParams()->chatEnabled();
auto me = conference->getMe(); auto me = conference->getMe();
auto confAddress = conference->getConferenceAddress();
if (confAddress) {
mConfUri = Utils::coreStringToAppString(confAddress->asStringUriOnly());
}
if (me) { if (me) {
mMe = ParticipantCore::create(me); mMe = ParticipantCore::create(me);
} }
@ -80,14 +75,7 @@ void ConferenceCore::setSelf(QSharedPointer<ConferenceCore> me) {
if (newState == linphone::Conference::State::Created) { if (newState == linphone::Conference::State::Created) {
if (auto participantDevice = conference->getActiveSpeakerParticipantDevice()) { if (auto participantDevice = conference->getActiveSpeakerParticipantDevice()) {
auto device = ParticipantDeviceCore::create(participantDevice); auto device = ParticipantDeviceCore::create(participantDevice);
QString address; mConferenceModelConnection->invokeToCore([this, device]() { setActiveSpeakerDevice(device); });
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) { } else if (conference->getParticipantDeviceList().size() > 1) {
for (auto &device : conference->getParticipantDeviceList()) { for (auto &device : conference->getParticipantDeviceList()) {
if (!ToolModel::isMe(device->getAddress())) { if (!ToolModel::isMe(device->getAddress())) {
@ -206,10 +194,6 @@ void ConferenceCore::setIsScreenSharingEnabled(bool state) {
} }
} }
bool ConferenceCore::isChatEnabled() const {
return mIsChatEnabled;
}
std::shared_ptr<ConferenceModel> ConferenceCore::getModel() const { std::shared_ptr<ConferenceModel> ConferenceCore::getModel() const {
return mConferenceModel; return mConferenceModel;
} }

View file

@ -37,14 +37,12 @@ class ConferenceCore : public QObject, public AbstractObject {
Q_OBJECT Q_OBJECT
public: public:
Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT) Q_PROPERTY(QDateTime startDate READ getStartDate CONSTANT)
Q_PROPERTY(bool isChatEnabled READ isChatEnabled CONSTANT)
// Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT) // Q_PROPERTY(ParticipantDeviceList *participantDevices READ getParticipantDeviceList CONSTANT)
// Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged) // Q_PROPERTY(ParticipantModel* localParticipant READ getLocalParticipant NOTIFY localParticipantChanged)
Q_PROPERTY(bool isReady MEMBER mIsReady WRITE setIsReady NOTIFY isReadyChanged) Q_PROPERTY(bool isReady MEMBER mIsReady WRITE setIsReady NOTIFY isReadyChanged)
Q_PROPERTY(bool isRecording READ isRecording WRITE setRecording NOTIFY isRecordingChanged) Q_PROPERTY(bool isRecording READ isRecording WRITE setRecording NOTIFY isRecordingChanged)
Q_PROPERTY(QString subject READ getSubject WRITE setSubject NOTIFY subjectChanged) 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 Q_PROPERTY(bool isLocalScreenSharing MEMBER mIsLocalScreenSharing WRITE setIsLocalScreenSharing NOTIFY
isLocalScreenSharingChanged) isLocalScreenSharingChanged)
Q_PROPERTY(bool isScreenSharingEnabled MEMBER mIsScreenSharingEnabled WRITE setIsScreenSharingEnabled NOTIFY Q_PROPERTY(bool isScreenSharingEnabled MEMBER mIsScreenSharingEnabled WRITE setIsScreenSharingEnabled NOTIFY
@ -82,8 +80,6 @@ public:
void setIsLocalScreenSharing(bool state); void setIsLocalScreenSharing(bool state);
void setIsScreenSharingEnabled(bool state); void setIsScreenSharingEnabled(bool state);
bool isChatEnabled() const;
std::shared_ptr<ConferenceModel> getModel() const; std::shared_ptr<ConferenceModel> getModel() const;
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
@ -96,7 +92,6 @@ signals:
void activeSpeakerDeviceChanged(); void activeSpeakerDeviceChanged();
void subjectChanged(); void subjectChanged();
void isRecordingChanged(); void isRecordingChanged();
void conferenceUriChanged();
void lToggleScreenSharing(); void lToggleScreenSharing();
@ -111,9 +106,7 @@ private:
bool mIsRecording = false; bool mIsRecording = false;
bool mIsLocalScreenSharing = false; bool mIsLocalScreenSharing = false;
bool mIsScreenSharingEnabled = false; bool mIsScreenSharingEnabled = false;
bool mIsChatEnabled = false;
QString mSubject; QString mSubject;
QString mConfUri;
QDateTime mStartDate = QDateTime::currentDateTime(); QDateTime mStartDate = QDateTime::currentDateTime();
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (c) 2021 Belledonne Communications SARL. * Copyright (c) 2021 Belledonne Communications SARL.
* *
* This file is part of linphone-desktop * This file is part of linphone-desktop
@ -21,15 +21,12 @@
#include "ConferenceInfoCore.hpp" #include "ConferenceInfoCore.hpp"
#include "core/App.hpp" #include "core/App.hpp"
#include "core/path/Paths.hpp"
#include "core/proxy/ListProxy.hpp" #include "core/proxy/ListProxy.hpp"
#include "model/object/VariantObject.hpp" #include "model/object/VariantObject.hpp"
#include "model/tool/ToolModel.hpp" #include "model/tool/ToolModel.hpp"
#include "tool/Utils.hpp" #include "tool/Utils.hpp"
#include "tool/thread/SafeConnection.hpp" #include "tool/thread/SafeConnection.hpp"
#include <QDesktopServices>
DEFINE_ABSTRACT_OBJECT(ConferenceInfoCore) DEFINE_ABSTRACT_OBJECT(ConferenceInfoCore)
QSharedPointer<ConferenceInfoCore> QSharedPointer<ConferenceInfoCore>
@ -72,13 +69,16 @@ ConferenceInfoCore::ConferenceInfoCore(std::shared_ptr<linphone::ConferenceInfo>
mUri = address && address->isValid() && !address->getDomain().empty() mUri = address && address->isValid() && !address->getDomain().empty()
? Utils::coreStringToAppString(address->asStringUriOnly()) ? Utils::coreStringToAppString(address->asStringUriOnly())
: ""; : "";
mIcalendarString = Utils::coreStringToAppString(conferenceInfo->getIcalendarString());
mDateTime = QDateTime::fromMSecsSinceEpoch(conferenceInfo->getDateTime() * 1000); mDateTime = QDateTime::fromMSecsSinceEpoch(conferenceInfo->getDateTime() * 1000);
mDuration = conferenceInfo->getDuration(); mDuration = conferenceInfo->getDuration();
mEndDateTime = mDateTime.addSecs(mDuration * 60); mEndDateTime = mDateTime.addSecs(mDuration * 60);
mIsScheduled = mDateTime.isValid(); mIsScheduled = mDateTime.isValid();
mOrganizerAddress = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->asStringUriOnly()); mOrganizerAddress = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->asStringUriOnly());
mOrganizerName = mConferenceInfoModel->getOrganizerName(); mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getDisplayName());
if (mOrganizerName.isEmpty()) {
mOrganizerName = Utils::coreStringToAppString(conferenceInfo->getOrganizer()->getUsername());
mOrganizerName.replace(".", " ");
}
mSubject = Utils::coreStringToAppString(conferenceInfo->getSubject()); mSubject = Utils::coreStringToAppString(conferenceInfo->getSubject());
mDescription = Utils::coreStringToAppString(conferenceInfo->getDescription()); mDescription = Utils::coreStringToAppString(conferenceInfo->getDescription());
mIsEnded = getDateTimeUtc().addSecs(mDuration * 60) < QDateTime::currentDateTimeUtc(); mIsEnded = getDateTimeUtc().addSecs(mDuration * 60) < QDateTime::currentDateTimeUtc();
@ -127,7 +127,6 @@ ConferenceInfoCore::ConferenceInfoCore(const ConferenceInfoCore &conferenceInfoC
mIsEnded = conferenceInfoCore.mIsEnded; mIsEnded = conferenceInfoCore.mIsEnded;
mInviteEnabled = conferenceInfoCore.mInviteEnabled; mInviteEnabled = conferenceInfoCore.mInviteEnabled;
mConferenceInfoState = conferenceInfoCore.mConferenceInfoState; mConferenceInfoState = conferenceInfoCore.mConferenceInfoState;
mIcalendarString = conferenceInfoCore.mIcalendarString;
} }
ConferenceInfoCore::~ConferenceInfoCore() { ConferenceInfoCore::~ConferenceInfoCore() {
@ -180,13 +179,6 @@ 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->makeConnectToCore(&ConferenceInfoCore::lDeleteConferenceInfo, [this]() {
mConfInfoModelConnection->invokeToModel([this] { mConferenceInfoModel->deleteConferenceInfo(); }); mConfInfoModelConnection->invokeToModel([this] { mConferenceInfoModel->deleteConferenceInfo(); });
}); });
@ -200,15 +192,21 @@ void ConferenceInfoCore::setSelf(QSharedPointer<ConferenceInfoCore> me) {
QString uri; QString uri;
if (state == linphone::ConferenceScheduler::State::Ready) { if (state == linphone::ConferenceScheduler::State::Ready) {
uri = mConferenceInfoModel->getConferenceScheduler()->getUri(); uri = mConferenceInfoModel->getConferenceScheduler()->getUri();
emit CoreModel::getInstance() -> conferenceInfoReceived(
CoreModel::getInstance()->getCore(),
mConferenceInfoModel->getConferenceInfo());
} }
mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state), mConfInfoModelConnection->invokeToCore([this, state = LinphoneEnums::fromLinphone(state),
infoState = LinphoneEnums::fromLinphone(confInfoState), infoState = LinphoneEnums::fromLinphone(confInfoState),
uri] { uri] {
setConferenceSchedulerState(state); setConferenceSchedulerState(state);
setConferenceInfoState(infoState); 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( mConfInfoModelConnection->makeConnectToModel(
@ -330,8 +328,7 @@ void ConferenceInfoCore::setTimeZoneModel(TimeZoneModel *model) {
mTimeZoneModel->getStandardTimeOffset() != model->getStandardTimeOffset() || mTimeZoneModel->getStandardTimeOffset() != model->getStandardTimeOffset() ||
mTimeZoneModel->getTimeZone() != model->getTimeZone()) { mTimeZoneModel->getTimeZone() != model->getTimeZone()) {
mTimeZoneModel = QSharedPointer<TimeZoneModel>(new TimeZoneModel(model->getTimeZone())); mTimeZoneModel = QSharedPointer<TimeZoneModel>(model);
emit timeZoneModelChanged(); emit timeZoneModelChanged();
} }
} }
@ -558,10 +555,6 @@ void ConferenceInfoCore::writeIntoModel(std::shared_ptr<ConferenceInfoModel> mod
model->setParticipantInfos(participantInfos); model->setParticipantInfos(participantInfos);
} }
std::shared_ptr<ConferenceInfoModel> ConferenceInfoCore::getModel() const {
return mConferenceInfoModel;
}
void ConferenceInfoCore::save() { void ConferenceInfoCore::save() {
mustBeInMainThread(getClassName() + "::save()"); mustBeInMainThread(getClassName() + "::save()");
ConferenceInfoCore *thisCopy = new ConferenceInfoCore(*this); // Pointer to avoid multiple copies in lambdas ConferenceInfoCore *thisCopy = new ConferenceInfoCore(*this); // Pointer to avoid multiple copies in lambdas
@ -582,8 +575,8 @@ void ConferenceInfoCore::save() {
linphone::RegistrationState::Ok) { linphone::RegistrationState::Ok) {
//: "Erreur" //: "Erreur"
Utils::showInformationPopup(tr("information_popup_error_title"), Utils::showInformationPopup(tr("information_popup_error_title"),
//: "Votre compte est déconnecté" //: "Votre compte est déconnecté"
tr("information_popup_disconnected_account_message"), false); tr("information_popup_disconnected_account_message"), false);
emit saveFailed(); emit saveFailed();
return; return;
} }
@ -606,9 +599,6 @@ void ConferenceInfoCore::save() {
} else lCritical() << "No default account"; } else lCritical() << "No default account";
// Add text capability for chat in conf // Add text capability for chat in conf
linphoneConf->setCapability(linphone::StreamType::Text, true); 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 confInfoModel = Utils::makeQObject_ptr<ConferenceInfoModel>(linphoneConf);
auto confSchedulerModel = confInfoModel->getConferenceScheduler(); auto confSchedulerModel = confInfoModel->getConferenceScheduler();
if (!confSchedulerModel) { if (!confSchedulerModel) {
@ -647,6 +637,12 @@ void ConferenceInfoCore::undo() {
} }
} }
void ConferenceInfoCore::cancelCreation() {
if (mConferenceInfoModel) {
mConferenceInfoModel->setConferenceScheduler(nullptr);
}
}
//------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------
void ConferenceInfoCore::onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) { void ConferenceInfoCore::onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations) {
@ -658,14 +654,3 @@ bool ConferenceInfoCore::isAllDayConf() const {
return mDateTime.time().hour() == 0 && mDateTime.time().minute() == 0 && mEndDateTime.time().hour() == 23 && return mDateTime.time().hour() == 0 && mDateTime.time().minute() == 0 && mEndDateTime.time().hour() == 23 &&
mEndDateTime.time().minute() == 59; 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));
}

View file

@ -1,4 +1,4 @@
/* /*
* Copyright (c) 2022 Belledonne Communications SARL. * Copyright (c) 2022 Belledonne Communications SARL.
* *
* This file is part of linphone-desktop * This file is part of linphone-desktop
@ -126,17 +126,14 @@ public:
void writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model); void writeFromModel(const std::shared_ptr<ConferenceInfoModel> &model);
void writeIntoModel(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 save();
Q_INVOKABLE void undo(); Q_INVOKABLE void undo();
Q_INVOKABLE void cancelCreation();
virtual void onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations); virtual void onInvitationsSent(const std::list<std::shared_ptr<linphone::Address>> &failedInvitations);
Q_INVOKABLE bool isAllDayConf() const; Q_INVOKABLE bool isAllDayConf() const;
Q_INVOKABLE void exportConferenceToICS() const;
signals: signals:
void dateTimeChanged(); void dateTimeChanged();
void endDateTimeChanged(); void endDateTimeChanged();
@ -161,7 +158,6 @@ signals:
void invitationsSent(); void invitationsSent();
void removed(ConferenceInfoCore *confInfo); void removed(ConferenceInfoCore *confInfo);
void lCancelCreation();
void lCancelConferenceInfo(); void lCancelConferenceInfo();
void lDeleteConferenceInfo(); // Remove completly this conference info from DB void lDeleteConferenceInfo(); // Remove completly this conference info from DB
@ -179,7 +175,6 @@ private:
QString mSubject; QString mSubject;
QString mDescription; QString mDescription;
QString mUri; QString mUri;
QString mIcalendarString;
QVariantList mParticipants; QVariantList mParticipants;
QSharedPointer<TimeZoneModel> mTimeZoneModel; QSharedPointer<TimeZoneModel> mTimeZoneModel;
LinphoneEnums::ConferenceSchedulerState mConferenceSchedulerState; LinphoneEnums::ConferenceSchedulerState mConferenceSchedulerState;

View file

@ -58,119 +58,58 @@ ConferenceInfoList::~ConferenceInfoList() {
void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) { void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
mCoreModelConnection = SafeConnection<ConferenceInfoList, CoreModel>::create(me, CoreModel::getInstance()); mCoreModelConnection = SafeConnection<ConferenceInfoList, CoreModel>::create(me, CoreModel::getInstance());
mCoreModelConnection->makeConnectToCore(&ConferenceInfoList::lUpdate, [this]() { mCoreModelConnection->makeConnectToCore(&ConferenceInfoList::lUpdate, [this](bool isInitialization) {
if (mIsUpdating) { mCoreModelConnection->invokeToModel([this, isInitialization]() {
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>>(); QList<QSharedPointer<ConferenceInfoCore>> *items = new QList<QSharedPointer<ConferenceInfoCore>>();
mustBeInLinphoneThread(getClassName());
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount(); auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
setAccountConnected(defaultAccount && defaultAccount->getState() == linphone::RegistrationState::Ok); if (!defaultAccount) return;
if (!defaultAccount || !mAccountConnected) {
endResetModel();
setIsUpdating(false);
return;
}
std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos = std::list<std::shared_ptr<linphone::ConferenceInfo>> conferenceInfos =
defaultAccount->getConferenceInformationList(); defaultAccount->getConferenceInformationList();
if (conferenceInfos.empty()) {
endResetModel();
setIsUpdating(false);
return;
}
items->push_back(nullptr); // Add Dummy conference for today items->push_back(nullptr); // Add Dummy conference for today
for (auto conferenceInfo : conferenceInfos) { for (auto conferenceInfo : conferenceInfos) {
// if (conferenceInfo->getState() == linphone::ConferenceInfo::State::Cancelled) { if (conferenceInfo->getState() == linphone::ConferenceInfo::State::Cancelled) {
// auto myAddress = defaultAccount->getParams()->getIdentityAddress(); auto myAddress = defaultAccount->getParams()->getIdentityAddress();
// if (!myAddress || myAddress->weakEqual(conferenceInfo->getOrganizer())) continue; if (!myAddress || myAddress->weakEqual(conferenceInfo->getOrganizer())) continue;
// } }
auto confInfoCore = build(conferenceInfo); auto confInfoCore = build(conferenceInfo);
// Cancelled conference organized ourself me must be hidden // Cancelled conference organized ourself me must be hidden
if (confInfoCore) { if (confInfoCore) {
// qDebug() << log().arg("Add conf") << confInfoCore->getSubject() << "with state"
// << confInfoCore->getConferenceInfoState();
items->push_back(confInfoCore); items->push_back(confInfoCore);
} }
} }
mCoreModelConnection->invokeToCore([this, items]() { mCoreModelConnection->invokeToCore([this, items, isInitialization]() {
mustBeInMainThread(getClassName()); mustBeInMainThread(getClassName());
for (auto &item : *items) { for (auto &item : *items) {
connectItem(item); connectItem(item);
mList << item.template objectCast<QObject>();
} }
updateHaveCurrentDate(); resetData(*items);
endResetModel();
setIsUpdating(false);
delete items; delete items;
if (isInitialization) {
emit initialized();
}
}); });
}); });
}); });
mCoreModelConnection->makeConnectToModel(
&CoreModel::conferenceInfoReceived,
[this](const std::shared_ptr<linphone::Core> &core,
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
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();
});
// This is needed because account does not have a contact address until // 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 // it is connected, so we can't verify if it is the organizer of a deleted
// conference (which must hidden) // conference (which must hidden)
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, [this]() { emit lUpdate(true); });
mCoreModelConnection->makeConnectToModel( mCoreModelConnection->makeConnectToModel(
&CoreModel::defaultAccountChanged, &CoreModel::conferenceInfoCreated,
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) { [this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { addConference(confInfo); });
auto accountCore = account ? AccountCore::create(account) : nullptr; mCoreModelConnection->makeConnectToModel(
mCoreModelConnection->invokeToCore([this, accountCore] { &CoreModel::conferenceInfoReceived,
if (mCurrentAccountCore) { [this](const std::shared_ptr<linphone::Core> &core,
disconnect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this, nullptr); const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
disconnect(mCurrentAccountCore.get(), &AccountCore::conferenceInformationUpdated, this, nullptr); lDebug() << log().arg("conference info received") << conferenceInfo->getSubject();
} addConference(conferenceInfo->clone());
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] { emit lUpdate(true);
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) { void ConferenceInfoList::resetData(QList<QSharedPointer<ConferenceInfoCore>> data) {
@ -190,7 +129,6 @@ void ConferenceInfoList::addConference(const std::shared_ptr<linphone::Conferenc
return confInfo->getUri()->weakEqual(confAddr); return confInfo->getUri()->weakEqual(confAddr);
}); });
if (haveConf == list.end()) { if (haveConf == list.end()) {
if (confInfo->getState() == linphone::ConferenceInfo::State::Cancelled) return;
auto confInfoCore = build(confInfo); auto confInfoCore = build(confInfo);
mCoreModelConnection->invokeToCore([this, confInfoCore] { mCoreModelConnection->invokeToCore([this, confInfoCore] {
connectItem(confInfoCore); connectItem(confInfoCore);
@ -235,17 +173,13 @@ int ConferenceInfoList::getCurrentDateIndex() {
return it == confInfoList.end() ? -1 : std::distance(confInfoList.begin(), it); return it == confInfoList.end() ? -1 : std::distance(confInfoList.begin(), it);
} }
QSharedPointer<ConferenceInfoCore> ConferenceInfoList::getCurrentDateConfInfo(bool enableCancelledConference) { QSharedPointer<ConferenceInfoCore> ConferenceInfoList::getCurrentDateConfInfo() {
auto today = QDate::currentDate(); auto today = QDate::currentDate();
auto confInfoList = getSharedList<ConferenceInfoCore>(); auto confInfoList = getSharedList<ConferenceInfoCore>();
QList<QSharedPointer<ConferenceInfoCore>>::iterator it; QList<QSharedPointer<ConferenceInfoCore>>::iterator it;
if (mHaveCurrentDate) { if (mHaveCurrentDate) {
it = std::find_if(confInfoList.begin(), confInfoList.end(), it = std::find_if(confInfoList.begin(), confInfoList.end(),
[today, enableCancelledConference](const QSharedPointer<ConferenceInfoCore> &item) { [today](const QSharedPointer<ConferenceInfoCore> &item) {
if (!item) return false;
if (!enableCancelledConference &&
item->getConferenceInfoState() == LinphoneEnums::ConferenceInfoState::Cancelled)
return false;
return item && item->getDateTimeUtc().date() == today; return item && item->getDateTimeUtc().date() == today;
}); });
} else it = std::find(confInfoList.begin(), confInfoList.end(), nullptr); } else it = std::find(confInfoList.begin(), confInfoList.end(), nullptr);
@ -302,9 +236,7 @@ QVariant ConferenceInfoList::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
return QVariant::fromValue(new ConferenceInfoGui(mList[row].objectCast<ConferenceInfoCore>())); return QVariant::fromValue(new ConferenceInfoGui(mList[row].objectCast<ConferenceInfoCore>()));
} else if (role == Qt::DisplayRole + 1) { } else if (role == Qt::DisplayRole + 1) {
auto date = mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc(); return Utils::toDateMonthString(mList[row].objectCast<ConferenceInfoCore>()->getDateTimeUtc());
if (date.date().year() != QDate::currentDate().year()) return Utils::toDateMonthAndYearString(date);
else return Utils::toDateMonthString(date);
} }
} else { // Dummy date } else { // Dummy date
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010-2024 Belledonne Communications SARL. * Copyright (c) 2010-2020 Belledonne Communications SARL.
* *
* This file is part of linphone-desktop * This file is part of linphone-desktop
* (see https://www.linphone.org). * (see https://www.linphone.org).
@ -48,32 +48,28 @@ public:
void updateHaveCurrentDate(); void updateHaveCurrentDate();
int getCurrentDateIndex(); int getCurrentDateIndex();
QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo(bool enableCancelledConference = false); QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo();
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo); QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo);
void connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore); void connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore);
QHash<int, QByteArray> roleNames() const override; 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; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals: signals:
void lUpdate(); void lUpdate(bool isInitialization = false);
void initialized();
void addCurrentDateChanged(); void addCurrentDateChanged();
void haveCurrentDateChanged(); void haveCurrentDateChanged();
void currentDateIndexChanged(int index); void currentDateIndexChanged(int index);
void confInfoInserted(QSharedPointer<ConferenceInfoCore> data); void confInfoInserted(QSharedPointer<ConferenceInfoCore> data);
void confInfoUpdated(QSharedPointer<ConferenceInfoCore> data); void confInfoUpdated(QSharedPointer<ConferenceInfoCore> data);
void accountConnectedChanged(bool connected);
private: private:
QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection;
QSharedPointer<AccountCore> mCurrentAccountCore; QSharedPointer<AccountCore> mCurrentAccountCore;
bool mHaveCurrentDate = false; bool mHaveCurrentDate = false;
bool mAccountConnected = false;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };
#endif // CONFERENCE_INFO_LIST_H_ #endif // CONFERENCE_INFO_LIST_H_

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2010-2024 Belledonne Communications SARL. * Copyright (c) 2010-2020 Belledonne Communications SARL.
* *
* This file is part of linphone-desktop * This file is part of linphone-desktop
* (see https://www.linphone.org). * (see https://www.linphone.org).
@ -57,26 +57,20 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) {
if (isSignalConnected(conferenceInfoUpdatedSignal)) emit conferenceInfoUpdated(new ConferenceInfoGui(data)); if (isSignalConnected(conferenceInfoUpdatedSignal)) emit conferenceInfoUpdated(new ConferenceInfoGui(data));
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
connect(mList.get(), &ConferenceInfoList::accountConnectedChanged, this, connect(mList.get(), &ConferenceInfoList::initialized, this, &ConferenceInfoProxy::initialized);
&ConferenceInfoProxy::accountConnectedChanged);
} }
ConferenceInfoProxy::~ConferenceInfoProxy() { ConferenceInfoProxy::~ConferenceInfoProxy() {
} }
bool ConferenceInfoProxy::haveCurrentDate() const { bool ConferenceInfoProxy::haveCurrentDate() const {
return mList && mList->haveCurrentDate(); return mList->haveCurrentDate();
}
bool ConferenceInfoProxy::getAccountConnected() const {
return mList && mList->getAccountConnected();
} }
bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
auto list = qobject_cast<ConferenceInfoList *>(sourceModel()); auto list = qobject_cast<ConferenceInfoList *>(sourceModel());
auto ciCore = list->getAt<ConferenceInfoCore>(sourceRow); auto ciCore = list->getAt<ConferenceInfoCore>(sourceRow);
if (ciCore) { if (ciCore) {
if (ciCore->getDuration() == 0) return false;
bool searchTextInSubject = false; bool searchTextInSubject = false;
bool searchTextInParticipant = false; bool searchTextInParticipant = false;
if (ciCore->getSubject().contains(mFilterText, Qt::CaseInsensitive)) searchTextInSubject = true; if (ciCore->getSubject().contains(mFilterText, Qt::CaseInsensitive)) searchTextInSubject = true;
@ -105,14 +99,6 @@ void ConferenceInfoProxy::clear() {
mList->clearData(); 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) { int ConferenceInfoProxy::loadUntil(ConferenceInfoGui *confInfo) {
return loadUntil(confInfo ? confInfo->mCore : nullptr); return loadUntil(confInfo ? confInfo->mCore : nullptr);
} }
@ -150,7 +136,7 @@ bool ConferenceInfoProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft
auto nowDate = QDate::currentDate(); auto nowDate = QDate::currentDate();
if (!l || !r) { // sort on date if (!l || !r) { // sort on date
auto rdate = r ? r->getDateTimeUtc().date() : QDate::currentDate(); 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 { } else {
return l->getDateTimeUtc() < r->getDateTimeUtc(); return l->getDateTimeUtc() < r->getDateTimeUtc();
} }

View file

@ -32,7 +32,6 @@ class ConferenceInfoProxy : public LimitProxy, public AbstractObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged) Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
Q_PROPERTY(bool accountConnected READ getAccountConnected NOTIFY accountConnectedChanged)
public: public:
enum ConferenceInfoFiltering { None = 0, Future = 1 }; enum ConferenceInfoFiltering { None = 0, Future = 1 };
@ -44,17 +43,15 @@ public:
~ConferenceInfoProxy(); ~ConferenceInfoProxy();
bool haveCurrentDate() const; bool haveCurrentDate() const;
bool getAccountConnected() const;
Q_INVOKABLE void clear(); Q_INVOKABLE void clear();
Q_INVOKABLE ConferenceInfoGui *getCurrentDateConfInfo(bool enableCancelledConference = false);
Q_INVOKABLE int loadUntil(ConferenceInfoGui *confInfo); Q_INVOKABLE int loadUntil(ConferenceInfoGui *confInfo);
int loadUntil(QSharedPointer<ConferenceInfoCore> data); int loadUntil(QSharedPointer<ConferenceInfoCore> data);
signals: signals:
void initialized();
void haveCurrentDateChanged(); void haveCurrentDateChanged();
void conferenceInfoCreated(ConferenceInfoGui *confInfo); void conferenceInfoCreated(ConferenceInfoGui *confInfo);
void conferenceInfoUpdated(ConferenceInfoGui *confInfo); void conferenceInfoUpdated(ConferenceInfoGui *confInfo);
void accountConnectedChanged(bool connected);
private: private:
QSharedPointer<ConferenceInfoList> mList; QSharedPointer<ConferenceInfoList> mList;

View file

@ -1,63 +0,0 @@
/*
* 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();
}

View file

@ -1,49 +0,0 @@
/*
* 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

View file

@ -1,91 +0,0 @@
/*
* 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;
}

View file

@ -1,54 +0,0 @@
/*
* 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

View file

@ -1,65 +0,0 @@
/*
* 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;
}

View file

@ -1,62 +0,0 @@
/*
* 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

View file

@ -1,62 +0,0 @@
/*
* 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;
}
}

View file

@ -1,58 +0,0 @@
/*
* 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_

View file

@ -1,40 +0,0 @@
/*
* 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_

View file

@ -1,30 +0,0 @@
/*
* 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];
}

View file

@ -1,134 +0,0 @@
/*
* 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;
}

View file

@ -1,50 +0,0 @@
/*
* 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_

View file

@ -48,9 +48,8 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact); mFriendModel = Utils::makeQObject_ptr<FriendModel>(contact);
mFriendModel->setSelf(mFriendModel); mFriendModel->setSelf(mFriendModel);
auto presence = mFriendModel->getPresence(contact); mConsolidatedPresence = LinphoneEnums::fromLinphone(contact->getConsolidatedPresence());
auto note = mFriendModel->getPresenceNote(contact); mPresenceTimestamp = mFriendModel->getPresenceTimestamp();
App::postCoreAsync([this, presence, note]() { setPresence(presence, note); });
mPictureUri = Utils::coreStringToAppString(contact->getPhoto()); mPictureUri = Utils::coreStringToAppString(contact->getPhoto());
mFullName = mFriendModel->getFullName(); mFullName = mFriendModel->getFullName();
auto defaultAddress = contact->getAddress(); auto defaultAddress = contact->getAddress();
@ -66,7 +65,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
auto addresses = contact->getAddresses(); auto addresses = contact->getAddresses();
for (auto &address : addresses) { for (auto &address : addresses) {
mAddressList.append(Utils::createFriendAddressVariant( 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(); mDefaultAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asStringUriOnly()) : QString();
mDefaultFullAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asString()) : QString(); mDefaultFullAddress = defaultAddress ? Utils::coreStringToAppString(defaultAddress->asString()) : QString();
@ -91,8 +90,7 @@ FriendCore::FriendCore(const std::shared_ptr<linphone::Friend> &contact, bool is
mStarred = contact->getStarred(); mStarred = contact->getStarred();
mIsSaved = true; mIsSaved = true;
mIsStored = isStored; 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; mIsCardDAV = (sourceFlags & (int)linphone::MagicSearch::Source::RemoteCardDAV) != 0;
mIsAppFriend = ToolModel::friendIsInFriendList(ToolModel::getAppFriendList(), contact); mIsAppFriend = ToolModel::friendIsInFriendList(ToolModel::getAppFriendList(), contact);
} else { } else {
@ -144,7 +142,8 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
mFriendModelConnection->makeConnectToModel( mFriendModelConnection->makeConnectToModel(
&FriendModel::removed, [this]() { mFriendModelConnection->invokeToCore([this]() { removed(this); }); }); &FriendModel::removed, [this]() { mFriendModelConnection->invokeToCore([this]() { removed(this); }); });
mFriendModelConnection->makeConnectToModel( mFriendModelConnection->makeConnectToModel(
&FriendModel::presenceReceived, [this](LinphoneEnums::Presence presence, QString presenceNote) { &FriendModel::presenceReceived,
[this](LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp) {
auto devices = mFriendModel->getDevices(); auto devices = mFriendModel->getDevices();
QVariantList devicesList; QVariantList devicesList;
for (auto &device : devices) { for (auto &device : devices) {
@ -154,11 +153,14 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
Utils::coreStringToAppString(device->getAddress()->asString()), Utils::coreStringToAppString(device->getAddress()->asString()),
LinphoneEnums::fromLinphone(device->getSecurityLevel()))); LinphoneEnums::fromLinphone(device->getSecurityLevel())));
} }
mFriendModelConnection->invokeToCore([this, presence, devicesList, presenceNote]() { mFriendModelConnection->invokeToCore(
setPresence(presence, presenceNote); [this, consolidatedPresence, presenceTimestamp, devicesList]() {
setDevices(devicesList); setConsolidatedPresence(consolidatedPresence);
updateVerifiedDevicesCount(); setPresenceTimestamp(presenceTimestamp);
});
setDevices(devicesList);
updateVerifiedDevicesCount();
});
}); });
mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) { mFriendModelConnection->makeConnectToModel(&FriendModel::pictureUriChanged, [this](const QString &uri) {
mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); }); mFriendModelConnection->invokeToCore([this, uri]() { this->onPictureUriChanged(uri); });
@ -186,7 +188,7 @@ void FriendCore::setSelf(QSharedPointer<FriendCore> me) {
QList<QVariant> addr; QList<QVariant> addr;
for (auto &num : numbers) { for (auto &num : numbers) {
addr.append(Utils::createFriendAddressVariant( addr.append(Utils::createFriendAddressVariant(
tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly()))); tr("sip_address"), Utils::coreStringToAppString(num->asStringUriOnly())));
} }
mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); }); mFriendModelConnection->invokeToCore([this, addr]() { resetPhoneNumbers(addr); });
}); });
@ -417,10 +419,9 @@ void FriendCore::appendAddress(const QString &addr) {
QString interpretedFullAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asString()) : ""; QString interpretedFullAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asString()) : "";
QString interpretedAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()) : ""; QString interpretedAddress = linphoneAddr ? Utils::coreStringToAppString(linphoneAddr->asStringUriOnly()) : "";
mCoreModelConnection->invokeToCore([this, interpretedAddress, interpretedFullAddress]() { mCoreModelConnection->invokeToCore([this, interpretedAddress, interpretedFullAddress]() {
if (interpretedAddress.isEmpty()) if (interpretedAddress.isEmpty()) Utils::showInformationPopup(tr("information_popup_error_title"),
Utils::showInformationPopup(tr("information_popup_error_title"), //: "Adresse invalide"
//: "Adresse invalide" tr("information_popup_invalid_address_message"), false);
tr("information_popup_invalid_address_message"), false);
else { else {
mAddressList.append(Utils::createFriendAddressVariant(tr("sip_address"), interpretedAddress)); mAddressList.append(Utils::createFriendAddressVariant(tr("sip_address"), interpretedAddress));
if (mDefaultFullAddress.isEmpty()) mDefaultFullAddress = interpretedFullAddress; if (mDefaultFullAddress.isEmpty()) mDefaultFullAddress = interpretedFullAddress;
@ -506,6 +507,30 @@ 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 { QString FriendCore::getPictureUri() const {
return mPictureUri; return mPictureUri;
} }
@ -587,8 +612,8 @@ void FriendCore::writeFromModel(const std::shared_ptr<FriendModel> &model) {
QList<QVariant> addresses; QList<QVariant> addresses;
for (auto &addr : model->getAddresses()) { for (auto &addr : model->getAddresses()) {
addresses.append(Utils::createFriendAddressVariant(tr("sip_address"), addresses.append(
Utils::coreStringToAppString(addr->asStringUriOnly()))); Utils::createFriendAddressVariant(tr("sip_address"), Utils::coreStringToAppString(addr->asStringUriOnly())));
} }
mAddressList = addresses; mAddressList = addresses;
mDefaultAddress = model->getDefaultAddress(); mDefaultAddress = model->getDefaultAddress();
@ -734,29 +759,3 @@ bool FriendCore::getReadOnly() const {
std::shared_ptr<FriendModel> FriendCore::getFriendModel() { std::shared_ptr<FriendModel> FriendCore::getFriendModel() {
return mFriendModel; 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);
}

View file

@ -29,8 +29,8 @@
#include "tool/thread/SafeSharedPointer.hpp" #include "tool/thread/SafeSharedPointer.hpp"
#include <linphone++/linphone.hh> #include <linphone++/linphone.hh>
#include <QColor>
#include <QDateTime> #include <QDateTime>
#include <QMap>
#include <QObject> #include <QObject>
#include <QSharedPointer> #include <QSharedPointer>
@ -63,11 +63,9 @@ class FriendCore : public QObject, public AbstractObject {
Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged) Q_PROPERTY(QString defaultAddress READ getDefaultAddress WRITE setDefaultAddress NOTIFY defaultAddressChanged)
Q_PROPERTY(QString defaultFullAddress READ getDefaultFullAddress WRITE setDefaultFullAddress NOTIFY Q_PROPERTY(QString defaultFullAddress READ getDefaultFullAddress WRITE setDefaultFullAddress NOTIFY
defaultFullAddressChanged) defaultFullAddressChanged)
Q_PROPERTY(LinphoneEnums::Presence presence MEMBER mPresence NOTIFY presenceChanged) Q_PROPERTY(QDateTime presenceTimestamp READ getPresenceTimestamp NOTIFY presenceTimestampChanged)
Q_PROPERTY(QUrl presenceIcon READ getPresenceIcon NOTIFY presenceChanged) Q_PROPERTY(LinphoneEnums::ConsolidatedPresence consolidatedPresence READ getConsolidatedPresence NOTIFY
Q_PROPERTY(QColor presenceColor READ getPresenceColor NOTIFY presenceChanged) consolidatedPresenceChanged)
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 isSaved READ getIsSaved NOTIFY isSavedChanged)
Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged) Q_PROPERTY(bool isStored READ getIsStored NOTIFY isStoredChanged)
Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged) Q_PROPERTY(QString pictureUri READ getPictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
@ -132,6 +130,12 @@ public:
void setDevices(QVariantList devices); void setDevices(QVariantList devices);
Q_INVOKABLE LinphoneEnums::SecurityLevel getSecurityLevelForAddress(const QString &address) const; 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; bool getIsSaved() const;
void setIsSaved(bool isSaved); void setIsSaved(bool isSaved);
@ -142,6 +146,8 @@ public:
void setPictureUri(const QString &uri); void setPictureUri(const QString &uri);
void onPictureUriChanged(QString uri); void onPictureUriChanged(QString uri);
void onPresenceReceived(LinphoneEnums::ConsolidatedPresence consolidatedPresence, QDateTime presenceTimestamp);
bool isLdap() const; bool isLdap() const;
bool isAppFriend() const; bool isAppFriend() const;
bool isCardDAV() const; bool isCardDAV() const;
@ -153,10 +159,6 @@ public:
Q_INVOKABLE void save(); Q_INVOKABLE void save();
Q_INVOKABLE void undo(); Q_INVOKABLE void undo();
QColor getPresenceColor();
QString getPresenceStatus();
QUrl getPresenceIcon();
protected: protected:
void resetPhoneNumbers(QList<QVariant> newList); void resetPhoneNumbers(QList<QVariant> newList);
void resetAddresses(QList<QVariant> newList); void resetAddresses(QList<QVariant> newList);
@ -171,6 +173,8 @@ signals:
void addressChanged(); void addressChanged();
void organizationChanged(); void organizationChanged();
void jobChanged(); void jobChanged();
void consolidatedPresenceChanged(LinphoneEnums::ConsolidatedPresence level);
void presenceTimestampChanged(QDateTime presenceTimestamp);
void pictureUriChanged(); void pictureUriChanged();
void saved(); void saved();
void isSavedChanged(bool isSaved); void isSavedChanged(bool isSaved);
@ -182,16 +186,13 @@ signals:
void devicesChanged(); void devicesChanged();
void verifiedDevicesChanged(); void verifiedDevicesChanged();
void lSetStarred(bool starred); void lSetStarred(bool starred);
void presenceChanged();
protected: protected:
void writeIntoModel(std::shared_ptr<FriendModel> model) const; void writeIntoModel(std::shared_ptr<FriendModel> model) const;
void writeFromModel(const std::shared_ptr<FriendModel> &model); void writeFromModel(const std::shared_ptr<FriendModel> &model);
LinphoneEnums::Presence mPresence = LinphoneEnums::Presence::Undefined; LinphoneEnums::ConsolidatedPresence mConsolidatedPresence = LinphoneEnums::ConsolidatedPresence::Offline;
QColor mPresenceColor; QDateTime mPresenceTimestamp;
QString mPresenceStatus;
QString mPresenceNote = "";
QString mGivenName; QString mGivenName;
QString mFamilyName; QString mFamilyName;
QString mFullName; QString mFullName;
@ -213,9 +214,6 @@ protected:
QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection; QSharedPointer<SafeConnection<FriendCore, FriendModel>> mFriendModelConnection;
QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection; QSharedPointer<SafeConnection<FriendCore, CoreModel>> mCoreModelConnection;
private:
void setPresence(LinphoneEnums::Presence presence, QString presenceNote);
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -64,27 +64,22 @@ void LoginPage::login(const QString &username,
const QString &password, const QString &password,
QString displayName, QString displayName,
QString domain, QString domain,
LinphoneEnums::TransportType transportType, LinphoneEnums::TransportType transportType) {
QString registrarUri,
QString outboundProxyAddress,
QString connectionId) {
setErrorMessage(""); setErrorMessage("");
App::postModelAsync([=]() { App::postModelAsync([=]() {
// Create on Model thread. // Create on Model thread.
AccountManager *accountManager = new AccountManager(); AccountManager *accountManager = new AccountManager();
connect(accountManager, &AccountManager::registrationStateChanged, this, connect(accountManager, &AccountManager::registrationStateChanged, this,
[accountManager, this](linphone::RegistrationState state, linphone::Reason reason, [accountManager, this](linphone::RegistrationState state, QString message) mutable {
QString message) mutable {
// View thread // View thread
setRegistrationState(state); setRegistrationState(state);
mBadIds = reason == linphone::Reason::Forbidden;
emit reasonChanged();
switch (state) { switch (state) {
case linphone::RegistrationState::Failed: { case linphone::RegistrationState::Failed: {
if (message.isEmpty()) if (message.isEmpty())
//: Erreur durant la connexion, veuillez vérifier vos paramètres //: Erreur durant la connexion
setErrorMessage(tr("default_account_connection_state_error_toast")); setErrorMessage(tr("default_account_connection_state_error_toast"));
else setErrorMessage(message); else
setErrorMessage(message);
if (accountManager) { if (accountManager) {
accountManager->deleteLater(); accountManager->deleteLater();
accountManager = nullptr; accountManager = nullptr;
@ -115,9 +110,9 @@ void LoginPage::login(const QString &username,
QString error; QString error;
if (!accountManager->login(username, password, displayName, domain, LinphoneEnums::toLinphone(transportType), if (!accountManager->login(username, password, displayName, domain, LinphoneEnums::toLinphone(transportType),
&error, registrarUri, outboundProxyAddress, connectionId)) { &error)) {
setErrorMessage(error); setErrorMessage(error);
emit accountManager->registrationStateChanged(linphone::RegistrationState::None, linphone::Reason::None); emit accountManager->registrationStateChanged(linphone::RegistrationState::None);
} }
}); });
} }

View file

@ -35,16 +35,12 @@ public:
Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged) Q_PROPERTY(linphone::RegistrationState registrationState READ getRegistrationState NOTIFY registrationStateChanged)
Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged) Q_PROPERTY(QString errorMessage READ getErrorMessage NOTIFY errorMessageChanged)
Q_PROPERTY(bool badIds MEMBER mBadIds NOTIFY reasonChanged)
Q_INVOKABLE void login(const QString &username, Q_INVOKABLE void login(const QString &username,
const QString &password, const QString &password,
QString displayName = QString(), QString displayName = QString(),
QString domain = 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; linphone::RegistrationState getRegistrationState() const;
void setRegistrationState(linphone::RegistrationState status); void setRegistrationState(linphone::RegistrationState status);
@ -55,12 +51,10 @@ public:
signals: signals:
void registrationStateChanged(); void registrationStateChanged();
void errorMessageChanged(QString error); void errorMessageChanged(QString error);
void reasonChanged();
private: private:
linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None; linphone::RegistrationState mRegistrationState = linphone::RegistrationState::None;
QString mErrorMessage; QString mErrorMessage;
bool mBadIds = false;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT
}; };

View file

@ -33,10 +33,8 @@
#include "core/App.hpp" #include "core/App.hpp"
#include "core/call/CallGui.hpp" #include "core/call/CallGui.hpp"
#include "core/chat/ChatGui.hpp"
#include "model/tool/ToolModel.hpp" #include "model/tool/ToolModel.hpp"
#include "tool/LinphoneEnums.hpp" #include "tool/LinphoneEnums.hpp"
#include "tool/accessibility/AccessibilityHelper.hpp"
#include "tool/providers/AvatarProvider.hpp" #include "tool/providers/AvatarProvider.hpp"
#include "tool/providers/ImageProvider.hpp" #include "tool/providers/ImageProvider.hpp"
@ -87,9 +85,9 @@ void setProperty(QObject &object, const char *property, const T &value) {
// ============================================================================= // =============================================================================
const QHash<int, Notifier::Notification> Notifier::Notifications = { 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::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::NewVersionAvailable, {Notifier::NewVersionAvailable, "NotificationNewVersionAvailable.qml", 30}},
//{Notifier::SnapshotWasTaken, {Notifier::SnapshotWasTaken, "NotificationSnapshotWasTaken.qml", 10}}, //{Notifier::SnapshotWasTaken, {Notifier::SnapshotWasTaken, "NotificationSnapshotWasTaken.qml", 10}},
//{Notifier::RecordingCompleted, {Notifier::RecordingCompleted, "NotificationRecordingCompleted.qml", 10}} //{Notifier::RecordingCompleted, {Notifier::RecordingCompleted, "NotificationRecordingCompleted.qml", 10}}
@ -129,8 +127,8 @@ Notifier::~Notifier() {
bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) { bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap data) {
mMutex->lock(); mMutex->lock();
// Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber); Q_ASSERT(mInstancesNumber <= MaxNotificationsNumber);
if (mInstancesNumber >= MaxNotificationsNumber) { // Check existing instances. if (mInstancesNumber == MaxNotificationsNumber) { // Check existing instances.
qWarning() << QStringLiteral("Unable to create another notification."); qWarning() << QStringLiteral("Unable to create another notification.");
mMutex->unlock(); mMutex->unlock();
return false; return false;
@ -165,6 +163,7 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
engine->deleteLater(); engine->deleteLater();
exit(-1); exit(-1);
} else { } else {
lDebug() << engine->rootObjects()[0];
auto window = qobject_cast<QQuickWindow *>(obj); auto window = qobject_cast<QQuickWindow *>(obj);
if (window) { if (window) {
window->setProperty(NotificationPropertyData, data); window->setProperty(NotificationPropertyData, data);
@ -172,24 +171,28 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
// window->setProperty(it.key().toLatin1(), it.value()); // window->setProperty(it.key().toLatin1(), it.value());
const int timeout = Notifications[type].getTimeout() * 1000; const int timeout = Notifications[type].getTimeout() * 1000;
auto updateNotificationCoordinates = [this, window, screen](int width, int height) { auto updateNotificationCoordinates = [this, window, screen](int width, int height) {
auto screenHeightOffset = int *screenHeightOffset = &mScreenHeightOffset[screen->name()]; // Access optimization
screen ? mScreenHeightOffset.value(screen->name()) : 0; // Access optimization
QRect availableGeometry = screen->availableGeometry(); QRect availableGeometry = screen->availableGeometry();
int heightOffset = availableGeometry.y() +
(availableGeometry.height() -
height); //*screen->devicePixelRatio(); when using manual scaler
window->setX(availableGeometry.x() + window->setX(availableGeometry.x() +
(availableGeometry.width() - (availableGeometry.width() -
width)); //*screen->devicePixelRatio()); when using manual scaler width)); //*screen->devicePixelRatio()); when using manual scaler
window->setY(availableGeometry.y() + availableGeometry.height() - screenHeightOffset - window->setY(heightOffset - (*screenHeightOffset % heightOffset));
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()); updateNotificationCoordinates(window->width(), window->height());
auto screenHeightOffset = QObject::connect(window, &QQuickWindow::closing, window,
screen ? mScreenHeightOffset.take(screen->name()) : 0; // Access optimization [this, window] { deleteNotification(QVariant::fromValue(window)); });
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); showNotification(window, timeout);
lInfo() << QStringLiteral("Create notification:") << QVariant::fromValue(window); lInfo() << QStringLiteral("Create notification:") << QVariant::fromValue(window);
} }
@ -209,6 +212,8 @@ bool Notifier::createNotification(Notifier::NotificationType type, QVariantMap d
void Notifier::showNotification(QObject *notification, int timeout) { void Notifier::showNotification(QObject *notification, int timeout) {
// Display notification. // Display notification.
QMetaObject::invokeMethod(notification, NotificationShowMethodName, Qt::DirectConnection);
QTimer *timer = new QTimer(notification); QTimer *timer = new QTimer(notification);
timer->setInterval(timeout); timer->setInterval(timeout);
timer->setSingleShot(true); timer->setSingleShot(true);
@ -280,153 +285,63 @@ void Notifier::notifyReceivedCall(const shared_ptr<linphone::Call> &call) {
auto account = ToolModel::findAccount(call->getToAddress()); auto account = ToolModel::findAccount(call->getToAddress());
if (account) { if (account) {
auto accountModel = Utils::makeQObject_ptr<AccountModel>(account); auto accountModel = Utils::makeQObject_ptr<AccountModel>(account);
accountModel->setSelf(accountModel);
if (!accountModel->getNotificationsAllowed()) { if (!accountModel->getNotificationsAllowed()) {
lInfo() << log().arg( qInfo()
"Notifications have been disabled for this account - not creating a notification for incoming call"); << "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; return;
} }
accountModel->deleteLater();
} }
auto model = CallCore::create(call); auto model = CallCore::create(call);
auto gui = new CallGui(model); auto gui = new CallGui(model);
gui->moveToThread(App::getInstance()->thread()); gui->moveToThread(App::getInstance()->thread());
auto callLog = call->getCallLog(); App::postCoreAsync([this, gui]() {
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()); mustBeInMainThread(getClassName());
QVariantMap map; QVariantMap map;
map["displayName"].setValue(displayName);
map["call"].setValue(gui); map["call"].setValue(gui);
CREATE_NOTIFICATION(Notifier::ReceivedCall, map) CREATE_NOTIFICATION(Notifier::ReceivedCall, map)
}); });
} }
void Notifier::notifyReceivedMessages(const std::shared_ptr<linphone::ChatRoom> &room,
const list<shared_ptr<linphone::ChatMessage>> &messages) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
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::notifyReceivedMessages(const list<shared_ptr<linphone::ChatMessage>> &messages) {
QVariantMap map;
QString txt;
if (messages.size() > 0) {
shared_ptr<linphone::ChatMessage> message = messages.front();
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)
}
}
void Notifier::notifyReceivedReactions( void Notifier::notifyReceivedReactions(
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const linphone::ChatMessageReaction>>> const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const linphone::ChatMessageReaction>>>

View file

@ -41,9 +41,9 @@ public:
~Notifier(); ~Notifier();
enum NotificationType { enum NotificationType {
ReceivedMessage, // ReceivedMessage,
// ReceivedFileMessage, // ReceivedFileMessage,
ReceivedCall ReceivedCall,
// NewVersionAvailable, // NewVersionAvailable,
// SnapshotWasTaken, // SnapshotWasTaken,
// RecordingCompleted // RecordingCompleted
@ -52,9 +52,8 @@ public:
// void notifyReceivedCall(Call *call); // void notifyReceivedCall(Call *call);
void notifyReceivedCall(const std::shared_ptr<linphone::Call> &call); // Call from Linphone 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( void notifyReceivedReactions(
const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const const QList<QPair<std::shared_ptr<linphone::ChatMessage>, std::shared_ptr<const
linphone::ChatMessageReaction>>> &reactions); void notifyReceivedFileMessage(const linphone::ChatMessageReaction>>> &reactions); void notifyReceivedFileMessage(const

View file

@ -46,16 +46,12 @@ ParticipantCore::ParticipantCore(const std::shared_ptr<linphone::Participant> &p
mParticipantModel->moveToThread(CoreModel::getInstance()->thread()); mParticipantModel->moveToThread(CoreModel::getInstance()->thread());
if (participant) { if (participant) {
mAdminStatus = participant->isAdmin(); mAdminStatus = participant->isAdmin();
auto participantAddress = participant->getAddress(); mSipAddress = Utils::coreStringToAppString(participant->getAddress()->asStringUriOnly());
mUsername = Utils::coreStringToAppString(participantAddress->getUsername());
mSipAddress = Utils::coreStringToAppString(participantAddress->asStringUriOnly());
mIsMe = ToolModel::isMe(mSipAddress); mIsMe = ToolModel::isMe(mSipAddress);
mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime()); mCreationTime = QDateTime::fromSecsSinceEpoch(participant->getCreationTime());
mDisplayName = Utils::coreStringToAppString(participantAddress->getDisplayName()); mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getDisplayName());
if (mDisplayName.isEmpty()) mDisplayName = ToolModel::getDisplayName(participantAddress); if (mDisplayName.isEmpty())
auto isFriend = ToolModel::findFriendByAddress(participantAddress); mDisplayName = Utils::coreStringToAppString(participant->getAddress()->getUsername());
if (isFriend && isFriend->getCore()) mSecurityLevel = LinphoneEnums::fromLinphone(isFriend->getSecurityLevel());
else mSecurityLevel = LinphoneEnums::SecurityLevel::None;
for (auto &device : participant->getDevices()) { for (auto &device : participant->getDevices()) {
auto name = Utils::coreStringToAppString(device->getName()); auto name = Utils::coreStringToAppString(device->getName());
auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly()); auto address = Utils::coreStringToAppString(device->getAddress()->asStringUriOnly());
@ -79,7 +75,7 @@ void ParticipantCore::setSelf(QSharedPointer<ParticipantCore> me) {
connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe); connect(this, &ParticipantCore::sipAddressChanged, this, &ParticipantCore::updateIsMe);
} }
LinphoneEnums::SecurityLevel ParticipantCore::getSecurityLevel() const { int ParticipantCore::getSecurityLevel() const {
return mSecurityLevel; return mSecurityLevel;
} }
@ -125,17 +121,6 @@ QString ParticipantCore::getDisplayName() const {
return mDisplayName; 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 { QDateTime ParticipantCore::getCreationTime() const {
return mCreationTime; return mCreationTime;
} }
@ -168,7 +153,7 @@ void ParticipantCore::setIsFocus(const bool &focus) {
} }
} }
void ParticipantCore::setSecurityLevel(LinphoneEnums::SecurityLevel level) { void ParticipantCore::setSecurityLevel(int level) {
if (level != mSecurityLevel) { if (level != mSecurityLevel) {
mSecurityLevel = level; mSecurityLevel = level;
emit securityLevelChanged(); emit securityLevelChanged();

View file

@ -40,12 +40,11 @@ class ParticipantCore : public QObject, public AbstractObject {
Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged) Q_PROPERTY(QString sipAddress READ getSipAddress WRITE setSipAddress NOTIFY sipAddressChanged)
Q_PROPERTY(QString displayName READ getDisplayName WRITE setDisplayName NOTIFY displayNameChanged) 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 isAdmin READ isAdmin WRITE setIsAdmin NOTIFY isAdminChanged)
Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged) Q_PROPERTY(bool isMe READ isMe NOTIFY isMeChanged)
Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT) Q_PROPERTY(QDateTime creationTime READ getCreationTime CONSTANT)
Q_PROPERTY(bool focus READ isFocus CONSTANT) Q_PROPERTY(bool focus READ isFocus CONSTANT)
Q_PROPERTY(LinphoneEnums::SecurityLevel securityLevel READ getSecurityLevel NOTIFY securityLevelChanged) Q_PROPERTY(int securityLevel READ getSecurityLevel NOTIFY securityLevelChanged)
Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged) Q_PROPERTY(int deviceCount READ getDeviceCount NOTIFY deviceCountChanged)
Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged) Q_PROPERTY(QList<QVariant> devices READ getParticipantDevices NOTIFY deviceChanged)
@ -57,12 +56,11 @@ public:
void setSelf(QSharedPointer<ParticipantCore> me); void setSelf(QSharedPointer<ParticipantCore> me);
QString getDisplayName() const; QString getDisplayName() const;
QString getUsername() const;
QString getSipAddress() const; QString getSipAddress() const;
QDateTime getCreationTime() const; QDateTime getCreationTime() const;
bool isAdmin() const; bool isAdmin() const;
bool isFocus() const; bool isFocus() const;
LinphoneEnums::SecurityLevel getSecurityLevel() const; int getSecurityLevel() const;
int getDeviceCount() const; int getDeviceCount() const;
bool isMe() const; bool isMe() const;
@ -71,11 +69,10 @@ public:
void setSipAddress(const QString &address); void setSipAddress(const QString &address);
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setUsername(const QString &name);
void setCreationTime(const QDateTime &date); void setCreationTime(const QDateTime &date);
void setIsAdmin(const bool &status); void setIsAdmin(const bool &status);
void setIsFocus(const bool &focus); void setIsFocus(const bool &focus);
void setSecurityLevel(LinphoneEnums::SecurityLevel level); void setSecurityLevel(int level);
QList<QVariant> getParticipantDevices(); QList<QVariant> getParticipantDevices();
@ -95,7 +92,6 @@ signals:
void invitingChanged(); void invitingChanged();
void creationTimeChanged(); void creationTimeChanged();
void displayNameChanged(); void displayNameChanged();
void usernameChanged();
void lStartInvitation(const int &secs = 30); void lStartInvitation(const int &secs = 30);
void lSetIsAdmin(bool status); void lSetIsAdmin(bool status);
@ -111,12 +107,11 @@ private:
QList<QVariant> mParticipantDevices; QList<QVariant> mParticipantDevices;
QString mDisplayName; QString mDisplayName;
QString mUsername;
QString mSipAddress; QString mSipAddress;
QDateTime mCreationTime; QDateTime mCreationTime;
bool mAdminStatus; bool mAdminStatus;
bool mIsFocus; bool mIsFocus;
LinphoneEnums::SecurityLevel mSecurityLevel; int mSecurityLevel;
bool mIsMe; bool mIsMe;
DECLARE_ABSTRACT_OBJECT DECLARE_ABSTRACT_OBJECT

View file

@ -44,13 +44,12 @@ ParticipantDeviceCore::ParticipantDeviceCore(const std::shared_ptr<linphone::Par
mustBeInLinphoneThread(getClassName()); mustBeInLinphoneThread(getClassName());
if (device) { if (device) {
mName = Utils::coreStringToAppString(device->getName()); mName = Utils::coreStringToAppString(device->getName());
auto deviceAddress = device->getAddress(); auto deviceAddress = device->getAddress()->clone();
mUniqueAddress = Utils::coreStringToAppString(deviceAddress->asString()); mUniqueAddress = Utils::coreStringToAppString(deviceAddress->asString());
mAddress = Utils::coreStringToAppString(deviceAddress->asStringUriOnly()); mAddress = Utils::coreStringToAppString(deviceAddress->asStringUriOnly());
// the display name of the device himself may be the uncleaned sip uri // the display name of the device himself may be the uncleaned sip uri
// Use the participant name instead // Use the participant name instead
auto participant = device->getParticipant(); mDisplayName = Utils::coreStringToAppString(device->getParticipant()->getAddress()->getDisplayName());
mDisplayName = Utils::coreStringToAppString(participant ? participant->getAddress()->getDisplayName() : "");
if (mDisplayName.isEmpty()) { if (mDisplayName.isEmpty()) {
mDisplayName = ToolModel::getDisplayName(deviceAddress); mDisplayName = ToolModel::getDisplayName(deviceAddress);
} }

View file

@ -1,76 +0,0 @@
/*
* 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();
}

View file

@ -1,51 +0,0 @@
/*
* 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 PARTICIPANT_INFO_LIST_H_
#define PARTICIPANT_INFO_LIST_H_
#include "../proxy/ListProxy.hpp"
#include "model/chat/ChatModel.hpp"
#include "tool/thread/SafeConnection.hpp"
class ChatCore;
// =============================================================================
class ParticipantInfoList : public ListProxy, public AbstractObject {
Q_OBJECT
public:
static QSharedPointer<ParticipantInfoList> create();
static QSharedPointer<ParticipantInfoList> create(const QSharedPointer<ChatCore> &chatCore);
ParticipantInfoList(QObject *parent = Q_NULLPTR);
virtual ~ParticipantInfoList();
void setChatCore(const QSharedPointer<ChatCore> &chatCore);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
signals:
void lUpdateParticipants();
private:
QSharedPointer<ChatCore> mChatCore;
DECLARE_ABSTRACT_OBJECT
};
#endif // PARTICIPANT_INFO_LIST_H_

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