Compare commits
	
		
			164 Commits
		
	
	
		
			nightly/20
			...
			beta/20241
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7152b51597 | |||
| 4a53397561 | |||
| d86a90207a | |||
| 7b298deee8 | |||
| 056cf14613 | |||
| 2e75dd8777 | |||
| 8bda8da414 | |||
| b7fb63ae40 | |||
| 31bd0392da | |||
| 59f3aa7c44 | |||
| 9aeb405644 | |||
| 9e1d8e3e56 | |||
| b65774add0 | |||
| c55486988f | |||
| 39833924af | |||
| a194e86d7a | |||
| 8cfd9bc3fc | |||
| bdec942d72 | |||
| 35d5595401 | |||
| 7330a87082 | |||
| 7243b10e81 | |||
| 964c8e0553 | |||
| 96c00ff019 | |||
| c8716d1113 | |||
| 630e5e9fe4 | |||
| f447327c02 | |||
| 650f98636b | |||
| b92cd902b9 | |||
| b99c2674b4 | |||
| 1524ba0177 | |||
| 5503769023 | |||
| 89354a07e1 | |||
| 69400bee2a | |||
| 0e07f9cee7 | |||
| d2eba1d91e | |||
| 78389d8c28 | |||
| e6d820850a | |||
| 0a7f9349a9 | |||
| 99254f8d02 | |||
| 010a2c4eea | |||
| 61163037d4 | |||
| 3577982a93 | |||
| 3ad0b92dcd | |||
| 91475c3a3f | |||
| 9379af23ec | |||
| 406a251c85 | |||
| 20e2852e44 | |||
| 3225f90ce8 | |||
| df3e76a1cf | |||
| c5e15d26a0 | |||
| 77e019b02b | |||
| 89bed2bf85 | |||
| 519871e458 | |||
| 0a842042b0 | |||
| 9aeb2377dc | |||
| 6ad5f4b850 | |||
| f5c63d24fb | |||
| 5cb34bd31c | |||
| e56a966de1 | |||
| acc0c97234 | |||
| 665af7c0c3 | |||
| fa51e042e5 | |||
| 3b9fb0bfca | |||
| 3673b0646c | |||
| 2e2f6423f8 | |||
| 28c1cbbb34 | |||
| 87c215deb7 | |||
| 77eddcd962 | |||
| 043a715c59 | |||
| 5bd3ead22d | |||
| a9aa1cac80 | |||
| 409ba70258 | |||
| dc50f19815 | |||
| d83895dcc9 | |||
| e24a3d6a4d | |||
| 06de33e1be | |||
| c8fbcd8c6b | |||
| 31269fe8fc | |||
| a676ad395a | |||
| 04c71d02e0 | |||
| 1fe60b9c33 | |||
| 51ef7a83da | |||
| 588a8abdac | |||
| 8a149b6c4f | |||
| 6105f4f7ce | |||
| 92341b27b6 | |||
| f39afdac4c | |||
| 690f2dd85c | |||
| bd45d6a406 | |||
| 5b92e4708a | |||
| 63c01f1439 | |||
| 73aeb02ebd | |||
| 9d91317089 | |||
| 474bc5f6a4 | |||
| f5b64e955b | |||
| b88627d125 | |||
| 200978a044 | |||
| a673ff9890 | |||
| 7803dd0991 | |||
| a8a736bc8c | |||
| ff7acf9932 | |||
| afde816b23 | |||
| 0745c3b798 | |||
| 1376ee1f4b | |||
| 2b03107bd5 | |||
| cd1ab0ed12 | |||
| a13c6ae0e7 | |||
| 1ef9a85148 | |||
| 072eafbaf4 | |||
| 201f3182ca | |||
| 23130a5752 | |||
| f28d47bc51 | |||
| ee7818eefb | |||
| f25e66aa6a | |||
| 79b19aec01 | |||
| 4c92cb9936 | |||
| 1c81553245 | |||
| 5c2fec53da | |||
| f706abe5a6 | |||
| 610c27f751 | |||
| 6d20d3b515 | |||
| a0b583aa8d | |||
| 3855a5e951 | |||
| 6689bce782 | |||
| 860ddf22b6 | |||
| ef716d657d | |||
| b0fe0251d1 | |||
| 1ec2d5f27b | |||
| 23316993e5 | |||
| d42fe78676 | |||
| 78724c2a7b | |||
| e14fbe9437 | |||
| 82c63d5a89 | |||
| a72af9cba5 | |||
| d7c642a2fe | |||
| 08f3339693 | |||
| 402515365d | |||
| df102068bc | |||
| d40e884a1f | |||
| 5371dac882 | |||
| 0f62829588 | |||
| 39da97396c | |||
| 406edda453 | |||
| bbbeda6a26 | |||
| 6b3efff7cc | |||
| 3531b8b354 | |||
| 487446cbc3 | |||
| d5349490f5 | |||
| 7650f45d6f | |||
| a98f6ca4e3 | |||
| 0b96cf5f1f | |||
| 07e0b10478 | |||
| b38e216721 | |||
| 91f32f2421 | |||
| 06c3ffa6ce | |||
| ae53d92c2e | |||
| 97e477416a | |||
| 3d3b4612df | |||
| 7060afe467 | |||
| f56026439a | |||
| 0a24bec5ec | |||
| 38b7880d5f | |||
| 71a88b75ab | |||
| 37e1780762 | 
							
								
								
									
										13
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -1,9 +1,18 @@
 | 
			
		||||
*.user
 | 
			
		||||
doc/Doxyfile
 | 
			
		||||
 | 
			
		||||
### VisualStudioCode ###
 | 
			
		||||
.vscode/**/*
 | 
			
		||||
!.vscode/settings.json
 | 
			
		||||
!.vscode/tasks.json
 | 
			
		||||
!.vscode/launch.json
 | 
			
		||||
!.vscode/extensions.json
 | 
			
		||||
 | 
			
		||||
### VisualStudioCode Patch ###
 | 
			
		||||
# Ignore all local history of files
 | 
			
		||||
**/.history
 | 
			
		||||
 | 
			
		||||
GeneratedFiles/
 | 
			
		||||
.vs/
 | 
			
		||||
.vscode/
 | 
			
		||||
x64/
 | 
			
		||||
x86/
 | 
			
		||||
[wW]in32/
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										49
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,49 @@
 | 
			
		||||
{
 | 
			
		||||
    "version": "0.2.0",
 | 
			
		||||
    "configurations": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Jami-Client-Debug",
 | 
			
		||||
            "type": "cppdbg",
 | 
			
		||||
            "request": "launch",
 | 
			
		||||
            "program": "",
 | 
			
		||||
            "linux":{
 | 
			
		||||
                "MIMode": "gdb",
 | 
			
		||||
                "program": "${workspaceFolder}/build/jami",
 | 
			
		||||
                "args": [
 | 
			
		||||
                    "-d",
 | 
			
		||||
                ],
 | 
			
		||||
            },
 | 
			
		||||
            "osx": {
 | 
			
		||||
                "MIMode": "lldb",
 | 
			
		||||
                "program": "${workspaceFolder}/build/Jami.app/Contents/MacOS/Jami",
 | 
			
		||||
                "environment": [
 | 
			
		||||
                    {
 | 
			
		||||
                        "name": "NO_COLOR",
 | 
			
		||||
                        "value": "true",
 | 
			
		||||
                    }
 | 
			
		||||
                ],
 | 
			
		||||
            },
 | 
			
		||||
            "cwd": "${workspaceFolder}",
 | 
			
		||||
            "preLaunchTask": "cmake-build",
 | 
			
		||||
            "externalConsole": false, // A macOS dev may want to set this to true.
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            // Using this configuration will require manually reconfiguring the project using
 | 
			
		||||
            // build.py --no-libwrap, otherwise the daemon executable will not be built and the
 | 
			
		||||
            // client will not be built with ENABLE_LIBWRAP=False.
 | 
			
		||||
            "name": "Jami-Daemon-Debug",
 | 
			
		||||
            "type": "cppdbg",
 | 
			
		||||
            "request": "launch",
 | 
			
		||||
            "linux": {
 | 
			
		||||
                "MIMode": "gdb",
 | 
			
		||||
                "program": "${workspaceFolder}/daemon/bin/dbus/jamid",
 | 
			
		||||
            },
 | 
			
		||||
            "program": "",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-cdp",
 | 
			
		||||
            ],
 | 
			
		||||
            "cwd": "${workspaceFolder}",
 | 
			
		||||
            "preLaunchTask": "cmake-build",
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,15 @@
 | 
			
		||||
{
 | 
			
		||||
    "C_Cpp.default.includePath": [
 | 
			
		||||
        "${default}",
 | 
			
		||||
        "${workspaceFolder}/**",
 | 
			
		||||
        "/usr/lib/libqt-jami/include/**",
 | 
			
		||||
        "/usr/lib64/qt-jami/include/**",
 | 
			
		||||
    ],
 | 
			
		||||
    "C_Cpp.default.cppStandard": "c++17",
 | 
			
		||||
    "C_Cpp.default.cStandard": "c11",
 | 
			
		||||
    "cmake.configureOnOpen": true,
 | 
			
		||||
    "editor.formatOnSave": true,
 | 
			
		||||
    "editor.defaultFormatter": "xaver.clang-format",
 | 
			
		||||
    "files.eol": "\n",
 | 
			
		||||
    "cSpell.enabled": false,
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,93 @@
 | 
			
		||||
{
 | 
			
		||||
    "version": "2.0.0",
 | 
			
		||||
    "tasks": [
 | 
			
		||||
        {
 | 
			
		||||
            "label": "run-tests",
 | 
			
		||||
            "type": "shell",
 | 
			
		||||
            "command": "ctest",
 | 
			
		||||
            "options": {
 | 
			
		||||
                "cwd": "${workspaceFolder}/build/tests",
 | 
			
		||||
                "env": {
 | 
			
		||||
                    "HOME": "/tmp"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-V",
 | 
			
		||||
                "-R"
 | 
			
		||||
            ],
 | 
			
		||||
            "group": {
 | 
			
		||||
                "kind": "test",
 | 
			
		||||
                "isDefault": true
 | 
			
		||||
            },
 | 
			
		||||
            "problemMatcher": [],
 | 
			
		||||
            "detail": "Run the tests using CTest."
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "label": "cmake-configure",
 | 
			
		||||
            "type": "shell",
 | 
			
		||||
            "command": "cmake",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-S", ".",
 | 
			
		||||
                "-B", "build",
 | 
			
		||||
                "-DCMAKE_BUILD_TYPE=Debug",
 | 
			
		||||
                "-DCMAKE_PREFIX_PATH=\"/usr/lib64/qt-jami;/usr/lib/libqt-jami\"",
 | 
			
		||||
            ],
 | 
			
		||||
            "group": "build",
 | 
			
		||||
            "problemMatcher": [],
 | 
			
		||||
            "detail": "Generate the build system files with CMake."
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "label": "cmake-configure-tests",
 | 
			
		||||
            "type": "shell",
 | 
			
		||||
            "command": "cmake",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-S", ".",
 | 
			
		||||
                "-B", "build",
 | 
			
		||||
                "-DBUILD_TESTING=${input:buildTestingInput}"
 | 
			
		||||
            ],
 | 
			
		||||
            "group": "build",
 | 
			
		||||
            "problemMatcher": [],
 | 
			
		||||
            "detail": "Generate the build system files with CMake."
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "label": "cmake-build",
 | 
			
		||||
            "type": "shell",
 | 
			
		||||
            "command": "cmake",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "--build", "build",
 | 
			
		||||
                "-j$(nproc)",
 | 
			
		||||
            ],
 | 
			
		||||
            "group": {
 | 
			
		||||
                "kind": "build",
 | 
			
		||||
                "isDefault": true
 | 
			
		||||
            },
 | 
			
		||||
            "problemMatcher": [
 | 
			
		||||
                "$gcc"
 | 
			
		||||
            ],
 | 
			
		||||
            "detail": "Compile the project using the generated build system.",
 | 
			
		||||
            "dependsOn": [
 | 
			
		||||
                "cmake-configure"
 | 
			
		||||
            ]
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "label": "cmake-clean",
 | 
			
		||||
            "type": "shell",
 | 
			
		||||
            "command": "rm",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-rf",
 | 
			
		||||
                "build"
 | 
			
		||||
            ],
 | 
			
		||||
            "group": "build",
 | 
			
		||||
            "problemMatcher": [],
 | 
			
		||||
            "detail": "Clean the build directory."
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "inputs": [
 | 
			
		||||
        {
 | 
			
		||||
            "id": "buildTestingInput",
 | 
			
		||||
            "type": "pickString",
 | 
			
		||||
            "description": "Do you want to enable testing?",
 | 
			
		||||
            "options": ["True", "False"],
 | 
			
		||||
        }
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								3rdparty/md4c
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
							
						
						
							
								
								
									
										102
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						@ -29,11 +29,11 @@ else()
 | 
			
		||||
  project(jami)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
include(${PROJECT_SOURCE_DIR}/extras/build/cmake/extra_tools.cmake)
 | 
			
		||||
set(CMAKE_SCRIPTS_DIR ${PROJECT_SOURCE_DIR}/extras/build/cmake)
 | 
			
		||||
include(${CMAKE_SCRIPTS_DIR}/extra_tools.cmake)
 | 
			
		||||
 | 
			
		||||
option(WITH_DAEMON_SUBMODULE "Build with daemon submodule" ON)
 | 
			
		||||
option(JAMICORE_AS_SUBDIR "Build Jami-core as a subdir dependency" OFF)
 | 
			
		||||
option(ENABLE_TESTS "Build with tests" OFF)
 | 
			
		||||
option(WITH_WEBENGINE "Build with WebEngine" ON)
 | 
			
		||||
option(ENABLE_LIBWRAP "Enable libwrap (single process mode)" ON)
 | 
			
		||||
if(NOT (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
 | 
			
		||||
@ -88,7 +88,6 @@ list(APPEND QWINDOWKIT_OPTIONS
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
if(WIN32)
 | 
			
		||||
  list(APPEND QWINDOWKIT_PATCHES ${EXTRA_PATCHES_DIR}/0002-workaround-right-margin.patch)
 | 
			
		||||
  list(APPEND QWINDOWKIT_OPTIONS QWINDOWKIT_ENABLE_WINDOWS_SYSTEM_BORDERS OFF)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
@ -119,6 +118,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
 | 
			
		||||
# src
 | 
			
		||||
set(LIBCLIENT_SRC_DIR ${PROJECT_SOURCE_DIR}/src/libclient)
 | 
			
		||||
set(APP_SRC_DIR ${PROJECT_SOURCE_DIR}/src/app)
 | 
			
		||||
set(VERSION_INFO_DIR ${PROJECT_SOURCE_DIR}/src/version_info)
 | 
			
		||||
# doc
 | 
			
		||||
set(DOC_DIR ${PROJECT_SOURCE_DIR}/doc)
 | 
			
		||||
# extras
 | 
			
		||||
@ -141,6 +141,11 @@ else()
 | 
			
		||||
  find_package(QT NAMES Qt6 REQUIRED)
 | 
			
		||||
endif()
 | 
			
		||||
if (${QT_VERSION_MINOR} GREATER_EQUAL ${QT6_MINVER_MINOR})
 | 
			
		||||
  # Enforce a minimum Qt version of 6.6.2 for the Windows build
 | 
			
		||||
  # https://github.com/stdware/qwindowkit/issues/23
 | 
			
		||||
  if(MSVC AND ${QT_VERSION_MINOR} EQUAL 6 AND ${QT_VERSION_PATCH} LESS 2)
 | 
			
		||||
    message(FATAL_ERROR "Qt 6.6.2 or higher is required. Found ${QT_VERSION}")
 | 
			
		||||
  endif()
 | 
			
		||||
  # Qt version is 6.6 or higher
 | 
			
		||||
  message(STATUS "Found a suitable Qt version ${QT_VERSION}")
 | 
			
		||||
else()
 | 
			
		||||
@ -207,6 +212,23 @@ include(FindPython3)
 | 
			
		||||
find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter)
 | 
			
		||||
set(PYTHON_EXEC ${Python3_EXECUTABLE})
 | 
			
		||||
 | 
			
		||||
# Versioning and build ID generation
 | 
			
		||||
set(VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/version_info.cpp)
 | 
			
		||||
# Touch the file to make sure it exists at configure time as
 | 
			
		||||
# we add it to the target_sources below.
 | 
			
		||||
file(TOUCH ${VERSION_FILE})
 | 
			
		||||
add_custom_target(
 | 
			
		||||
  generate_version_info ALL
 | 
			
		||||
  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
 | 
			
		||||
  COMMAND ${CMAKE_COMMAND}
 | 
			
		||||
  -DAPP_SOURCE_DIR=${CMAKE_SOURCE_DIR}
 | 
			
		||||
  -DAPP_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
 | 
			
		||||
  -DCORE_SOURCE_DIR=${DAEMON_DIR}
 | 
			
		||||
  -DCPP_INT_FILE=${VERSION_INFO_DIR}/version_info.cpp.in
 | 
			
		||||
  -P ${CMAKE_SCRIPTS_DIR}/generate_version_info.cmake
 | 
			
		||||
)
 | 
			
		||||
list(APPEND CLIENT_INCLUDE_DIRS ${VERSION_INFO_DIR})
 | 
			
		||||
 | 
			
		||||
# Resource auto-gen
 | 
			
		||||
# QML and related code files
 | 
			
		||||
# Check files in the app's src directory and force a reconfigure if it
 | 
			
		||||
@ -244,6 +266,7 @@ set(QML_IMPORT_PATH ${QML_DIRS}
 | 
			
		||||
add_definitions(-DQT_NO_KEYWORDS)
 | 
			
		||||
 | 
			
		||||
set(COMMON_SOURCES
 | 
			
		||||
  ${VERSION_FILE}
 | 
			
		||||
  ${APP_SRC_DIR}/bannedlistmodel.cpp
 | 
			
		||||
  ${APP_SRC_DIR}/accountlistmodel.cpp
 | 
			
		||||
  ${APP_SRC_DIR}/networkmanager.cpp
 | 
			
		||||
@ -303,6 +326,7 @@ set(COMMON_SOURCES
 | 
			
		||||
  ${APP_SRC_DIR}/pluginversionmanager.cpp)
 | 
			
		||||
 | 
			
		||||
set(COMMON_HEADERS
 | 
			
		||||
  ${APP_SRC_DIR}/global.h
 | 
			
		||||
  ${APP_SRC_DIR}/avatarimageprovider.h
 | 
			
		||||
  ${APP_SRC_DIR}/networkmanager.h
 | 
			
		||||
  ${APP_SRC_DIR}/smartlistmodel.h
 | 
			
		||||
@ -451,10 +475,12 @@ elseif (NOT APPLE)
 | 
			
		||||
    ${APP_SRC_DIR}/xrectsel.c
 | 
			
		||||
    ${APP_SRC_DIR}/connectivitymonitor.cpp
 | 
			
		||||
    ${APP_SRC_DIR}/dbuserrorhandler.cpp
 | 
			
		||||
    ${APP_SRC_DIR}/appversionmanager.cpp)
 | 
			
		||||
    ${APP_SRC_DIR}/appversionmanager.cpp
 | 
			
		||||
    ${APP_SRC_DIR}/screencastportal.cpp)
 | 
			
		||||
  list(APPEND COMMON_HEADERS
 | 
			
		||||
    ${APP_SRC_DIR}/xrectsel.h
 | 
			
		||||
    ${APP_SRC_DIR}/dbuserrorhandler.h)
 | 
			
		||||
    ${APP_SRC_DIR}/dbuserrorhandler.h
 | 
			
		||||
    ${APP_SRC_DIR}/screencastportal.h)
 | 
			
		||||
  list(APPEND QT_MODULES DBus)
 | 
			
		||||
 | 
			
		||||
  find_package(PkgConfig REQUIRED)
 | 
			
		||||
@ -469,6 +495,11 @@ elseif (NOT APPLE)
 | 
			
		||||
    add_definitions(${GIO_CFLAGS})
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  pkg_check_modules(GIOUNIX REQUIRED gio-unix-2.0)
 | 
			
		||||
  if(GIOUNIX_FOUND)
 | 
			
		||||
    add_definitions(${GIOUNIX_CFLAGS})
 | 
			
		||||
  endif()
 | 
			
		||||
 | 
			
		||||
  pkg_check_modules(LIBNM libnm)
 | 
			
		||||
  if(LIBNM_FOUND)
 | 
			
		||||
    add_definitions(-DUSE_LIBNM)
 | 
			
		||||
@ -580,6 +611,7 @@ include_directories(
 | 
			
		||||
if(ENABLE_LIBWRAP)
 | 
			
		||||
  list(APPEND COMMON_HEADERS
 | 
			
		||||
    ${LIBCLIENT_SRC_DIR}/qtwrapper/instancemanager_wrap.h)
 | 
			
		||||
  add_definitions(-DENABLE_LIBWRAP=true)
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
# SFPM
 | 
			
		||||
@ -588,6 +620,7 @@ add_subdirectory(3rdparty/SortFilterProxyModel)
 | 
			
		||||
set(SFPM_OBJECTS $<TARGET_OBJECTS:SortFilterProxyModel>)
 | 
			
		||||
 | 
			
		||||
# md4c
 | 
			
		||||
set(BUILD_MD2HTML_EXECUTABLE OFF CACHE BOOL "Don't build md2html executable" FORCE)
 | 
			
		||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Don't build shared md4c library" FORCE)
 | 
			
		||||
add_subdirectory(3rdparty/md4c EXCLUDE_FROM_ALL)
 | 
			
		||||
list(APPEND CLIENT_LINK_DIRS ${MD4C_BINARY_DIR}/src)
 | 
			
		||||
@ -613,6 +646,9 @@ qt_add_executable(
 | 
			
		||||
  ${QML_RESOURCES_QML}
 | 
			
		||||
  ${SFPM_OBJECTS})
 | 
			
		||||
 | 
			
		||||
# Make sure we can find the generated version file
 | 
			
		||||
add_dependencies(${PROJECT_NAME} generate_version_info)
 | 
			
		||||
 | 
			
		||||
foreach(MODULE ${QT_MODULES})
 | 
			
		||||
  list(APPEND QT_LIBS "Qt::${MODULE}")
 | 
			
		||||
endforeach()
 | 
			
		||||
@ -806,12 +842,20 @@ else()
 | 
			
		||||
    "-framework Security"
 | 
			
		||||
      compression
 | 
			
		||||
      resolv
 | 
			
		||||
    )
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  set(APP_CONTAINER "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents")
 | 
			
		||||
 | 
			
		||||
  # ringtones. Copy the entire directory to the app bundle.
 | 
			
		||||
  # daemon/ringtones -> Jami.app/Contents/Resources/ringtones
 | 
			
		||||
  execute_process(
 | 
			
		||||
    COMMAND ${CMAKE_COMMAND} -E copy_directory
 | 
			
		||||
    ${DAEMON_DIR}/ringtones
 | 
			
		||||
    ${APP_CONTAINER}/Resources/ringtones
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  # translations
 | 
			
		||||
  if(Qt${QT_VERSION_MAJOR}LinguistTools_FOUND)
 | 
			
		||||
    set(APP_CONTAINER
 | 
			
		||||
      "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents")
 | 
			
		||||
    file(GLOB TS_FILES ${PROJECT_SOURCE_DIR}/translations/*.ts)
 | 
			
		||||
 | 
			
		||||
    # Generate lproj folders.
 | 
			
		||||
@ -839,26 +883,26 @@ else()
 | 
			
		||||
          MACOSX_BUNDLE_SHORT_VERSION_STRING "${JAMI_VERSION}"
 | 
			
		||||
          MACOSX_BUNDLE_BUNDLE_VERSION "${JAMI_BUILD}"
 | 
			
		||||
          MACOSX_BUNDLE_COPYRIGHT "${PROJ_COPYRIGHT}")
 | 
			
		||||
      if(APPSTORE)
 | 
			
		||||
          message(STATUS "app store version")
 | 
			
		||||
          set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
			
		||||
               XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/appstore/Jami.entitlements")
 | 
			
		||||
      else()
 | 
			
		||||
          set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
			
		||||
                SPARKLE_URL "${SPARKLE_URL}"
 | 
			
		||||
                SPARKLE_PUBLIC_KEY "${SPARKLE_PUBLIC_KEY}"
 | 
			
		||||
                XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/Jami.entitlements"
 | 
			
		||||
                XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE)
 | 
			
		||||
      endif()
 | 
			
		||||
      if(DEPLOY)
 | 
			
		||||
          add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
 | 
			
		||||
                             COMMAND ${CMAKE_COMMAND} -DQML_SRC_DIR=${SRC_DIR}
 | 
			
		||||
                             -DMAC_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin
 | 
			
		||||
                             -DEXE_NAME="${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app"
 | 
			
		||||
                             -DSPARKLE_PATH=${SPARKLE_FRAMEWORK}
 | 
			
		||||
                             -DENABLE_SPARKLE=${ENABLE_SPARKLE}
 | 
			
		||||
                             -P ${EXTRAS_DIR}/build/cmake/macos_qt_deploy.cmake)
 | 
			
		||||
      endif()
 | 
			
		||||
  if(APPSTORE)
 | 
			
		||||
    message(STATUS "app store version")
 | 
			
		||||
    set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
			
		||||
          XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/appstore/Jami.entitlements")
 | 
			
		||||
  else()
 | 
			
		||||
    set_target_properties(${PROJECT_NAME} PROPERTIES
 | 
			
		||||
          SPARKLE_URL "${SPARKLE_URL}"
 | 
			
		||||
          SPARKLE_PUBLIC_KEY "${SPARKLE_PUBLIC_KEY}"
 | 
			
		||||
          XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/Jami.entitlements"
 | 
			
		||||
          XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE)
 | 
			
		||||
  endif()
 | 
			
		||||
  if(DEPLOY)
 | 
			
		||||
    execute_process(COMMAND
 | 
			
		||||
      "${CMAKE_PREFIX_PATH}/bin/macdeployqt"
 | 
			
		||||
      "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app"
 | 
			
		||||
      -qmldir=${QML_SRC_DIR})
 | 
			
		||||
    if(${ENABLE_SPARKLE} MATCHES true)
 | 
			
		||||
      file(COPY ${SPARKLE_FRAMEWORK} DESTINATION ${EXE_NAME}/Contents/Frameworks/)
 | 
			
		||||
    endif()
 | 
			
		||||
  endif()
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
target_include_directories(${PROJECT_NAME} PRIVATE ${CLIENT_INCLUDE_DIRS})
 | 
			
		||||
@ -869,7 +913,7 @@ qt_import_qml_plugins(${PROJECT_NAME})
 | 
			
		||||
qt_finalize_executable(${PROJECT_NAME})
 | 
			
		||||
 | 
			
		||||
# tests
 | 
			
		||||
if(ENABLE_TESTS)
 | 
			
		||||
if(BUILD_TESTING)
 | 
			
		||||
  message("Add Jami tests")
 | 
			
		||||
  add_subdirectory(${TESTS_DIR})
 | 
			
		||||
endif()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										15
									
								
								INSTALL.md
									
									
									
									
									
								
							
							
						
						@ -14,7 +14,7 @@ So, you will need to get Qt 6.6 first. For this, there is 3 methods:
 | 
			
		||||
### Qt from our repo (recommended)
 | 
			
		||||
 | 
			
		||||
If your distribution is supported, we provide a Qt package (libqt-jami) on our repo.
 | 
			
		||||
The files will be installed in `/usr/lib/libqt-jami`.
 | 
			
		||||
The files will be installed to `/usr/lib/libqt-jami` on Debian-like distributions. For RPM based distributions the files will be installed to `/usr/lib64/qt-jami`.
 | 
			
		||||
 | 
			
		||||
#### Install libqt-jami, Ubuntu based
 | 
			
		||||
 | 
			
		||||
@ -131,6 +131,11 @@ Notes:
 | 
			
		||||
 | 
			
		||||
- `--global-install` to install client-qt globally under /usr/local
 | 
			
		||||
- `--prefix` to change the destination of the install.
 | 
			
		||||
+ For developers:
 | 
			
		||||
    + `--asan` add address sanitizer on the binary
 | 
			
		||||
    + `--debug` enable debug symbols
 | 
			
		||||
    + `--testing` will build the tests for both the daemon and client
 | 
			
		||||
    + `--no-libwrap` will build the DBUS version.
 | 
			
		||||
 | 
			
		||||
## Build only the client
 | 
			
		||||
 | 
			
		||||
@ -207,7 +212,7 @@ Only 64-bit MSVC build can be compiled.
 | 
			
		||||
 | 
			
		||||
  |                      | Qt Version |
 | 
			
		||||
  | -------------------- | ---------- |
 | 
			
		||||
  | Minimum requirement: | 6.6.1      |
 | 
			
		||||
  | Minimum requirement: | 6.6.2      |
 | 
			
		||||
 | 
			
		||||
- Install [Python3](https://www.python.org/downloads/) for Windows
 | 
			
		||||
 | 
			
		||||
@ -233,7 +238,7 @@ Only 64-bit MSVC build can be compiled.
 | 
			
		||||
- Using a new **Non-Elevated Command Prompt**
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
    python build.py --install --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.1/msvc2019_64)
 | 
			
		||||
    python build.py --install --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.2/msvc2019_64)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> **SDK** Note:
 | 
			
		||||
@ -276,14 +281,14 @@ Once the build has finished, you should then be able to use the Visual Studio So
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
    python extras\scripts\build-windows.py --init
 | 
			
		||||
    python extras\scripts\build-windows.py --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.1/msvc2019_64)
 | 
			
		||||
    python extras\scripts\build-windows.py --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.2/msvc2019_64)
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Building On MacOS
 | 
			
		||||
 | 
			
		||||
**Set up**
 | 
			
		||||
 | 
			
		||||
- macOS minimum version 10.15
 | 
			
		||||
- macOS minimum version 11.0
 | 
			
		||||
- install python3
 | 
			
		||||
- download xcode
 | 
			
		||||
- install Qt 6.6
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								build.py
									
									
									
									
									
								
							
							
						
						@ -100,7 +100,7 @@ ZYPPER_DEPENDENCIES = [
 | 
			
		||||
    'speexdsp-devel', 'speex-devel', 'libdbus-c++-devel', 'jsoncpp-devel', 'yaml-cpp-devel',
 | 
			
		||||
    'yasm', 'libuuid-devel', 'libnettle-devel', 'libopus-devel', 'libexpat-devel',
 | 
			
		||||
    'libgnutls-devel', 'msgpack-c-devel', 'msgpack-cxx-devel', 'libavcodec-devel', 'libavdevice-devel', 'pcre-devel',
 | 
			
		||||
    'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel',
 | 
			
		||||
    'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel', 'pipewire-devel',
 | 
			
		||||
    'libopenssl-devel', 'libavutil-devel',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -130,7 +130,7 @@ DNF_DEPENDENCIES = [
 | 
			
		||||
    'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel',
 | 
			
		||||
    'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel',
 | 
			
		||||
    'yaml-cpp-devel', 'swig', 'jsoncpp-devel',
 | 
			
		||||
    'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'msgpack-devel',
 | 
			
		||||
    'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'pipewire-devel', 'msgpack-devel',
 | 
			
		||||
    'sqlite-devel', 'openssl-static', 'pandoc', 'nasm',
 | 
			
		||||
    'bzip2'
 | 
			
		||||
]
 | 
			
		||||
@ -154,7 +154,7 @@ APT_DEPENDENCIES = [
 | 
			
		||||
    'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libssl-dev',
 | 
			
		||||
    'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool',
 | 
			
		||||
    'libudev-dev', 'libyaml-cpp-dev', 'sip-tester', 'swig',
 | 
			
		||||
    'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libmsgpack-dev',
 | 
			
		||||
    'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libpipewire-0.3-dev', 'libmsgpack-dev',
 | 
			
		||||
    'pandoc', 'nasm', 'dpkg-dev', 'libsystemd-dev'
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -389,6 +389,8 @@ def run_install(args):
 | 
			
		||||
        install_args.append('-u')
 | 
			
		||||
    if args.debug:
 | 
			
		||||
        install_args.append('-d')
 | 
			
		||||
    if args.testing:
 | 
			
		||||
        install_args.append('-t')
 | 
			
		||||
    if args.asan:
 | 
			
		||||
        install_args.append('-A')
 | 
			
		||||
    if args.no_libwrap:
 | 
			
		||||
@ -397,6 +399,8 @@ def run_install(args):
 | 
			
		||||
        install_args.append('-w')
 | 
			
		||||
    if args.arch:
 | 
			
		||||
        install_args += ('-a', args.arch)
 | 
			
		||||
    if args.extra_cmake_flags:
 | 
			
		||||
        install_args += ('-D', args.extra_cmake_flags)
 | 
			
		||||
 | 
			
		||||
    if args.distribution == OSX_DISTRIBUTION_NAME:
 | 
			
		||||
        # The `universal_newlines` parameter has been renamed to `text` in
 | 
			
		||||
@ -725,6 +729,9 @@ def parse_args():
 | 
			
		||||
                    default=True, action='store_false')
 | 
			
		||||
    ap.add_argument('--qt', type=str,
 | 
			
		||||
                    help='Use the Qt path supplied')
 | 
			
		||||
    ap.add_argument('--testing', dest='testing',
 | 
			
		||||
                    default=False, action='store_true',
 | 
			
		||||
                    help='Enable testing for both client and daemon')
 | 
			
		||||
    ap.add_argument('--no-libwrap', dest='no_libwrap',
 | 
			
		||||
                    default=False, action='store_true',
 | 
			
		||||
                    help='Disable libwrap. Also set --disable-shared option to daemon configure')
 | 
			
		||||
@ -740,6 +747,9 @@ def parse_args():
 | 
			
		||||
    ap.add_argument('--pywinmake', dest='pywinmake',
 | 
			
		||||
                    default=False, action='store_true',
 | 
			
		||||
                    help='Build Jami for Windows using pywinmake')
 | 
			
		||||
    # Allow supplying extra congifure flags to the client cmake.
 | 
			
		||||
    ap.add_argument('--extra-cmake-flags', type=str,
 | 
			
		||||
                    help='Extra flags to pass to the client cmake')
 | 
			
		||||
 | 
			
		||||
    dist = choose_distribution()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								daemon
									
									
									
									
									
								
							
							
								
								
								
								
								
							
						
						
							
								
								
									
										34
									
								
								extras/build/cmake/generate_version_info.cmake
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,34 @@
 | 
			
		||||
find_package(Git QUIET REQUIRED)
 | 
			
		||||
 | 
			
		||||
message(STATUS "Generating version information...")
 | 
			
		||||
 | 
			
		||||
function(configure_version_string SOURCE_DIR VERSION_STRING_OUT)
 | 
			
		||||
  # Get short git SHA
 | 
			
		||||
  execute_process(
 | 
			
		||||
    COMMAND "${GIT_EXECUTABLE}" rev-parse --short HEAD
 | 
			
		||||
    WORKING_DIRECTORY "${SOURCE_DIR}"
 | 
			
		||||
    OUTPUT_VARIABLE _GIT_SHA
 | 
			
		||||
    OUTPUT_STRIP_TRAILING_WHITESPACE
 | 
			
		||||
  )
 | 
			
		||||
 | 
			
		||||
  # Output the VERSION_STRING_OUT to the caller
 | 
			
		||||
  set(${VERSION_STRING_OUT} "${_GIT_SHA}" PARENT_SCOPE)
 | 
			
		||||
endfunction()
 | 
			
		||||
 | 
			
		||||
# These need to be set to the parent scripts values for configure_file to work,
 | 
			
		||||
# as it prepends CMAKE_CURRENT_SOURCE_DIR to the <input> and CMAKE_CURRENT_BINARY_DIR
 | 
			
		||||
# to <output>.
 | 
			
		||||
set(CMAKE_CURRENT_SOURCE_DIR ${APP_SOURCE_DIR})
 | 
			
		||||
set(CMAKE_CURRENT_BINARY_DIR ${APP_BINARY_DIR})
 | 
			
		||||
 | 
			
		||||
# Generate the version string for the application and core
 | 
			
		||||
configure_version_string(${APP_SOURCE_DIR} APP_VERSION_STRING)
 | 
			
		||||
configure_version_string(${CORE_SOURCE_DIR} CORE_VERSION_STRING)
 | 
			
		||||
 | 
			
		||||
# Get output file names with the .in extension removed
 | 
			
		||||
get_filename_component(VERSION_CPP_FILENAME ${CPP_INT_FILE} NAME_WE)
 | 
			
		||||
set(VERSION_CPP_FILE "${CMAKE_CURRENT_BINARY_DIR}/${VERSION_CPP_FILENAME}.cpp")
 | 
			
		||||
 | 
			
		||||
message(STATUS "infiles: ${CPP_INT_FILE}")
 | 
			
		||||
message(STATUS "outfiles: ${VERSION_CPP_FILE}")
 | 
			
		||||
configure_file(${CPP_INT_FILE} ${VERSION_CPP_FILE})
 | 
			
		||||
@ -1,7 +0,0 @@
 | 
			
		||||
message("Qt deploying in dir " ${QML_SRC_DIR})
 | 
			
		||||
execute_process(COMMAND "${MAC_DEPLOY_QT_PATH}/macdeployqt"
 | 
			
		||||
                            ${EXE_NAME}
 | 
			
		||||
                            -qmldir=${QML_SRC_DIR})
 | 
			
		||||
if(${ENABLE_SPARKLE} MATCHES true)
 | 
			
		||||
    file(COPY ${SPARKLE_PATH} DESTINATION ${EXE_NAME}/Contents/Frameworks/)
 | 
			
		||||
endif()
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
FROM ubuntu:20.04
 | 
			
		||||
FROM ubuntu:22.04
 | 
			
		||||
 | 
			
		||||
ENV DEBIAN_FRONTEND noninteractive
 | 
			
		||||
ENV QT_QUICK_BACKEND software
 | 
			
		||||
@ -10,7 +10,7 @@ RUN apt-get update && \
 | 
			
		||||
 | 
			
		||||
RUN apt install gnupg dirmngr ca-certificates curl --no-install-recommends
 | 
			
		||||
RUN curl -s https://dl.jami.net/public-key.gpg | tee /usr/share/keyrings/jami-archive-keyring.gpg > /dev/null
 | 
			
		||||
RUN sh -c "echo 'deb [signed-by=/usr/share/keyrings/jami-archive-keyring.gpg] https://dl.jami.net/internal/ubuntu_20.04/ jami main' > /etc/apt/sources.list.d/jami.list"
 | 
			
		||||
RUN sh -c "echo 'deb [signed-by=/usr/share/keyrings/jami-archive-keyring.gpg] https://dl.jami.net/internal/ubuntu_22.04/ jami main' > /etc/apt/sources.list.d/jami.list"
 | 
			
		||||
RUN apt-get update && apt-get install libqt-jami -y
 | 
			
		||||
 | 
			
		||||
RUN apt-get install -y -o Acquire::Retries=10 \
 | 
			
		||||
@ -51,6 +51,7 @@ RUN apt-get install -y -o Acquire::Retries=10 \
 | 
			
		||||
        libswscale-dev \
 | 
			
		||||
        libavdevice-dev \
 | 
			
		||||
        libopus-dev \
 | 
			
		||||
        libpipewire-0.3-dev \
 | 
			
		||||
        libudev-dev \
 | 
			
		||||
        libgsm1-dev \
 | 
			
		||||
        libjsoncpp-dev \
 | 
			
		||||
@ -65,6 +66,7 @@ RUN apt-get install -y -o Acquire::Retries=10 \
 | 
			
		||||
        libvdpau-dev \
 | 
			
		||||
        libssl-dev
 | 
			
		||||
RUN apt-get install -y pandoc \
 | 
			
		||||
        libcppunit-dev \
 | 
			
		||||
        googletest \
 | 
			
		||||
        libgtest-dev \
 | 
			
		||||
        wget
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								extras/ci/client-qt-gnulinux/Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -113,7 +113,7 @@ pipeline {
 | 
			
		||||
                                    cd ${dockerTopDir}
 | 
			
		||||
                                    ./build.py --install --qt /usr/lib/libqt-jami/
 | 
			
		||||
                                    cd build
 | 
			
		||||
                                    cmake .. -DENABLE_TESTS=True
 | 
			
		||||
                                    cmake .. -DBUILD_TESTING=True
 | 
			
		||||
                                    make -j${cpuCount}
 | 
			
		||||
                                """)
 | 
			
		||||
                                // Run tests
 | 
			
		||||
 | 
			
		||||
@ -49,7 +49,7 @@ QT_MAJOR := 6
 | 
			
		||||
QT_MINOR := 6
 | 
			
		||||
QT_PATCH := 1
 | 
			
		||||
QT_TARBALL_CHECKSUM := dd3668f65645fe270bc615d748bd4dc048bd17b9dc297025106e6ecc419ab95d
 | 
			
		||||
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-0
 | 
			
		||||
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-1
 | 
			
		||||
DEBIAN_QT_DSC_FILENAME := libqt-jami_$(DEBIAN_QT_VERSION).dsc
 | 
			
		||||
QT_JAMI_PREFIX := /usr/lib/libqt-jami
 | 
			
		||||
 | 
			
		||||
@ -166,11 +166,14 @@ DISTRIBUTIONS := \
 | 
			
		||||
	debian_unstable \
 | 
			
		||||
	ubuntu_20.04 \
 | 
			
		||||
	ubuntu_22.04 \
 | 
			
		||||
	ubuntu_23.04 \
 | 
			
		||||
	ubuntu_23.10 \
 | 
			
		||||
	ubuntu_24.04 \
 | 
			
		||||
	ubuntu_24.10 \
 | 
			
		||||
	fedora_37 \
 | 
			
		||||
	fedora_38 \
 | 
			
		||||
	fedora_39 \
 | 
			
		||||
	fedora_40 \
 | 
			
		||||
	fedora_41 \
 | 
			
		||||
	alma_9 \
 | 
			
		||||
	opensuse-leap_15.4 \
 | 
			
		||||
	opensuse-leap_15.5 \
 | 
			
		||||
 | 
			
		||||
@ -100,6 +100,7 @@ RUN dnf install -y \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        python3-html5lib \
 | 
			
		||||
        cups-devel
 | 
			
		||||
        cups-devel \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
CMD ["/opt/build-package-rpm.sh"]
 | 
			
		||||
@ -28,4 +28,10 @@ ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
 | 
			
		||||
RUN /opt/install-cmake.sh
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
 | 
			
		||||
 | 
			
		||||
# Setting this variable so that FFmpeg gets built without pipewiregrab
 | 
			
		||||
# (see daemon/contrib/bootstrap and daemon/contrib/src/ffmpeg/rules.mak)
 | 
			
		||||
# We rely on PipeWire for screen sharing on Wayland, but the version available on Debian 11 is too old.
 | 
			
		||||
ENV DISABLE_PIPEWIRE=true
 | 
			
		||||
 | 
			
		||||
CMD ["/opt/build-package-debian.sh"]
 | 
			
		||||
 | 
			
		||||
@ -27,9 +27,7 @@ RUN /opt/prebuild-package-debian.sh qt-deps
 | 
			
		||||
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
 | 
			
		||||
RUN /opt/prebuild-package-debian.sh jami-deps
 | 
			
		||||
 | 
			
		||||
# Install CMake 3.21 for Qt 6
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
 | 
			
		||||
RUN /opt/install-cmake.sh
 | 
			
		||||
RUN apt-get remove -y libre2-dev libre2-11
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
 | 
			
		||||
CMD ["/opt/build-package-debian.sh"]
 | 
			
		||||
 | 
			
		||||
@ -27,9 +27,7 @@ RUN /opt/prebuild-package-debian.sh qt-deps
 | 
			
		||||
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
 | 
			
		||||
RUN /opt/prebuild-package-debian.sh jami-deps
 | 
			
		||||
 | 
			
		||||
# Install CMake 3.21 for Qt 6
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
 | 
			
		||||
RUN /opt/install-cmake.sh
 | 
			
		||||
RUN apt-get remove -y libre2-dev libre2-11
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
 | 
			
		||||
CMD ["/opt/build-package-debian.sh"]
 | 
			
		||||
 | 
			
		||||
@ -98,6 +98,7 @@ RUN dnf install -y \
 | 
			
		||||
        clang \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        pipewire-devel \
 | 
			
		||||
        cups-devel #Chromium for Qt
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
 | 
			
		||||
@ -98,7 +98,8 @@ RUN dnf install -y \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        python3-html5lib \
 | 
			
		||||
        cups-devel
 | 
			
		||||
        cups-devel \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -97,7 +97,8 @@ RUN dnf install -y \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        python3.10 \
 | 
			
		||||
        cups-devel
 | 
			
		||||
        cups-devel \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								extras/packaging/gnu-linux/docker/Dockerfile_fedora_40
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,105 @@
 | 
			
		||||
FROM fedora:40
 | 
			
		||||
 | 
			
		||||
RUN dnf clean all
 | 
			
		||||
RUN dnf update -y
 | 
			
		||||
 | 
			
		||||
RUN dnf install -y dnf-command\(builddep\) rpmdevtools && \
 | 
			
		||||
    dnf install -y mock
 | 
			
		||||
 | 
			
		||||
RUN dnf groupinstall -y "X Software Development"
 | 
			
		||||
 | 
			
		||||
RUN dnf install -y \
 | 
			
		||||
        git \
 | 
			
		||||
        rpm-build \
 | 
			
		||||
        tar \
 | 
			
		||||
        make \
 | 
			
		||||
        autoconf \
 | 
			
		||||
        automake \
 | 
			
		||||
        nasm \
 | 
			
		||||
        speexdsp-devel \
 | 
			
		||||
        pulseaudio-libs-devel \
 | 
			
		||||
        libcanberra-devel \
 | 
			
		||||
        libcurl-devel \
 | 
			
		||||
        libtool \
 | 
			
		||||
        mesa-libgbm-devel \
 | 
			
		||||
        mesa-dri-drivers \
 | 
			
		||||
        dbus-devel \
 | 
			
		||||
        expat-devel \
 | 
			
		||||
        pcre-devel \
 | 
			
		||||
        yaml-cpp-devel \
 | 
			
		||||
        libXext-devel \
 | 
			
		||||
        libXfixes-devel \
 | 
			
		||||
        yasm \
 | 
			
		||||
        speex-devel \
 | 
			
		||||
        gsm-devel \
 | 
			
		||||
        chrpath \
 | 
			
		||||
        check \
 | 
			
		||||
        astyle \
 | 
			
		||||
        uuid-c++-devel \
 | 
			
		||||
        gettext-devel \
 | 
			
		||||
        gcc-c++ \
 | 
			
		||||
        which \
 | 
			
		||||
        alsa-lib-devel \
 | 
			
		||||
        systemd-devel \
 | 
			
		||||
        libuuid-devel \
 | 
			
		||||
        uuid-devel \
 | 
			
		||||
        gnutls-devel \
 | 
			
		||||
        nettle-devel \
 | 
			
		||||
        opus-devel \
 | 
			
		||||
        patch \
 | 
			
		||||
        jsoncpp-devel \
 | 
			
		||||
        libnatpmp-devel \
 | 
			
		||||
        webkitgtk4-devel \
 | 
			
		||||
        cryptopp-devel \
 | 
			
		||||
        libva-devel \
 | 
			
		||||
        libvdpau-devel \
 | 
			
		||||
        msgpack-devel \
 | 
			
		||||
        NetworkManager-libnm-devel \
 | 
			
		||||
        openssl-devel \
 | 
			
		||||
        clutter-devel \
 | 
			
		||||
        clutter-gtk-devel \
 | 
			
		||||
        libappindicator-gtk3-devel \
 | 
			
		||||
        libnotify-devel \
 | 
			
		||||
        libupnp-devel \
 | 
			
		||||
        qrencode-devel \
 | 
			
		||||
        libargon2-devel \
 | 
			
		||||
        libsndfile-devel \
 | 
			
		||||
        libdrm \
 | 
			
		||||
        gperf \
 | 
			
		||||
        bison \
 | 
			
		||||
        clang \
 | 
			
		||||
        clang-devel \
 | 
			
		||||
        llvm-devel \
 | 
			
		||||
        nodejs \
 | 
			
		||||
        flex \
 | 
			
		||||
        gstreamer1 gstreamer1-devel \
 | 
			
		||||
        gstreamer1-plugins-base-devel \
 | 
			
		||||
        gstreamer1-plugins-good \
 | 
			
		||||
        gstreamer1-plugins-bad-free-devel \
 | 
			
		||||
        nss-devel \
 | 
			
		||||
        libxcb* \
 | 
			
		||||
        libxkb* \
 | 
			
		||||
        libX11-devel \
 | 
			
		||||
        vulkan-devel \
 | 
			
		||||
        libXrender-devel \
 | 
			
		||||
        xcb-util-* \
 | 
			
		||||
        xz \
 | 
			
		||||
        xkeyboard-config \
 | 
			
		||||
        libnotify \
 | 
			
		||||
        wget \
 | 
			
		||||
        libstdc++-static \
 | 
			
		||||
        sqlite-devel \
 | 
			
		||||
        perl-generators \
 | 
			
		||||
        perl-English \
 | 
			
		||||
        libxshmfence-devel \
 | 
			
		||||
        ninja-build \
 | 
			
		||||
        clang \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        python3.10 \
 | 
			
		||||
        cups-devel \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
 | 
			
		||||
CMD ["/opt/build-package-rpm.sh"]
 | 
			
		||||
							
								
								
									
										103
									
								
								extras/packaging/gnu-linux/docker/Dockerfile_fedora_41
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,103 @@
 | 
			
		||||
FROM fedora:41
 | 
			
		||||
 | 
			
		||||
RUN dnf clean all
 | 
			
		||||
RUN dnf update -y
 | 
			
		||||
 | 
			
		||||
RUN dnf install -y dnf-command\(builddep\) rpmdevtools && \
 | 
			
		||||
    dnf install -y mock
 | 
			
		||||
 | 
			
		||||
RUN dnf group install -y x-software-development
 | 
			
		||||
 | 
			
		||||
RUN dnf install -y \
 | 
			
		||||
        git \
 | 
			
		||||
        rpm-build \
 | 
			
		||||
        tar \
 | 
			
		||||
        make \
 | 
			
		||||
        autoconf \
 | 
			
		||||
        automake \
 | 
			
		||||
        nasm \
 | 
			
		||||
        speexdsp-devel \
 | 
			
		||||
        pulseaudio-libs-devel \
 | 
			
		||||
        libcanberra-devel \
 | 
			
		||||
        libcurl-devel \
 | 
			
		||||
        libtool \
 | 
			
		||||
        mesa-libgbm-devel \
 | 
			
		||||
        mesa-dri-drivers \
 | 
			
		||||
        dbus-devel \
 | 
			
		||||
        expat-devel \
 | 
			
		||||
        pcre-devel \
 | 
			
		||||
        yaml-cpp-devel \
 | 
			
		||||
        libXext-devel \
 | 
			
		||||
        libXfixes-devel \
 | 
			
		||||
        yasm \
 | 
			
		||||
        speex-devel \
 | 
			
		||||
        gsm-devel \
 | 
			
		||||
        chrpath \
 | 
			
		||||
        check \
 | 
			
		||||
        astyle \
 | 
			
		||||
        uuid-c++-devel \
 | 
			
		||||
        gettext-devel \
 | 
			
		||||
        gcc-c++ \
 | 
			
		||||
        which \
 | 
			
		||||
        alsa-lib-devel \
 | 
			
		||||
        systemd-devel \
 | 
			
		||||
        libuuid-devel \
 | 
			
		||||
        uuid-devel \
 | 
			
		||||
        gnutls-devel \
 | 
			
		||||
        nettle-devel \
 | 
			
		||||
        opus-devel \
 | 
			
		||||
        patch \
 | 
			
		||||
        jsoncpp-devel \
 | 
			
		||||
        libnatpmp-devel \
 | 
			
		||||
        webkitgtk4-devel \
 | 
			
		||||
        cryptopp-devel \
 | 
			
		||||
        libva-devel \
 | 
			
		||||
        libvdpau-devel \
 | 
			
		||||
        msgpack-devel \
 | 
			
		||||
        NetworkManager-libnm-devel \
 | 
			
		||||
        openssl-devel \
 | 
			
		||||
        clutter-devel \
 | 
			
		||||
        clutter-gtk-devel \
 | 
			
		||||
        libappindicator-gtk3-devel \
 | 
			
		||||
        libnotify-devel \
 | 
			
		||||
        libupnp-devel \
 | 
			
		||||
        qrencode-devel \
 | 
			
		||||
        libargon2-devel \
 | 
			
		||||
        libsndfile-devel \
 | 
			
		||||
        libdrm \
 | 
			
		||||
        gperf \
 | 
			
		||||
        bison \
 | 
			
		||||
        clang18-devel \
 | 
			
		||||
        llvm18-devel \
 | 
			
		||||
        nodejs \
 | 
			
		||||
        flex \
 | 
			
		||||
        gstreamer1 gstreamer1-devel \
 | 
			
		||||
        gstreamer1-plugins-base-devel \
 | 
			
		||||
        gstreamer1-plugins-good \
 | 
			
		||||
        gstreamer1-plugins-bad-free-devel \
 | 
			
		||||
        nss-devel \
 | 
			
		||||
        libxcb* \
 | 
			
		||||
        libxkb* \
 | 
			
		||||
        libX11-devel \
 | 
			
		||||
        vulkan-devel \
 | 
			
		||||
        libXrender-devel \
 | 
			
		||||
        xcb-util-* \
 | 
			
		||||
        xz \
 | 
			
		||||
        xkeyboard-config \
 | 
			
		||||
        libnotify \
 | 
			
		||||
        wget \
 | 
			
		||||
        libstdc++-static \
 | 
			
		||||
        sqlite-devel \
 | 
			
		||||
        perl-generators \
 | 
			
		||||
        perl-English \
 | 
			
		||||
        libxshmfence-devel \
 | 
			
		||||
        ninja-build \
 | 
			
		||||
        cmake \
 | 
			
		||||
        fmt-devel \
 | 
			
		||||
        python3.10 \
 | 
			
		||||
        cups-devel \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
 | 
			
		||||
 | 
			
		||||
CMD ["/opt/build-package-rpm.sh"]
 | 
			
		||||
@ -99,7 +99,8 @@ RUN zypper --non-interactive install -y \
 | 
			
		||||
        gstreamer-plugins-bad-devel \
 | 
			
		||||
        gstreamer-plugins-base-devel \
 | 
			
		||||
        cmake \
 | 
			
		||||
        wget
 | 
			
		||||
        wget \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
# openSUSE Leap 15.4 comes with Python 3.6 by default,
 | 
			
		||||
# but we need at least 3.7 to compile Qt 6.6.1
 | 
			
		||||
@ -112,4 +113,10 @@ ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-r
 | 
			
		||||
 | 
			
		||||
ENV CC=gcc
 | 
			
		||||
ENV CXX=g++
 | 
			
		||||
 | 
			
		||||
# Setting this variable so that FFmpeg gets built without pipewiregrab
 | 
			
		||||
# (see daemon/contrib/bootstrap and daemon/contrib/src/ffmpeg/rules.mak)
 | 
			
		||||
# We rely on PipeWire for screen sharing on Wayland, but the version available on openSUSE Leap 15.4 is too old.
 | 
			
		||||
ENV DISABLE_PIPEWIRE=true
 | 
			
		||||
 | 
			
		||||
CMD ["/opt/build-package-rpm.sh"]
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
FROM opensuse/leap:15.5
 | 
			
		||||
 | 
			
		||||
RUN zypper refresh
 | 
			
		||||
RUN zypper --gpg-auto-import-keys refresh
 | 
			
		||||
 | 
			
		||||
RUN zypper --non-interactive install -y \
 | 
			
		||||
        dnf \
 | 
			
		||||
@ -100,7 +100,8 @@ RUN zypper --non-interactive install -y \
 | 
			
		||||
        gstreamer-plugins-bad-devel \
 | 
			
		||||
        gstreamer-plugins-base-devel \
 | 
			
		||||
        cmake \
 | 
			
		||||
        wget
 | 
			
		||||
        wget \
 | 
			
		||||
        pipewire-devel
 | 
			
		||||
 | 
			
		||||
# openSUSE Leap 15.5 comes with Python 3.6 by default,
 | 
			
		||||
# but we need at least 3.7 to compile Qt 6.6.1
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,11 @@ COPY --from=builder /snap/snapcraft /snap/snapcraft
 | 
			
		||||
COPY --from=builder /snap/bin/snapcraft /snap/bin/snapcraft
 | 
			
		||||
 | 
			
		||||
# Generate locale and install dependencies.
 | 
			
		||||
RUN apt-get update && apt-get dist-upgrade --yes && apt-get install --yes snapd sudo apt-transport-https locales && locale-gen en_US.UTF-8
 | 
			
		||||
RUN apt-get update && apt-get dist-upgrade --yes && apt-get install --yes snapd sudo apt-transport-https locales wget && locale-gen en_US.UTF-8
 | 
			
		||||
 | 
			
		||||
# Install CMake 3.21 for Qt 6
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
 | 
			
		||||
RUN /opt/install-cmake.sh
 | 
			
		||||
 | 
			
		||||
# Set the proper environment.
 | 
			
		||||
ENV LANG="en_US.UTF-8"
 | 
			
		||||
 | 
			
		||||
@ -33,4 +33,10 @@ ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
 | 
			
		||||
RUN /opt/install-cmake.sh
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
 | 
			
		||||
 | 
			
		||||
# Setting this variable so that FFmpeg gets built without pipewiregrab
 | 
			
		||||
# (see daemon/contrib/bootstrap and daemon/contrib/src/ffmpeg/rules.mak)
 | 
			
		||||
# We rely on PipeWire for screen sharing on Wayland, but the version available on Ubuntu 20.04 is too old.
 | 
			
		||||
ENV DISABLE_PIPEWIRE=true
 | 
			
		||||
 | 
			
		||||
CMD ["/opt/build-package-debian.sh"]
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
FROM ubuntu:23.04
 | 
			
		||||
FROM ubuntu:24.04
 | 
			
		||||
 | 
			
		||||
ENV DEBIAN_FRONTEND=noninteractive
 | 
			
		||||
 | 
			
		||||
@ -10,6 +10,9 @@ RUN apt-get update && \
 | 
			
		||||
        python-is-python3 \
 | 
			
		||||
        wget
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/install-gcc-debian.sh /opt/install-gcc-debian.sh
 | 
			
		||||
RUN /opt/install-gcc-debian.sh 13
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/prebuild-package-debian.sh /opt/prebuild-package-debian.sh
 | 
			
		||||
 | 
			
		||||
COPY extras/packaging/gnu-linux/rules/debian-qt/control /tmp/builddeps/debian/control
 | 
			
		||||
							
								
								
									
										29
									
								
								extras/packaging/gnu-linux/docker/Dockerfile_ubuntu_24.10
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,29 @@
 | 
			
		||||
FROM ubuntu:24.10
 | 
			
		||||
 | 
			
		||||
ENV DEBIAN_FRONTEND=noninteractive
 | 
			
		||||
 | 
			
		||||
RUN apt-get clean
 | 
			
		||||
RUN apt-get update && \
 | 
			
		||||
    apt-get install -y -o Acquire::Retries=10 \
 | 
			
		||||
        devscripts \
 | 
			
		||||
        equivs \
 | 
			
		||||
        python-is-python3 \
 | 
			
		||||
        wget
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/prebuild-package-debian.sh /opt/prebuild-package-debian.sh
 | 
			
		||||
 | 
			
		||||
COPY extras/packaging/gnu-linux/rules/debian-qt/control /tmp/builddeps/debian/control
 | 
			
		||||
RUN /opt/prebuild-package-debian.sh qt-deps
 | 
			
		||||
 | 
			
		||||
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
 | 
			
		||||
RUN /opt/prebuild-package-debian.sh jami-deps
 | 
			
		||||
 | 
			
		||||
# Remove the libre2-dev package in order to force Qt to build using the bundled
 | 
			
		||||
# version of the RE2 library. This is necessary because the system version of the
 | 
			
		||||
# library on Ubuntu 24.10 (libre2-11) is not compatible with the one used in
 | 
			
		||||
# Qt 6.6.1 due to an API change:
 | 
			
		||||
# https://codereview.qt-project.org/c/qt/qtwebengine/+/516094
 | 
			
		||||
RUN apt-get remove -y libre2-dev libre2-11
 | 
			
		||||
 | 
			
		||||
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
 | 
			
		||||
CMD ["/opt/build-package-debian.sh"]
 | 
			
		||||
@ -92,6 +92,7 @@ Build-Depends: debhelper (>= 9),
 | 
			
		||||
               libgl1-mesa-dri,
 | 
			
		||||
# pkg-kde-tools (>= 0.15.17~),
 | 
			
		||||
               python3:any,
 | 
			
		||||
               python3-bs4,
 | 
			
		||||
               python3-html5lib,
 | 
			
		||||
# qtbase5-private-dev (>= 5.15.2+dfsg~),
 | 
			
		||||
               xauth <!nocheck>,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,348 @@
 | 
			
		||||
From 24fb774485f719df1e84dda31605d3f69202d69f Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Thu, 8 Aug 2024 14:59:17 -0400
 | 
			
		||||
Subject: [PATCH] qtwebengine: enable building with Python 3.12
 | 
			
		||||
 | 
			
		||||
Replace the deprecated imp module by importlib:
 | 
			
		||||
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/524014
 | 
			
		||||
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/534568
 | 
			
		||||
 | 
			
		||||
Update six to fix html5lib import failure:
 | 
			
		||||
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/535605
 | 
			
		||||
https://issues.chromium.org/issues/40286977
 | 
			
		||||
---
 | 
			
		||||
 .../protobufs/binary_proto_generator.py          |  8 ++++++--
 | 
			
		||||
 .../mojo/public/tools/mojom/mojom/fileutil.py    |  1 -
 | 
			
		||||
 .../tools/mojom/mojom/fileutil_unittest.py       |  5 +----
 | 
			
		||||
 .../mojom/mojom/generate/generator_unittest.py   |  7 ++-----
 | 
			
		||||
 .../mojom/mojom/generate/translate_unittest.py   |  4 ----
 | 
			
		||||
 .../tools/mojom/mojom/parse/ast_unittest.py      |  6 ------
 | 
			
		||||
 .../mojom/parse/conditional_features_unittest.py |  8 ++------
 | 
			
		||||
 .../mojo/public/tools/mojom/mojom/parse/lexer.py |  1 -
 | 
			
		||||
 .../tools/mojom/mojom/parse/lexer_unittest.py    |  7 ++-----
 | 
			
		||||
 .../tools/mojom/mojom/parse/parser_unittest.py   |  5 -----
 | 
			
		||||
 .../third_party/catapult/third_party/six/six.py  | 16 ++++++++++++++++
 | 
			
		||||
 11 files changed, 29 insertions(+), 39 deletions(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
 | 
			
		||||
index 2a1802dccdc..8b9de65ed0b 100755
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
 """
 | 
			
		||||
 from __future__ import print_function
 | 
			
		||||
 import abc
 | 
			
		||||
-import imp
 | 
			
		||||
+from importlib import util as imp_util
 | 
			
		||||
 import optparse
 | 
			
		||||
 import os
 | 
			
		||||
 import re
 | 
			
		||||
@@ -68,7 +68,11 @@ class GoogleProtobufModuleImporter:
 | 
			
		||||
       raise ImportError(fullname)
 | 
			
		||||
 
 | 
			
		||||
     filepath = self._fullname_to_filepath(fullname)
 | 
			
		||||
-    return imp.load_source(fullname, filepath)
 | 
			
		||||
+    spec = imp_util.spec_from_file_location(fullname, filepath)
 | 
			
		||||
+    loaded = imp_util.module_from_spec(spec)
 | 
			
		||||
+    spec.loader.exec_module(loaded)
 | 
			
		||||
+
 | 
			
		||||
+    return loaded
 | 
			
		||||
 
 | 
			
		||||
 class BinaryProtoGenerator:
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
 | 
			
		||||
index 29daec367c5..124f12c134b 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
 | 
			
		||||
@@ -3,7 +3,6 @@
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
 import errno
 | 
			
		||||
-import imp
 | 
			
		||||
 import os.path
 | 
			
		||||
 import sys
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
 | 
			
		||||
index 48eaf4eca94..c93d22898d2 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
 | 
			
		||||
@@ -2,19 +2,16 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
 import os.path
 | 
			
		||||
 import shutil
 | 
			
		||||
-import sys
 | 
			
		||||
 import tempfile
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
 from mojom import fileutil
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class FileUtilTest(unittest.TestCase):
 | 
			
		||||
   def testEnsureDirectoryExists(self):
 | 
			
		||||
-    """Test that EnsureDirectoryExists fuctions correctly."""
 | 
			
		||||
+    """Test that EnsureDirectoryExists functions correctly."""
 | 
			
		||||
 
 | 
			
		||||
     temp_dir = tempfile.mkdtemp()
 | 
			
		||||
     try:
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
 | 
			
		||||
index 76cda3981f3..7143e07c4d7 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
 | 
			
		||||
@@ -2,12 +2,11 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
+import importlib.util
 | 
			
		||||
 import os.path
 | 
			
		||||
 import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 def _GetDirAbove(dirname):
 | 
			
		||||
   """Returns the directory "above" this file containing |dirname| (which must
 | 
			
		||||
   also be "above" this file)."""
 | 
			
		||||
@@ -20,12 +19,11 @@ def _GetDirAbove(dirname):
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
 try:
 | 
			
		||||
-  imp.find_module("mojom")
 | 
			
		||||
+  importlib.util.find_spec("mojom")
 | 
			
		||||
 except ImportError:
 | 
			
		||||
   sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
 | 
			
		||||
 from mojom.generate import generator
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class StringManipulationTest(unittest.TestCase):
 | 
			
		||||
   """generator contains some string utilities, this tests only those."""
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +67,5 @@ class StringManipulationTest(unittest.TestCase):
 | 
			
		||||
     self.assertEquals("SNAKE_D3D11_CASE",
 | 
			
		||||
                       generator.ToUpperSnakeCase("snakeD3d11Case"))
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 if __name__ == "__main__":
 | 
			
		||||
   unittest.main()
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
 | 
			
		||||
index 4259374513f..558e71e1193 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
 | 
			
		||||
@@ -2,16 +2,12 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
-import os.path
 | 
			
		||||
-import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
 from mojom.generate import module as mojom
 | 
			
		||||
 from mojom.generate import translate
 | 
			
		||||
 from mojom.parse import ast
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class TranslateTest(unittest.TestCase):
 | 
			
		||||
   """Tests |parser.Parse()|."""
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
 | 
			
		||||
index c36376712e7..b289f7b11f6 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
 | 
			
		||||
@@ -2,14 +2,10 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
-import os.path
 | 
			
		||||
-import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
 from mojom.parse import ast
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class _TestNode(ast.NodeBase):
 | 
			
		||||
   """Node type for tests."""
 | 
			
		||||
 
 | 
			
		||||
@@ -20,13 +16,11 @@ class _TestNode(ast.NodeBase):
 | 
			
		||||
   def __eq__(self, other):
 | 
			
		||||
     return super().__eq__(other) and self.value == other.value
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class _TestNodeList(ast.NodeListBase):
 | 
			
		||||
   """Node list type for tests."""
 | 
			
		||||
 
 | 
			
		||||
   _list_item_type = _TestNode
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class ASTTest(unittest.TestCase):
 | 
			
		||||
   """Tests various AST classes."""
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
 | 
			
		||||
index 5fc582025ee..2fa5d2be6ab 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
 | 
			
		||||
@@ -2,12 +2,11 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
+import importlib.util
 | 
			
		||||
 import os
 | 
			
		||||
 import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 def _GetDirAbove(dirname):
 | 
			
		||||
   """Returns the directory "above" this file containing |dirname| (which must
 | 
			
		||||
   also be "above" this file)."""
 | 
			
		||||
@@ -18,9 +17,8 @@ def _GetDirAbove(dirname):
 | 
			
		||||
     if tail == dirname:
 | 
			
		||||
       return path
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 try:
 | 
			
		||||
-  imp.find_module('mojom')
 | 
			
		||||
+  importlib.util.find_spec("mojom")
 | 
			
		||||
 except ImportError:
 | 
			
		||||
   sys.path.append(os.path.join(_GetDirAbove('pylib'), 'pylib'))
 | 
			
		||||
 import mojom.parse.ast as ast
 | 
			
		||||
@@ -29,7 +27,6 @@ import mojom.parse.parser as parser
 | 
			
		||||
 
 | 
			
		||||
 ENABLED_FEATURES = frozenset({'red', 'green', 'blue'})
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class ConditionalFeaturesTest(unittest.TestCase):
 | 
			
		||||
   """Tests |mojom.parse.conditional_features|."""
 | 
			
		||||
 
 | 
			
		||||
@@ -356,6 +353,5 @@ class ConditionalFeaturesTest(unittest.TestCase):
 | 
			
		||||
                       conditional_features.RemoveDisabledDefinitions,
 | 
			
		||||
                       definition, ENABLED_FEATURES)
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 if __name__ == '__main__':
 | 
			
		||||
   unittest.main()
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
 | 
			
		||||
index 73ca15df94c..1083a1af7bb 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
 | 
			
		||||
@@ -2,7 +2,6 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
 import os.path
 | 
			
		||||
 import sys
 | 
			
		||||
 
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
 | 
			
		||||
index ce376da66e0..bc9f8354316 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
 | 
			
		||||
@@ -2,12 +2,11 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
+import importlib.util
 | 
			
		||||
 import os.path
 | 
			
		||||
 import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 def _GetDirAbove(dirname):
 | 
			
		||||
   """Returns the directory "above" this file containing |dirname| (which must
 | 
			
		||||
   also be "above" this file)."""
 | 
			
		||||
@@ -18,17 +17,15 @@ def _GetDirAbove(dirname):
 | 
			
		||||
     if tail == dirname:
 | 
			
		||||
       return path
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 sys.path.insert(1, os.path.join(_GetDirAbove("mojo"), "third_party"))
 | 
			
		||||
 from ply import lex
 | 
			
		||||
 
 | 
			
		||||
 try:
 | 
			
		||||
-  imp.find_module("mojom")
 | 
			
		||||
+  importlib.util.find_spec("mojom")
 | 
			
		||||
 except ImportError:
 | 
			
		||||
   sys.path.append(os.path.join(_GetDirAbove("pylib"), "pylib"))
 | 
			
		||||
 import mojom.parse.lexer
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 # This (monkey-patching LexToken to make comparison value-based) is evil, but
 | 
			
		||||
 # we'll do it anyway. (I'm pretty sure ply's lexer never cares about comparing
 | 
			
		||||
 # for object identity.)
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
 | 
			
		||||
index 0513343ec7e..0a26307b1a3 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
 | 
			
		||||
@@ -2,16 +2,12 @@
 | 
			
		||||
 # Use of this source code is governed by a BSD-style license that can be
 | 
			
		||||
 # found in the LICENSE file.
 | 
			
		||||
 
 | 
			
		||||
-import imp
 | 
			
		||||
-import os.path
 | 
			
		||||
-import sys
 | 
			
		||||
 import unittest
 | 
			
		||||
 
 | 
			
		||||
 from mojom.parse import ast
 | 
			
		||||
 from mojom.parse import lexer
 | 
			
		||||
 from mojom.parse import parser
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 class ParserTest(unittest.TestCase):
 | 
			
		||||
   """Tests |parser.Parse()|."""
 | 
			
		||||
 
 | 
			
		||||
@@ -1375,6 +1371,5 @@ class ParserTest(unittest.TestCase):
 | 
			
		||||
         r" *associated\? MyInterface& a;$"):
 | 
			
		||||
       parser.Parse(source3, "my_file.mojom")
 | 
			
		||||
 
 | 
			
		||||
-
 | 
			
		||||
 if __name__ == "__main__":
 | 
			
		||||
   unittest.main()
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py b/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
 | 
			
		||||
index 83f69783d1a..5e7f0ce4437 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
 | 
			
		||||
@@ -71,6 +71,11 @@ else:
 | 
			
		||||
             MAXSIZE = int((1 << 63) - 1)
 | 
			
		||||
         del X
 | 
			
		||||
 
 | 
			
		||||
+if PY34:
 | 
			
		||||
+    from importlib.util import spec_from_loader
 | 
			
		||||
+else:
 | 
			
		||||
+    spec_from_loader = None
 | 
			
		||||
+
 | 
			
		||||
 
 | 
			
		||||
 def _add_doc(func, doc):
 | 
			
		||||
     """Add documentation to a function."""
 | 
			
		||||
@@ -186,6 +191,11 @@ class _SixMetaPathImporter(object):
 | 
			
		||||
             return self
 | 
			
		||||
         return None
 | 
			
		||||
 
 | 
			
		||||
+    def find_spec(self, fullname, path, target=None):
 | 
			
		||||
+        if fullname in self.known_modules:
 | 
			
		||||
+            return spec_from_loader(fullname, self)
 | 
			
		||||
+        return None
 | 
			
		||||
+
 | 
			
		||||
     def __get_module(self, fullname):
 | 
			
		||||
         try:
 | 
			
		||||
             return self.known_modules[fullname]
 | 
			
		||||
@@ -223,6 +233,12 @@ class _SixMetaPathImporter(object):
 | 
			
		||||
         return None
 | 
			
		||||
     get_source = get_code  # same as get_code
 | 
			
		||||
 
 | 
			
		||||
+    def create_module(self, spec):
 | 
			
		||||
+        return self.load_module(spec.name)
 | 
			
		||||
+
 | 
			
		||||
+    def exec_module(self, module):
 | 
			
		||||
+        pass
 | 
			
		||||
+
 | 
			
		||||
 _importer = _SixMetaPathImporter(__name__)
 | 
			
		||||
 
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.34.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,16 @@
 | 
			
		||||
 qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
 | 
			
		||||
index 3488120543..120e47a76f 100644
 | 
			
		||||
--- a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
 | 
			
		||||
+++ b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
 | 
			
		||||
@@ -472,7 +472,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
 | 
			
		||||
     }
 | 
			
		||||
     catch (const DeadlyImportError& e)
 | 
			
		||||
     {
 | 
			
		||||
-        if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
 | 
			
		||||
+        if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
 | 
			
		||||
             throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
 | 
			
		||||
         }
 | 
			
		||||
         throw;
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
From cf208d11dc8a9a02160a57283596ec8bab964a09 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Sebastien Blin <sebastien.blin@savoirfairelinux.com>
 | 
			
		||||
Date: Mon, 27 May 2024 16:01:21 -0400
 | 
			
		||||
Subject: [PATCH] qtwayland: downgrade wl-seat to avoid high-resolution
 | 
			
		||||
 scrolling events
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 qtwayland/src/client/qwaylandinputdevice.cpp | 2 +-
 | 
			
		||||
 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwayland/src/client/qwaylandinputdevice.cpp b/qtwayland/src/client/qwaylandinputdevice.cpp
 | 
			
		||||
index a4f8757e3c..ad0aa7941c 100644
 | 
			
		||||
--- a/qtwayland/src/client/qwaylandinputdevice.cpp
 | 
			
		||||
+++ b/qtwayland/src/client/qwaylandinputdevice.cpp
 | 
			
		||||
@@ -383,7 +383,7 @@ QWaylandInputDevice::Touch::~Touch()
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
 QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id)
 | 
			
		||||
-    : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 9))
 | 
			
		||||
+    : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 7))
 | 
			
		||||
     , mQDisplay(display)
 | 
			
		||||
     , mDisplay(display->wl_display())
 | 
			
		||||
 {
 | 
			
		||||
-- 
 | 
			
		||||
2.45.0
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
From 420b3e5ac2e91b7a99488ac34577e2798a84a68c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Tue, 6 Aug 2024 17:35:56 -0400
 | 
			
		||||
Subject: [PATCH] qtbase: fix CMake error
 | 
			
		||||
 | 
			
		||||
For more information, see:
 | 
			
		||||
https://github.com/qt/qtbase/commit/3411f2984a5325a35e3bed1f961e5973d8a565b9
 | 
			
		||||
---
 | 
			
		||||
 qtbase/configure.cmake            | 1 +
 | 
			
		||||
 qtbase/src/corelib/CMakeLists.txt | 1 -
 | 
			
		||||
 2 files changed, 1 insertion(+), 1 deletion(-)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtbase/configure.cmake b/qtbase/configure.cmake
 | 
			
		||||
index 43de2aa026..37a82dcdb6 100644
 | 
			
		||||
--- a/qtbase/configure.cmake
 | 
			
		||||
+++ b/qtbase/configure.cmake
 | 
			
		||||
@@ -18,6 +18,7 @@ if(TARGET ZLIB::ZLIB)
 | 
			
		||||
     set_property(TARGET ZLIB::ZLIB PROPERTY IMPORTED_GLOBAL TRUE)
 | 
			
		||||
 endif()
 | 
			
		||||
 
 | 
			
		||||
+qt_find_package(Threads PROVIDED_TARGETS Threads::Threads)
 | 
			
		||||
 qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders MODULE_NAME core)
 | 
			
		||||
 # openssl_headers
 | 
			
		||||
 # OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1
 | 
			
		||||
diff --git a/qtbase/src/corelib/CMakeLists.txt b/qtbase/src/corelib/CMakeLists.txt
 | 
			
		||||
index 31b81734e8..b62e2f763b 100644
 | 
			
		||||
--- a/qtbase/src/corelib/CMakeLists.txt
 | 
			
		||||
+++ b/qtbase/src/corelib/CMakeLists.txt
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
 # Copyright (C) 2022 The Qt Company Ltd.
 | 
			
		||||
 # SPDX-License-Identifier: BSD-3-Clause
 | 
			
		||||
 
 | 
			
		||||
-qt_find_package(Threads PROVIDED_TARGETS Threads::Threads)
 | 
			
		||||
 qt_find_package(WrapPCRE2 PROVIDED_TARGETS WrapPCRE2::WrapPCRE2)
 | 
			
		||||
 qt_find_package(WrapZLIB PROVIDED_TARGETS WrapZLIB::WrapZLIB)
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.34.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
From 4c7360faeb0fb7f1dfd995619fb8c596b4e15606 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Thu, 8 Aug 2024 10:29:43 -0400
 | 
			
		||||
Subject: [PATCH] qtwebengine: add missing chromium dependencies
 | 
			
		||||
 | 
			
		||||
For more information, see:
 | 
			
		||||
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/555586
 | 
			
		||||
---
 | 
			
		||||
 chromium/content/public/browser/BUILD.gn                         | 1 +
 | 
			
		||||
 chromium/extensions/browser/api/declarative_net_request/BUILD.gn | 1 +
 | 
			
		||||
 2 files changed, 2 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
index b25bf5764e7..dfbfb2ec77b 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
@@ -515,6 +515,7 @@ jumbo_source_set("browser_sources") {
 | 
			
		||||
     "//cc",
 | 
			
		||||
     "//components/services/storage/public/cpp",
 | 
			
		||||
     "//components/viz/host",
 | 
			
		||||
+    "//components/spellcheck:buildflags",
 | 
			
		||||
     "//content/browser",  # Must not be public_deps!
 | 
			
		||||
     "//device/fido",
 | 
			
		||||
     "//gpu",
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
index 1fc492f5a0c..13a266e22f1 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
@@ -23,6 +23,7 @@ source_set("declarative_net_request") {
 | 
			
		||||
     "//extensions/common",
 | 
			
		||||
     "//extensions/common/api",
 | 
			
		||||
     "//services/preferences/public/cpp",
 | 
			
		||||
+    "//components/web_cache/browser",
 | 
			
		||||
   ]
 | 
			
		||||
 
 | 
			
		||||
   public_deps = [ "//extensions/browser:browser_sources" ]
 | 
			
		||||
-- 
 | 
			
		||||
2.34.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,49 @@
 | 
			
		||||
From ab6d5bebaf68a9f4d00440b2adbaffe0e5b2ae6c Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Thu, 8 Aug 2024 10:55:08 -0400
 | 
			
		||||
Subject: [PATCH] qtwebengine: fix libxml2 build error
 | 
			
		||||
 | 
			
		||||
Version 2.12 of libxml2 introduced a change that broke chromium's build,
 | 
			
		||||
see: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/523633
 | 
			
		||||
---
 | 
			
		||||
 .../third_party/blink/renderer/core/xml/xslt_processor.h     | 5 +++++
 | 
			
		||||
 .../blink/renderer/core/xml/xslt_processor_libxslt.cc        | 4 ++++
 | 
			
		||||
 2 files changed, 9 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
 | 
			
		||||
index d53835e9675..72536e4fd7d 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
 | 
			
		||||
@@ -77,7 +77,12 @@ class XSLTProcessor final : public ScriptWrappable {
 | 
			
		||||
 
 | 
			
		||||
   void reset();
 | 
			
		||||
 
 | 
			
		||||
+#if LIBXML_VERSION >= 21200
 | 
			
		||||
+  static void ParseErrorFunc(void* user_data, const xmlError*);
 | 
			
		||||
+#else
 | 
			
		||||
   static void ParseErrorFunc(void* user_data, xmlError*);
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
   static void GenericErrorFunc(void* user_data, const char* msg, ...);
 | 
			
		||||
 
 | 
			
		||||
   // Only for libXSLT callbacks
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
 | 
			
		||||
index 133e0b3355d..e8e6a09f485 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
 | 
			
		||||
@@ -66,7 +66,11 @@ void XSLTProcessor::GenericErrorFunc(void*, const char*, ...) {
 | 
			
		||||
   // It would be nice to do something with this error message.
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
+#if LIBXML_VERSION >= 21200
 | 
			
		||||
+void XSLTProcessor::ParseErrorFunc(void* user_data, const xmlError* error) {
 | 
			
		||||
+#else
 | 
			
		||||
 void XSLTProcessor::ParseErrorFunc(void* user_data, xmlError* error) {
 | 
			
		||||
+#endif
 | 
			
		||||
   FrameConsole* console = static_cast<FrameConsole*>(user_data);
 | 
			
		||||
   if (!console)
 | 
			
		||||
     return;
 | 
			
		||||
-- 
 | 
			
		||||
2.34.1
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
From 6e0848a1c51c6494e3b7410c5fe38941d48fcb36 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Wed, 16 Oct 2024 22:32:12 -0400
 | 
			
		||||
Subject: [PATCH] qtwebengine: fix v8 build error
 | 
			
		||||
 | 
			
		||||
In file included from ../../../3rdparty/chromium/v8/src/heap/cppgc/sweeper.h:14,
 | 
			
		||||
                 from ./../../../3rdparty/chromium/v8/src/heap/cppgc/sweeper.cc:5,
 | 
			
		||||
                 from gen/v8/cppgc_base_jumbo_7.cc:5:
 | 
			
		||||
../../../3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h: In member function 'void cppgc::internal::StatsCollector::ForAllAllocationObservers(Callback)':
 | 
			
		||||
../../../3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h:401:48: error: cannot convert 'std::vector<cppgc::internal::StatsCollector::AllocationObserver*>::iterator' to 'const char*'
 | 
			
		||||
  401 |         std::remove(allocation_observers_.begin(), allocation_observers_.end(),
 | 
			
		||||
      |                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
 | 
			
		||||
      |                                                |
 | 
			
		||||
      |                                                std::vector<cppgc::internal::StatsCollector::AllocationObserver*>::iterator
 | 
			
		||||
---
 | 
			
		||||
 .../src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h    | 1 +
 | 
			
		||||
 1 file changed, 1 insertion(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
index 2cf728489d..d8414ae3c6 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 #include <stddef.h>
 | 
			
		||||
 #include <stdint.h>
 | 
			
		||||
 
 | 
			
		||||
+#include <algorithm>
 | 
			
		||||
 #include <atomic>
 | 
			
		||||
 #include <vector>
 | 
			
		||||
 
 | 
			
		||||
-- 
 | 
			
		||||
2.47.0
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
0001-qtwebengine-enable-building-with-Python-3.12.patch
 | 
			
		||||
0002-fix-binary-tokenizer.patch
 | 
			
		||||
0003-qtwayland-downgrade-wl-seat-to-avoid-high-resolution.patch
 | 
			
		||||
0004-qtbase-fix-CMake-error.patch
 | 
			
		||||
0005-qtwebengine-add-missing-chromium-dependencies.patch
 | 
			
		||||
0006-qtwebengine-fix-libxml2-build-error.patch
 | 
			
		||||
0007-qtwebengine-fix-v8-build-error.patch
 | 
			
		||||
@ -22,7 +22,7 @@ Build-Depends: debhelper (>= 9),
 | 
			
		||||
               libpulse-dev,
 | 
			
		||||
               libasound2-dev,
 | 
			
		||||
               libexpat1-dev,
 | 
			
		||||
               libpcre3-dev,
 | 
			
		||||
               libpcre3-dev | libpcre2-dev,
 | 
			
		||||
               libyaml-cpp-dev,
 | 
			
		||||
               libboost-dev,
 | 
			
		||||
               libxext-dev,
 | 
			
		||||
@ -45,6 +45,8 @@ Build-Depends: debhelper (>= 9),
 | 
			
		||||
               libvdpau-dev,
 | 
			
		||||
               libssl-dev,
 | 
			
		||||
               libargon2-dev | libargon2-0-dev,
 | 
			
		||||
# TODO: remove libpipewire-0.2-dev once we stop supporting Ubuntu 20.04
 | 
			
		||||
               libpipewire-0.3-dev | libpipewire-0.2-dev,
 | 
			
		||||
# other
 | 
			
		||||
               nasm,
 | 
			
		||||
               yasm,
 | 
			
		||||
 | 
			
		||||
@ -99,10 +99,12 @@ if [ -f /etc/os-release ]; then
 | 
			
		||||
        ENDTAG="ubuntu_20.04"
 | 
			
		||||
    elif [ "${UBUNTU_CODENAME}" = "jammy" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_22.04" ]; then
 | 
			
		||||
        ENDTAG="ubuntu_22.04"
 | 
			
		||||
    elif [ "${UBUNTU_CODENAME}" = "lunar" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_23.04" ]; then
 | 
			
		||||
        ENDTAG="ubuntu_23.04"
 | 
			
		||||
    elif [ "${UBUNTU_CODENAME}" = "mantic" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_23.10" ]; then
 | 
			
		||||
        ENDTAG="ubuntu_23.10"
 | 
			
		||||
    elif [ "${UBUNTU_CODENAME}" = "noble" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_24.04" ]; then
 | 
			
		||||
        ENDTAG="ubuntu_24.04"
 | 
			
		||||
    elif [ "${UBUNTU_CODENAME}" = "oracular" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_24.10" ]; then
 | 
			
		||||
        ENDTAG="ubuntu_24.10"
 | 
			
		||||
    elif [ "${ID}" = "debian" ] && \
 | 
			
		||||
             [ "$(command -v lsb_release)" ] && \
 | 
			
		||||
             [ "$(lsb_release -rs)" = "testing" ]; then
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,7 @@ BuildRequires: libuuid-devel
 | 
			
		||||
BuildRequires: libva-devel
 | 
			
		||||
BuildRequires: libvdpau-devel
 | 
			
		||||
BuildRequires: pcre-devel
 | 
			
		||||
BuildRequires: pipewire-devel
 | 
			
		||||
BuildRequires: uuid-devel
 | 
			
		||||
BuildRequires: yaml-cpp-devel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,9 @@
 | 
			
		||||
%define computed_job_count_ %(echo $(( %available_memory / %memory_required_per_core / %max_parallel_builds )))
 | 
			
		||||
%define computed_job_count %max %computed_job_count_ 1
 | 
			
		||||
%define job_count %min %cpu_count %computed_job_count
 | 
			
		||||
# Exclude vendored Qt6 from dependency generator
 | 
			
		||||
%define __provides_exclude_from ^%{_libdir}/qt-jami/.*$
 | 
			
		||||
%define __requires_exclude ^libQt6.*$
 | 
			
		||||
 | 
			
		||||
Name:          %{name}
 | 
			
		||||
Version:       %{version}
 | 
			
		||||
@ -26,6 +29,8 @@ License:       GPLv3+
 | 
			
		||||
Vendor:        Savoir-faire Linux Inc.
 | 
			
		||||
URL:           https://jami.net/
 | 
			
		||||
Source:        jami-libqt-%{version}.tar.xz
 | 
			
		||||
Patch0:        0001-fix-gcc14.patch
 | 
			
		||||
Patch1:        0002-qtwebengine-add-missing-chromium-dependencies.patch
 | 
			
		||||
 | 
			
		||||
%global gst 0.10
 | 
			
		||||
%if 0%{?fedora} || 0%{?rhel} > 7
 | 
			
		||||
@ -61,6 +66,8 @@ This package contains Qt libraries for Jami.
 | 
			
		||||
 | 
			
		||||
%prep
 | 
			
		||||
%setup -n qt-everywhere-src-%{version}
 | 
			
		||||
%patch -P 0 -p1
 | 
			
		||||
%patch -P 1 -p1
 | 
			
		||||
 | 
			
		||||
%build
 | 
			
		||||
echo "Building Qt using %{job_count} parallel jobs"
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,9 @@
 | 
			
		||||
%define version     RELEASE_VERSION
 | 
			
		||||
%define release     0
 | 
			
		||||
 | 
			
		||||
# Exclude vendored Qt6 from dependency generator
 | 
			
		||||
%define __requires_exclude ^libQt6.*$
 | 
			
		||||
 | 
			
		||||
Name:          %{name}
 | 
			
		||||
Version:       %{version}
 | 
			
		||||
Release:       %{release}%{?dist}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
From 9721082687c9529fe6ae3c5304dcf079158e8a77 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Sam James <sam@gentoo.org>
 | 
			
		||||
Date: Sun, 04 Jun 2023 04:15:16 +0100
 | 
			
		||||
Subject: [PATCH] heap: Add missing <algorithm> include for std::remove
 | 
			
		||||
 | 
			
		||||
GCC 14 changes some internal includes within libstdc++ so this transient
 | 
			
		||||
include gets lost. Include <algorithm> explicitly for std::remove.
 | 
			
		||||
 | 
			
		||||
Change-Id: Iab8a2c751a0f9c9dc6a770d6296ad6de724ef3bb
 | 
			
		||||
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4583222
 | 
			
		||||
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
 | 
			
		||||
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
 | 
			
		||||
Cr-Commit-Position: refs/heads/main@{#88037}
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
index 2cf728489d..d8414ae3c6 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
 | 
			
		||||
@@ -8,6 +8,7 @@
 | 
			
		||||
 #include <stddef.h>
 | 
			
		||||
 #include <stdint.h>
 | 
			
		||||
 | 
			
		||||
+#include <algorithm>
 | 
			
		||||
 #include <atomic>
 | 
			
		||||
 #include <vector>
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
From 04778c7f54c8a1a0e7fced75c5ef39ced82cece1 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
 | 
			
		||||
 <francois-simon.fauteux-chapleau@savoirfairelinux.com>
 | 
			
		||||
Date: Sat, 12 Oct 2024 16:21:35 -0400
 | 
			
		||||
Subject: [PATCH] qtwebengine: add missing chromium dependencies
 | 
			
		||||
 | 
			
		||||
For more information, see:
 | 
			
		||||
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/555586
 | 
			
		||||
---
 | 
			
		||||
 chromium/content/public/browser/BUILD.gn                         | 1 +
 | 
			
		||||
 chromium/extensions/browser/api/declarative_net_request/BUILD.gn | 1 +
 | 
			
		||||
 2 files changed, 2 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
index b25bf5764e7..dfbfb2ec77b 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
 | 
			
		||||
@@ -515,6 +515,7 @@ jumbo_source_set("browser_sources") {
 | 
			
		||||
     "//cc",
 | 
			
		||||
     "//components/services/storage/public/cpp",
 | 
			
		||||
     "//components/viz/host",
 | 
			
		||||
+    "//components/spellcheck:buildflags",
 | 
			
		||||
     "//content/browser",  # Must not be public_deps!
 | 
			
		||||
     "//device/fido",
 | 
			
		||||
     "//gpu",
 | 
			
		||||
diff --git a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
index 1fc492f5a0c..13a266e22f1 100644
 | 
			
		||||
--- a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
+++ b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
 | 
			
		||||
@@ -23,6 +23,7 @@ source_set("declarative_net_request") {
 | 
			
		||||
     "//extensions/common",
 | 
			
		||||
     "//extensions/common/api",
 | 
			
		||||
     "//services/preferences/public/cpp",
 | 
			
		||||
+    "//components/web_cache/browser",
 | 
			
		||||
   ]
 | 
			
		||||
 
 | 
			
		||||
   public_deps = [ "//extensions/browser:browser_sources" ]
 | 
			
		||||
-- 
 | 
			
		||||
2.47.0
 | 
			
		||||
 | 
			
		||||
@ -138,6 +138,10 @@ apps:
 | 
			
		||||
    autostart: jami.desktop
 | 
			
		||||
    common-id: net.jami.Jami
 | 
			
		||||
    desktop: usr/share/applications/jami.desktop
 | 
			
		||||
    environment:
 | 
			
		||||
      PIPEWIRE_CONFIG_NAME: "$SNAP/usr/share/pipewire/pipewire.conf"
 | 
			
		||||
      PIPEWIRE_MODULE_DIR: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/pipewire-0.3"
 | 
			
		||||
      SPA_PLUGIN_DIR: "$SNAP/usr/lib/$SNAPCRAFT_ARCH_TRIPLET/spa-0.2"
 | 
			
		||||
    slots:
 | 
			
		||||
    - dbus-jami
 | 
			
		||||
    - dbus-ring
 | 
			
		||||
@ -168,7 +172,7 @@ package-repositories:
 | 
			
		||||
    components: [main]
 | 
			
		||||
    suites: [jami]
 | 
			
		||||
    key-id: A295D773307D25A33AE72F2F64CD5FA175348F84
 | 
			
		||||
    url: https://dl.jami.net/nightly/ubuntu_20.04/
 | 
			
		||||
    url: https://dl.jami.net/internal/ubuntu_20.04/
 | 
			
		||||
 | 
			
		||||
parts:
 | 
			
		||||
  desktop-launch:
 | 
			
		||||
@ -255,6 +259,8 @@ parts:
 | 
			
		||||
      sed -i -E 's|(tmpName) << (PACKAGE_NAME << "_shm_")|\1 << "snap.jami." << \2|' ./daemon/src/media/video/sinkclient.cpp
 | 
			
		||||
      sed -i -E 's|^Icon=.*|Icon=${SNAP}/usr/share/icons/hicolor/scalable/apps/jami.svg|' extras/data/jami.desktop
 | 
			
		||||
    override-build: |
 | 
			
		||||
      $SNAPCRAFT_PART_BUILD/extras/packaging/gnu-linux/scripts/install-pipewire-from-source.sh
 | 
			
		||||
 | 
			
		||||
      cd $SNAPCRAFT_PART_BUILD/daemon/contrib
 | 
			
		||||
      mkdir -p native
 | 
			
		||||
      cd native
 | 
			
		||||
 | 
			
		||||
@ -44,6 +44,23 @@ QUILT_REFRESH_ARGS="-p 1"
 | 
			
		||||
 | 
			
		||||
if [ ! -f "${qt_deb_path}" ] || [ "${FORCE_REBUILD_QT}" = "true" ]; then
 | 
			
		||||
    (
 | 
			
		||||
 | 
			
		||||
        # HACK: For now on ubuntu 24.04 there is no python3.10 package
 | 
			
		||||
        # So create a PyEnv environment to install the required packages
 | 
			
		||||
        if cat /etc/os-release | grep -Eq "24.04"; then
 | 
			
		||||
            apt-get install git gcc make python3-pip libssl-dev curl libreadline-dev -y
 | 
			
		||||
            curl https://pyenv.run | bash
 | 
			
		||||
            export PYENV_ROOT="$HOME/.pyenv"
 | 
			
		||||
            [[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
 | 
			
		||||
            eval "$(pyenv init -)"
 | 
			
		||||
            pyenv install 3.10.0
 | 
			
		||||
            pyenv local 3.10.0
 | 
			
		||||
 | 
			
		||||
            python -m pip install html5lib
 | 
			
		||||
            python -m pip install six
 | 
			
		||||
        fi
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        flock 9                 # block until the lock file is gone
 | 
			
		||||
        test -f "${qt_deb_path}" && exit 0 # check again
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ rpmdev-setuptree
 | 
			
		||||
 | 
			
		||||
# Copy the source tarball.
 | 
			
		||||
cp --reflink=auto "/src/$RELEASE_TARBALL_FILENAME" /root/rpmbuild/SOURCES
 | 
			
		||||
cp patches/*.patch /root/rpmbuild/SOURCES/
 | 
			
		||||
 | 
			
		||||
QT_JAMI_PREFIX="/usr/lib64/qt-jami"
 | 
			
		||||
PATH="${QT_JAMI_PREFIX}/bin:${PATH}"
 | 
			
		||||
@ -43,7 +44,7 @@ PKG_CONFIG_PATH="${QT_JAMI_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}"
 | 
			
		||||
CMAKE_PREFIX_PATH="${QT_JAMI_PREFIX}/lib/cmake:${CMAKE_PREFIX_PATH}"
 | 
			
		||||
QT_MAJOR=6
 | 
			
		||||
QT_MINOR=6
 | 
			
		||||
QT_PATCH=1
 | 
			
		||||
QT_PATCH=3
 | 
			
		||||
QT_RELEASE_PATCH=0
 | 
			
		||||
 | 
			
		||||
QT_MAJOR_MINOR=${QT_MAJOR}.${QT_MINOR}
 | 
			
		||||
@ -52,7 +53,7 @@ QT_MAJOR_MINOR_PATCH=${QT_MAJOR}.${QT_MINOR}.${QT_PATCH}
 | 
			
		||||
QT_TARBALL_URL=https://download.qt.io/archive/qt/$QT_MAJOR_MINOR/\
 | 
			
		||||
$QT_MAJOR_MINOR_PATCH/single/qt-everywhere-src-$QT_MAJOR_MINOR_PATCH.tar.xz
 | 
			
		||||
 | 
			
		||||
QT_TARBALL_SHA256="dd3668f65645fe270bc615d748bd4dc048bd17b9dc297025106e6ecc419ab95d"
 | 
			
		||||
QT_TARBALL_SHA256="69d0348fef415da98aa890a34651e9cfb232f1bffcee289b7b4e21386bf36104"
 | 
			
		||||
QT_TARBALL_FILE_NAME=$(basename "$QT_TARBALL_URL")
 | 
			
		||||
CACHED_QT_TARBALL=$TARBALLS/$QT_TARBALL_FILE_NAME
 | 
			
		||||
 | 
			
		||||
@ -111,6 +112,10 @@ if [ ! -f "${RPM_PATH}" ]; then
 | 
			
		||||
            cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc38.x86_64.rpm "${RPM_PATH}"
 | 
			
		||||
        elif [[ "${DISTRIBUTION}" == "fedora_39" ]]; then
 | 
			
		||||
            cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc39.x86_64.rpm "${RPM_PATH}"
 | 
			
		||||
        elif [[ "${DISTRIBUTION}" == "fedora_40" ]]; then
 | 
			
		||||
            cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc40.x86_64.rpm "${RPM_PATH}"
 | 
			
		||||
        elif [[ "${DISTRIBUTION}" == "fedora_41" ]]; then
 | 
			
		||||
            cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc41.x86_64.rpm "${RPM_PATH}"
 | 
			
		||||
        elif [[ "${DISTRIBUTION}" == "alma_9" ]]; then
 | 
			
		||||
            cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el9.x86_64.rpm "${RPM_PATH}"
 | 
			
		||||
        else
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								extras/packaging/gnu-linux/scripts/install-pipewire-from-source.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						@ -0,0 +1,38 @@
 | 
			
		||||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
# The purpose of this script is to build PipeWire from source in a snap based on core20 / Ubuntu 20.04
 | 
			
		||||
# It must be called in the "override-build" section of the relevant part in snapcraft.yaml
 | 
			
		||||
 | 
			
		||||
set -e
 | 
			
		||||
 | 
			
		||||
OLD_WD=$(pwd)
 | 
			
		||||
cd /tmp
 | 
			
		||||
 | 
			
		||||
# Install PipeWire's build dependencies
 | 
			
		||||
apt-get install --yes gcc git libasound2-dev libdbus-1-dev libglib2.0-dev ninja-build pkg-config
 | 
			
		||||
 | 
			
		||||
# Get a version of Meson that's recent enough to build PipeWire 1.0.5 (the one available via apt is too old)
 | 
			
		||||
wget -q https://github.com/mesonbuild/meson/releases/download/0.61.1/meson-0.61.1.tar.gz
 | 
			
		||||
echo "feb2cefb325b437dbf36146df7c6b87688ddff0b0205caa31dc64055c6da410c  meson-0.61.1.tar.gz" | sha256sum --check
 | 
			
		||||
tar xzf meson-0.61.1.tar.gz
 | 
			
		||||
 | 
			
		||||
# Build PipeWire 1.0.5 and install it in the /usr directory of the build environment
 | 
			
		||||
wget -q https://gitlab.freedesktop.org/pipewire/pipewire/-/archive/1.0.5/pipewire-1.0.5.tar.gz
 | 
			
		||||
echo "c5a5de26d684a1a84060ad7b6131654fb2835e03fccad85059be92f8e3ffe993  pipewire-1.0.5.tar.gz" | sha256sum --check
 | 
			
		||||
tar xzf pipewire-1.0.5.tar.gz
 | 
			
		||||
cd pipewire-1.0.5
 | 
			
		||||
../meson-0.61.1/meson.py setup builddir -Dsession-managers=media-session -Dalsa=disabled -Dprefix=/usr
 | 
			
		||||
../meson-0.61.1/meson.py compile -C builddir
 | 
			
		||||
../meson-0.61.1/meson.py install -C builddir
 | 
			
		||||
 | 
			
		||||
# The files installed by the previous command are only for the "Build" step of the snap
 | 
			
		||||
# creation process (https://snapcraft.io/docs/how-snapcraft-builds). In order to ensure
 | 
			
		||||
# that PipeWire is installed in the final snap archive, we also need to copy all the
 | 
			
		||||
# required files under the $SNAPCRAFT_PART_INSTALL directory.
 | 
			
		||||
../meson-0.61.1/meson.py configure builddir -Dprefix=$SNAPCRAFT_PART_INSTALL/usr/
 | 
			
		||||
../meson-0.61.1/meson.py install -C builddir
 | 
			
		||||
 | 
			
		||||
# Cleanup
 | 
			
		||||
cd /tmp
 | 
			
		||||
rm -rf meson-0.61.1  meson-0.61.1.tar.gz  pipewire-1.0.5  pipewire-1.0.5.tar.gz
 | 
			
		||||
cd $OLD_WD
 | 
			
		||||
@ -34,7 +34,7 @@ cat << EOFILE > ${REPO_FOLDER}/${SPARKLE_FILE}
 | 
			
		||||
            <pubDate>$DATE_RFC2822</pubDate>
 | 
			
		||||
            <sparkle:version>${BUILD}</sparkle:version>
 | 
			
		||||
            <sparkle:shortVersionString>${VERSION}</sparkle:shortVersionString>
 | 
			
		||||
            <sparkle:minimumSystemVersion>10.15.0</sparkle:minimumSystemVersion>
 | 
			
		||||
            <sparkle:minimumSystemVersion>11.0</sparkle:minimumSystemVersion>
 | 
			
		||||
            <enclosure url="${REPO_URL}/$(basename ${PACKAGE})" type="application/octet-stream" $(./sign_update ${PACKAGE}) />
 | 
			
		||||
        </item>
 | 
			
		||||
$(echo -e "${ITEMS}")
 | 
			
		||||
 | 
			
		||||
@ -1,34 +0,0 @@
 | 
			
		||||
From ca2be6466c150d1b82a646d97b27df35b45d90f1 Mon Sep 17 00:00:00 2001
 | 
			
		||||
From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
 | 
			
		||||
Date: Tue, 9 Jan 2024 15:25:19 -0500
 | 
			
		||||
Subject: [PATCH] workaround right margin
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
 src/core/contexts/win32windowcontext.cpp | 11 +++++++++++
 | 
			
		||||
 1 file changed, 11 insertions(+)
 | 
			
		||||
 | 
			
		||||
diff --git a/src/core/contexts/win32windowcontext.cpp b/src/core/contexts/win32windowcontext.cpp
 | 
			
		||||
index 3f6623e..9ee7752 100644
 | 
			
		||||
--- a/src/core/contexts/win32windowcontext.cpp
 | 
			
		||||
+++ b/src/core/contexts/win32windowcontext.cpp
 | 
			
		||||
@@ -402,6 +402,17 @@ namespace QWK {
 | 
			
		||||
                     return true;
 | 
			
		||||
                 }
 | 
			
		||||
             }
 | 
			
		||||
+
 | 
			
		||||
+#if !QWINDOWKIT_CONFIG(ENABLE_WINDOWS_SYSTEM_BORDERS)
 | 
			
		||||
+            if (msg->message == WM_MOVE || msg->message == WM_SIZE ||
 | 
			
		||||
+                (msg->message == WM_IME_SETCONTEXT && (GetForegroundWindow() == msg->hwnd))) {
 | 
			
		||||
+                static const auto flags = SWP_FRAMECHANGED | SWP_NOMOVE |
 | 
			
		||||
+                                          SWP_NOSIZE | SWP_NOZORDER |
 | 
			
		||||
+                                          SWP_NOOWNERZORDER;
 | 
			
		||||
+                SetWindowPos(msg->hwnd, NULL, 0, 0, 0, 0, flags);
 | 
			
		||||
+            }
 | 
			
		||||
+#endif
 | 
			
		||||
+
 | 
			
		||||
             return false;
 | 
			
		||||
         }
 | 
			
		||||
 | 
			
		||||
--
 | 
			
		||||
2.7.4
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ mutually exclusive required arguments:
 | 
			
		||||
  -z, --zip         Build portable archive
 | 
			
		||||
 | 
			
		||||
examples:
 | 
			
		||||
1.  build.py --qt=C:/Qt/6.6.1/msvc2019_64  # Build the app using a specific Qt
 | 
			
		||||
1.  build.py --qt=C:/Qt/6.6.2/msvc2019_64  # Build the app using a specific Qt
 | 
			
		||||
2.  build.py --init pack --msi             # Build the app and an MSI installer
 | 
			
		||||
3.  build.py --init --tests                # Build the app and run tests
 | 
			
		||||
    build.py pack --zip --skip-build       # Generate a 7z archive of the app
 | 
			
		||||
@ -280,7 +280,7 @@ def build(config_str, qt_dir, tests):
 | 
			
		||||
        "-DCMAKE_INSTALL_PREFIX=" + os.getcwd(),
 | 
			
		||||
        "-DCMAKE_SYSTEM_VERSION=" + WIN_SDK_VERSION,
 | 
			
		||||
        "-DCMAKE_BUILD_TYPE=" + "Release",
 | 
			
		||||
        "-DENABLE_TESTS=" + str(tests).lower(),
 | 
			
		||||
        "-DBUILD_TESTING=" + str(tests).lower(),
 | 
			
		||||
        "-DBETA=" + str((0, 1)[config_str == "Beta"]),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -99,6 +99,12 @@ for ARCH in "${ARCHS[@]}"; do
 | 
			
		||||
  echo "$ARCH"
 | 
			
		||||
  cd "$DAEMON"
 | 
			
		||||
  HOST="${ARCH}-apple-darwin"
 | 
			
		||||
  SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
 | 
			
		||||
 | 
			
		||||
  CC="xcrun -sdk macosx clang"
 | 
			
		||||
  CXX="xcrun -sdk macosx clang++"
 | 
			
		||||
  CFLAGS="-arch $ARCH -isysroot $SDKROOT"
 | 
			
		||||
  CXXFLAGS="-std=c++17 $CFLAGS"
 | 
			
		||||
  CONFIGURE_FLAGS=" --without-dbus --host=${HOST} -with-contrib=$DAEMON/contrib/${ARCH}-apple-darwin${OS_VER} --prefix=${INSTALL}/daemon/$ARCH"
 | 
			
		||||
 | 
			
		||||
  if [ "${debug}" = "true" ]; then
 | 
			
		||||
@ -113,7 +119,11 @@ for ARCH in "${ARCHS[@]}"; do
 | 
			
		||||
  mkdir -p "build-macos-${ARCH}"
 | 
			
		||||
  cd "build-macos-${ARCH}"
 | 
			
		||||
 | 
			
		||||
  "$DAEMON"/configure $CONFIGURE_FLAGS ARCH="$ARCH" || exit 1
 | 
			
		||||
  "$DAEMON"/configure $CONFIGURE_FLAGS ARCH="$ARCH" \
 | 
			
		||||
    CC="$CC $CFLAGS" \
 | 
			
		||||
    CXX="$CXX $CXXFLAGS" \
 | 
			
		||||
    CFLAGS="$CFLAGS" \
 | 
			
		||||
    CXXFLAGS="$CXXFLAGS" || exit 1
 | 
			
		||||
 | 
			
		||||
  echo "$CONFIGURE_FLAGS"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,8 @@ export OSTYPE
 | 
			
		||||
  # -W: disable libwrap and shared library
 | 
			
		||||
  # -w: do not use Qt WebEngine
 | 
			
		||||
  # -a: arch to build
 | 
			
		||||
  # -A: enable AddressSanitizer
 | 
			
		||||
  # -D: extra CMake flags for the client
 | 
			
		||||
 | 
			
		||||
set -ex
 | 
			
		||||
 | 
			
		||||
@ -44,9 +46,11 @@ priv_install=true
 | 
			
		||||
enable_libwrap=true
 | 
			
		||||
enable_webengine=true
 | 
			
		||||
asan=
 | 
			
		||||
extra_cmake_flags=''
 | 
			
		||||
arch=''
 | 
			
		||||
enable_testing=false
 | 
			
		||||
 | 
			
		||||
while getopts gsc:dQ:P:p:uWwa:A OPT; do
 | 
			
		||||
while getopts gsc:dQ:P:p:uWwa:AtD: OPT; do
 | 
			
		||||
  case "$OPT" in
 | 
			
		||||
    g)
 | 
			
		||||
      global='true'
 | 
			
		||||
@ -81,6 +85,12 @@ while getopts gsc:dQ:P:p:uWwa:A OPT; do
 | 
			
		||||
    A)
 | 
			
		||||
      asan='true'
 | 
			
		||||
    ;;
 | 
			
		||||
    t)
 | 
			
		||||
      enable_testing='true'
 | 
			
		||||
    ;;
 | 
			
		||||
    D)
 | 
			
		||||
      extra_cmake_flags="${OPTARG}"
 | 
			
		||||
    ;;
 | 
			
		||||
    \?)
 | 
			
		||||
      exit 1
 | 
			
		||||
    ;;
 | 
			
		||||
@ -196,6 +206,12 @@ if [ "${asan}" = "true" ]; then
 | 
			
		||||
    client_cmake_flags+=(-DENABLE_ASAN=true)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "${enable_testing}" = "true" ]; then
 | 
			
		||||
    client_cmake_flags+=(-DBUILD_TESTING=On)
 | 
			
		||||
else
 | 
			
		||||
    client_cmake_flags+=(-DBUILD_TESTING=Off)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [[ "$OSTYPE" == "darwin"* ]]; then
 | 
			
		||||
    #detect arch for macos
 | 
			
		||||
    CMAKE_OSX_ARCHITECTURES="arm64"
 | 
			
		||||
@ -220,6 +236,11 @@ else
 | 
			
		||||
                         -DWITH_DAEMON_SUBMODULE=true)
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
# Add extra flags for the client
 | 
			
		||||
if [ -n "${extra_cmake_flags}" ]; then
 | 
			
		||||
    client_cmake_flags+=(${extra_cmake_flags})
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
echo "info: Configuring $client client with flags: ${client_cmake_flags[*]}"
 | 
			
		||||
cmake .. "${client_cmake_flags[@]}"
 | 
			
		||||
make -j"${proc}" V=1
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
	<key>CFBundleShortVersionString</key>
 | 
			
		||||
	<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
 | 
			
		||||
	<key>LSMinimumSystemVersion</key>
 | 
			
		||||
	<string>10.15</string>
 | 
			
		||||
	<string>11.0</string>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
 | 
			
		||||
	<key>LSApplicationCategoryType</key>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										10
									
								
								resources/icons/Receive.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,10 @@
 | 
			
		||||
<svg id="Receive" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="12" height="12" viewBox="0 0 12 12">
 | 
			
		||||
  <defs>
 | 
			
		||||
    <clipPath id="clip-path">
 | 
			
		||||
      <rect id="Rectangle_429" data-name="Rectangle 429" width="12" height="12" fill="none"/>
 | 
			
		||||
    </clipPath>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <g id="Group_225" data-name="Group 225" clip-path="url(#clip-path)">
 | 
			
		||||
    <path id="Path_333" data-name="Path 333" d="M6.43,8.784,3.007,5.362,4.06,4.309l2.37,2.37,4.314-4.314A5.966,5.966,0,0,0,6,0c-.032,0-.061.008-.094.01A5.98,5.98,0,0,0,.094,5.074,5.911,5.911,0,0,0,0,6a5.911,5.911,0,0,0,.094.926A5.98,5.98,0,0,0,5.906,11.99c.032,0,.061.01.094.01a6,6,0,0,0,5.533-8.32Z" fill="#60c880"/>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 702 B  | 
							
								
								
									
										3
									
								
								resources/icons/incoming-call.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="22.08" height="22.08" viewBox="0 0 22.08 22.08">
 | 
			
		||||
  <path id="noun-arrow-1167262" d="M35.45,26.488l-4.476,4.476V18.9H28.916V30.964l-4.476-4.476L23,27.955,29.945,34.9l6.971-6.945Z" transform="translate(8.913 -29.202) rotate(45)" stroke="#000" stroke-width="0.5"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 316 B  | 
							
								
								
									
										8
									
								
								resources/icons/missed-incoming-call.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,8 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="8.814" viewBox="0 0 16 8.814">
 | 
			
		||||
  <g id="noun-missed-3555066" transform="translate(-23.455 -28)">
 | 
			
		||||
    <g id="Group_82" data-name="Group 82" transform="translate(23.455 28)">
 | 
			
		||||
      <path id="Path_289" data-name="Path 289" d="M37.727,37.615a2.761,2.761,0,0,1-1.964-.815L31.17,32.211l1.782-1.782,4.589,4.593a.268.268,0,0,0,.368,0l5.852-5.852,1.782,1.782L39.691,36.8A2.761,2.761,0,0,1,37.727,37.615Z" transform="translate(-29.543 -28.802)"/>
 | 
			
		||||
      <path id="Path_290" data-name="Path 290" d="M28.518,35.555H26v-6.3A1.259,1.259,0,0,1,27.259,28h6.3v2.518H28.518Z" transform="translate(-26 -28)"/>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 672 B  | 
							
								
								
									
										8
									
								
								resources/icons/missed-outgoing-call.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,8 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="8.814" viewBox="0 0 16 8.814">
 | 
			
		||||
  <g id="noun-missed-3555066" transform="translate(-0.001)">
 | 
			
		||||
    <g id="Group_82" data-name="Group 82" transform="translate(0.001)">
 | 
			
		||||
      <path id="Path_289" data-name="Path 289" d="M38.986,37.615A2.761,2.761,0,0,0,40.95,36.8l4.593-4.589-1.782-1.782-4.589,4.593a.268.268,0,0,1-.368,0L32.952,29.17,31.17,30.952,37.022,36.8A2.761,2.761,0,0,0,38.986,37.615Z" transform="translate(-31.17 -28.802)"/>
 | 
			
		||||
      <path id="Path_290" data-name="Path 290" d="M31.036,35.555h2.518v-6.3A1.259,1.259,0,0,0,32.3,28H26v2.518h5.036Z" transform="translate(-17.555 -28)"/>
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 666 B  | 
							
								
								
									
										3
									
								
								resources/icons/outgoing-call.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,3 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" width="22.08" height="22.08" viewBox="0 0 22.08 22.08">
 | 
			
		||||
  <path id="noun-arrow-1167262" d="M12.45,7.589,7.974,12.064V0H5.916V12.064L1.44,7.588,0,9.055,6.945,16l6.971-6.945Z" transform="translate(10.267 21.654) rotate(-135)" stroke="#000" stroke-width="0.5"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 306 B  | 
@ -1 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M42 13.85V39q0 1.2-.9 2.1-.9.9-2.1.9H9q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h25.15Zm-3 1.35L32.8 9H9v30h30ZM24 35.75q2.15 0 3.675-1.525T29.2 30.55q0-2.15-1.525-3.675T24 25.35q-2.15 0-3.675 1.525T18.8 30.55q0 2.15 1.525 3.675T24 35.75ZM11.65 18.8h17.9v-7.15h-17.9ZM9 15.2V39 9Z"/></svg>
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M480-313 287-506l43-43 120 120v-371h60v371l120-120 43 43-193 193ZM220-160q-24 0-42-18t-18-42v-143h60v143h520v-143h60v143q0 24-18 42t-42 18H220Z"/></svg>
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 268 B  | 
							
								
								
									
										11
									
								
								resources/icons/share_black_24dp.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,11 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
 | 
			
		||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
 | 
			
		||||
	 viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
 | 
			
		||||
<path d="M17.1,15.7c-0.8,0-1.5,0.3-2.1,0.8l-5.3-3.3C9.9,12.8,10,12.4,10,12c0-0.4-0.1-0.8-0.3-1.2l5.3-3.3c0.6,0.5,1.3,0.8,2.1,0.8
 | 
			
		||||
	c1.7,0,3.1-1.4,3.1-3.1S18.9,2,17.1,2C15.4,2,14,3.4,14,5.1c0,0.4,0.1,0.8,0.3,1.2L8.9,9.6C8.3,9.1,7.6,8.9,6.9,8.9
 | 
			
		||||
	c-1.7,0-3.1,1.4-3.1,3.1s1.4,3.1,3.1,3.1c0.8,0,1.5-0.3,2.1-0.8l5.3,3.3C14.1,18,14,18.4,14,18.9c0,1.7,1.4,3.1,3.1,3.1
 | 
			
		||||
	c1.7,0,3.1-1.4,3.1-3.1S18.9,15.7,17.1,15.7z M17.1,20.6c-1,0-1.8-0.8-1.8-1.8s0.8-1.8,1.8-1.8c1,0,1.8,0.8,1.8,1.8
 | 
			
		||||
	S18.1,20.6,17.1,20.6z M17.1,3.4c1,0,1.8,0.8,1.8,1.8s-0.8,1.8-1.8,1.8c-1,0-1.8-0.8-1.8-1.8S16.2,3.4,17.1,3.4z M6.9,13.8
 | 
			
		||||
	c-1,0-1.8-0.8-1.8-1.8s0.8-1.8,1.8-1.8S8.6,11,8.6,12S7.8,13.8,6.9,13.8z"/>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1019 B  | 
@ -1,10 +1,13 @@
 | 
			
		||||
<h4 align="left"><span style="font-weight:600"> Created by</span></h4>
 | 
			
		||||
<p>Adrien Béraud<br>
 | 
			
		||||
<p>%1</p>
 | 
			
		||||
<h4 align="left"><span style="font-weight:600">%2</span></h4>
 | 
			
		||||
<p>Abhishek Ojha<br>
 | 
			
		||||
Adrien Béraud<br>
 | 
			
		||||
Albert Babí<br>
 | 
			
		||||
Alexandre Lision<br>
 | 
			
		||||
Alexandr Sergheev<br>
 | 
			
		||||
Alexandre Viau<br>
 | 
			
		||||
Alexander Lussier-Cullen<br>
 | 
			
		||||
Alexandr Sergheev<br>
 | 
			
		||||
Alexandre Eberhardt<br>
 | 
			
		||||
Alexandre Lision<br>
 | 
			
		||||
Alexandre Viau<br>
 | 
			
		||||
Aline Bonnet<br>
 | 
			
		||||
Aline Gondim Santos<br>
 | 
			
		||||
Alireza Toghiani<br>
 | 
			
		||||
@ -17,7 +20,6 @@ Brando Tovar<br>
 | 
			
		||||
Capucine Berthet<br>
 | 
			
		||||
Charles-Francis Damedey<br>
 | 
			
		||||
Cyrille Béraud<br>
 | 
			
		||||
Dorina Mosku<br>
 | 
			
		||||
Eden Abitbol<br>
 | 
			
		||||
Édric Milaret<br>
 | 
			
		||||
Éloi Bail<br>
 | 
			
		||||
@ -25,17 +27,23 @@ Emma Falkiewitz<br>
 | 
			
		||||
Emmanuel Lepage-Vallée<br>
 | 
			
		||||
Fadi Shehadeh<br>
 | 
			
		||||
Franck Laurent<br>
 | 
			
		||||
François-Simon Fauteux-Chapleau<br>
 | 
			
		||||
Frédéric Guimont<br>
 | 
			
		||||
Guillaume Heller<br>
 | 
			
		||||
Guillaume Roguez<br>
 | 
			
		||||
Hadrien De Sousa<br>
 | 
			
		||||
Hugo Lefeuvre<br>
 | 
			
		||||
Julien Grossholtz<br>
 | 
			
		||||
Julien Robert<br>
 | 
			
		||||
Kateryna Kostiuk<br>
 | 
			
		||||
Kessler DuPont-Teevin<br>
 | 
			
		||||
Léo Banno-Cloutier<br>
 | 
			
		||||
Léopold Chappuis<br>
 | 
			
		||||
Liam Courdoson<br>
 | 
			
		||||
Loïc Siret<br>
 | 
			
		||||
Louis Maillard<br>
 | 
			
		||||
Mathéo Joseph<br>
 | 
			
		||||
Michel Schmit<br>
 | 
			
		||||
Mingrui Zhang<br>
 | 
			
		||||
Mohamed Chibani<br>
 | 
			
		||||
Mohamed Amine Younes Bouacida<br>
 | 
			
		||||
@ -55,6 +63,7 @@ Rayan Osseiran<br>
 | 
			
		||||
Romain Bertozzi<br>
 | 
			
		||||
Saher Azer<br>
 | 
			
		||||
Sébastien Blin<br>
 | 
			
		||||
Seva Ivanov<br>
 | 
			
		||||
Silbino Gonçalves Matado<br>
 | 
			
		||||
Simon Désaulniers<br>
 | 
			
		||||
Simon Zeni<br>
 | 
			
		||||
@ -62,9 +71,21 @@ Stepan Salenikovich<br>
 | 
			
		||||
Thibault Wittemberg<br>
 | 
			
		||||
Thomas Ballasi<br>
 | 
			
		||||
Trevor Tabah<br>
 | 
			
		||||
Vitalii Nikitchyn<br>
 | 
			
		||||
Vsevolod Ivanov<br>
 | 
			
		||||
Xavier Jouslin de Noray<br>
 | 
			
		||||
Yang Wang<br></p>
 | 
			
		||||
<h4 align="left"><span style="font-weight:600"> Artwork by</span></h4>
 | 
			
		||||
Yang Wang<br>
 | 
			
		||||
</p>
 | 
			
		||||
<h4 align="left"><span style="font-weight:600"> %3</span></h4>
 | 
			
		||||
<p>Charlotte Hoffmann<br>
 | 
			
		||||
Marianne Forget<br></p>
 | 
			
		||||
<h4 align="left"><span style="font-weight:600"> %4</span></h4>
 | 
			
		||||
<p>Dorina Mosku<br>
 | 
			
		||||
Cabrel Tambue<br>
 | 
			
		||||
Loïc Bogino<br></p>
 | 
			
		||||
<h4 align="left"><span style="font-weight:600"> %5</span></h4>
 | 
			
		||||
<p>Anna<br>
 | 
			
		||||
Elys<br>
 | 
			
		||||
VeroJeanLuc<br>
 | 
			
		||||
</p>
 | 
			
		||||
<p>%6</p>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										217
									
								
								src/app/ComponentTestWindow.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,217 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2024 Savoir-faire Linux Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import QtQuick
 | 
			
		||||
import QtQuick.Controls
 | 
			
		||||
import QtQuick.Layouts
 | 
			
		||||
import Qt.labs.qmlmodels
 | 
			
		||||
 | 
			
		||||
import net.jami.Models 1.1
 | 
			
		||||
import net.jami.Adapters 1.1
 | 
			
		||||
import net.jami.Enums 1.1
 | 
			
		||||
import net.jami.Helpers 1.1
 | 
			
		||||
import net.jami.Constants 1.1
 | 
			
		||||
 | 
			
		||||
import "mainview"
 | 
			
		||||
import "mainview/components"
 | 
			
		||||
import "wizardview"
 | 
			
		||||
import "commoncomponents"
 | 
			
		||||
 | 
			
		||||
// A window into which we can load a QML file for testing.
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
    id: appWindow
 | 
			
		||||
    visible: true
 | 
			
		||||
    width: testWidth || loader.implicitWidth || 800
 | 
			
		||||
    height: testHeight || loader.implicitHeight || 600
 | 
			
		||||
    title: testComponentURI
 | 
			
		||||
 | 
			
		||||
    // WARNING: The following currently must be maintained in tandem with MainApplicationWindow.qml
 | 
			
		||||
    // Used to manage full screen mode and save/restore window geometry.
 | 
			
		||||
    readonly property bool useFrameless: false
 | 
			
		||||
    property bool isRTL: UtilsAdapter.isRTL
 | 
			
		||||
    LayoutMirroring.enabled: isRTL
 | 
			
		||||
    LayoutMirroring.childrenInherit: isRTL
 | 
			
		||||
    property LayoutManager layoutManager: LayoutManager {
 | 
			
		||||
        appContainer: null
 | 
			
		||||
    }
 | 
			
		||||
    // Used to manage dynamic view loading and unloading.
 | 
			
		||||
    property ViewManager viewManager: ViewManager {}
 | 
			
		||||
    // Used to manage the view stack and the current view.
 | 
			
		||||
    property ViewCoordinator viewCoordinator: ViewCoordinator {}
 | 
			
		||||
 | 
			
		||||
    Loader {
 | 
			
		||||
        id: loader
 | 
			
		||||
 | 
			
		||||
        source: Qt.resolvedUrl(testComponentURI)
 | 
			
		||||
        onStatusChanged: {
 | 
			
		||||
            console.log("Status changed to:", loader.status)
 | 
			
		||||
            if (loader.status == Loader.Error || loader.status == Loader.Null) {
 | 
			
		||||
                console.error("Couldn't load component:", source)
 | 
			
		||||
                Qt.exit(1);
 | 
			
		||||
            } else if (loader.status == Loader.Ready) {
 | 
			
		||||
                console.info("Loaded component:", source);
 | 
			
		||||
                // If any of the dimensions are not set, set them to the appWindow's dimensions
 | 
			
		||||
                item.width = item.width || Qt.binding(() => appWindow.width);
 | 
			
		||||
                item.height = item.height || Qt.binding(() => appWindow.height);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Closing this window should always exit the application.
 | 
			
		||||
    onClosing: Qt.quit()
 | 
			
		||||
 | 
			
		||||
    // A window to modify properties for Jamified components.
 | 
			
		||||
    // Sometimes we need to modify properties including current conversation ID, account ID, etc.
 | 
			
		||||
    // This window should have a simple layout: a list of editable parameters within a scroll view.
 | 
			
		||||
    Window {
 | 
			
		||||
        id: configTool
 | 
			
		||||
        width: 400
 | 
			
		||||
        height: 400
 | 
			
		||||
        title: "Config tool"
 | 
			
		||||
 | 
			
		||||
        visible: true
 | 
			
		||||
        // Cannot be closed.
 | 
			
		||||
        flags: Qt.SplashScreen
 | 
			
		||||
 | 
			
		||||
        // Anchor the window to the right of the parent window.
 | 
			
		||||
        x: appWindow.x + appWindow.width
 | 
			
		||||
        y: appWindow.y
 | 
			
		||||
 | 
			
		||||
        color: "lightgray"
 | 
			
		||||
 | 
			
		||||
        Page {
 | 
			
		||||
            anchors.fill: parent
 | 
			
		||||
            header: Control {
 | 
			
		||||
                contentItem: Text {
 | 
			
		||||
                    horizontalAlignment: Text.AlignHCenter
 | 
			
		||||
                    text: "Config tool"
 | 
			
		||||
                }
 | 
			
		||||
                background: Rectangle { color: configTool.color }
 | 
			
		||||
            }
 | 
			
		||||
            contentItem: Control {
 | 
			
		||||
                background: Rectangle { color: Qt.lighter(configTool.color, 1.1) }
 | 
			
		||||
                padding: 10
 | 
			
		||||
                contentItem: ListView {
 | 
			
		||||
                    // Declare types of controls. TODO: add as needed.
 | 
			
		||||
                    Component {
 | 
			
		||||
                        id: checkComponent
 | 
			
		||||
                        CheckBox {
 | 
			
		||||
                            text: label
 | 
			
		||||
                            onCheckedChanged: checkChangedCb(checked)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Component {
 | 
			
		||||
                        id: comboComponent
 | 
			
		||||
                        Control {
 | 
			
		||||
                            contentItem: RowLayout {
 | 
			
		||||
                                Text { text: label }
 | 
			
		||||
                                ComboBox {
 | 
			
		||||
                                    id: comboBox
 | 
			
		||||
                                    displayText: CurrentConversation.title || "undefined"
 | 
			
		||||
                                    model: getDataModel()
 | 
			
		||||
                                    delegate: ItemDelegate {
 | 
			
		||||
                                        highlighted: comboBox.highlightedIndex === index
 | 
			
		||||
                                        width: parent.width
 | 
			
		||||
                                        text: JamiQmlUtils.getModelData(comboBox.model, index, displayRole)
 | 
			
		||||
                                    }
 | 
			
		||||
                                    onCurrentIndexChanged: onIndexChanged(model, currentIndex)
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    spacing: 5
 | 
			
		||||
                    model: ListModel {
 | 
			
		||||
                        ListElement {
 | 
			
		||||
                            label: "Conversation ID"
 | 
			
		||||
                            type: "combobox"
 | 
			
		||||
                            getDataModel: () => ConversationsAdapter.convListProxyModel
 | 
			
		||||
                            displayRole: ConversationList.Title
 | 
			
		||||
                            onIndexChanged: function(model, index) {
 | 
			
		||||
                                const convUid = JamiQmlUtils.getModelData(model, index, ConversationList.UID);
 | 
			
		||||
                                LRCInstance.selectConversation(convUid);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        ListElement {
 | 
			
		||||
                            label: "Account ID"
 | 
			
		||||
                            type: "combobox"
 | 
			
		||||
                            getDataModel: () => AccountListModel
 | 
			
		||||
                            displayRole: AccountList.Username
 | 
			
		||||
                            onIndexChanged: function(model, index) {
 | 
			
		||||
                                const accountId = JamiQmlUtils.getModelData(model, index, AccountList.ID);
 | 
			
		||||
                                LRCInstance.currentAccountId = accountId;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        ListElement {
 | 
			
		||||
                            label: "Force local preview"
 | 
			
		||||
                            type: "checkbox"
 | 
			
		||||
                            value: false
 | 
			
		||||
                            checkChangedCb: function(checked) {
 | 
			
		||||
                                // Find any child component of type `LocalVideo` and start it.
 | 
			
		||||
                                const localVideo = findChild(loader.item, LocalVideo, "type");
 | 
			
		||||
                                if (localVideo) {
 | 
			
		||||
                                    if (checked) {
 | 
			
		||||
                                        localVideo.startWithId(VideoDevices.getDefaultDevice());
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        localVideo.startWithId("");
 | 
			
		||||
                                    }
 | 
			
		||||
                                } else {
 | 
			
		||||
                                    console.error("LocalVideo not found");
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    delegate: DelegateChooser {
 | 
			
		||||
                        role: "type"
 | 
			
		||||
                        DelegateChoice {
 | 
			
		||||
                            roleValue: "checkbox"
 | 
			
		||||
                            delegate: checkComponent
 | 
			
		||||
                        }
 | 
			
		||||
                        DelegateChoice {
 | 
			
		||||
                            roleValue: "combobox"
 | 
			
		||||
                            delegate: comboComponent
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // From TestCase.qml, refactored to find a child by type or name.
 | 
			
		||||
    function findChild(parent, searchValue, searchBy = "name") {
 | 
			
		||||
        if (!parent || parent.children === undefined) {
 | 
			
		||||
            console.error("No children found");
 | 
			
		||||
            return null;
 | 
			
		||||
        }
 | 
			
		||||
        // Search directly under the given parent
 | 
			
		||||
        for (var i = 0; i < parent.children.length; ++i) {
 | 
			
		||||
            var child = parent.children[i];
 | 
			
		||||
            var match = false;
 | 
			
		||||
            if (searchBy === "name" && child.objectName === searchValue) {
 | 
			
		||||
                match = true;
 | 
			
		||||
            } else if (searchBy === "type" && child instanceof searchValue) {
 | 
			
		||||
                match = true;
 | 
			
		||||
            }
 | 
			
		||||
            if (match) return child;
 | 
			
		||||
        }
 | 
			
		||||
        // Recursively search in child objects
 | 
			
		||||
        for (i = 0; i < parent.children.length; ++i) {
 | 
			
		||||
            var found = findChild(parent.children[i], searchValue, searchBy);
 | 
			
		||||
            if (found) return found;
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -41,6 +41,20 @@ QtObject {
 | 
			
		||||
    // Used to store if a OngoingCallPage component is fullscreened.
 | 
			
		||||
    property bool isCallFullscreen: false
 | 
			
		||||
 | 
			
		||||
    // QWK: Provide spacing for widgets that may be occluded by the system buttons.
 | 
			
		||||
    property QtObject qwkSystemButtonSpacing: QtObject {
 | 
			
		||||
        id: qwkSystemButtonSpacing
 | 
			
		||||
        readonly property bool isMacOS: Qt.platform.os.toString() === "osx"
 | 
			
		||||
        // macOS buttons are on the left.
 | 
			
		||||
        readonly property real left: {
 | 
			
		||||
            appWindow.useFrameless && isMacOS && viewCoordinator.isInSinglePaneMode ? 80 : 0
 | 
			
		||||
        }
 | 
			
		||||
        // Windows and Linux buttons are on the right.
 | 
			
		||||
        readonly property real right: {
 | 
			
		||||
            appWindow.useFrameless && !isMacOS && !root.isFullscreen ? sysBtnsLoader.width + 24 : 0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Restore a visible windowed mode.
 | 
			
		||||
    function restoreApp() {
 | 
			
		||||
        if (isHidden) {
 | 
			
		||||
 | 
			
		||||
@ -41,14 +41,11 @@ import QWindowKit
 | 
			
		||||
ApplicationWindow {
 | 
			
		||||
    id: appWindow
 | 
			
		||||
 | 
			
		||||
    readonly property bool useFrameless: UtilsAdapter.getAppValue(Settings.Key.UseFramelessWindow)
 | 
			
		||||
    property bool isRTL: UtilsAdapter.isRTL
 | 
			
		||||
 | 
			
		||||
    LayoutMirroring.enabled: isRTL
 | 
			
		||||
    LayoutMirroring.childrenInherit: isRTL
 | 
			
		||||
 | 
			
		||||
    // This needs to be set from the start.
 | 
			
		||||
    readonly property bool useFrameless: UtilsAdapter.getAppValue(Settings.Key.UseFramelessWindow)
 | 
			
		||||
 | 
			
		||||
    onActiveFocusItemChanged: {
 | 
			
		||||
        focusOverlay.margin = -5;
 | 
			
		||||
        if (activeFocusItem && ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason))) {
 | 
			
		||||
@ -94,16 +91,10 @@ ApplicationWindow {
 | 
			
		||||
        id: layoutManager
 | 
			
		||||
        appContainer: fullscreenContainer
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Used to manage dynamic view loading and unloading.
 | 
			
		||||
    ViewManager {
 | 
			
		||||
        id: viewManager
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    property ViewManager viewManager: ViewManager {}
 | 
			
		||||
    // Used to manage the view stack and the current view.
 | 
			
		||||
    ViewCoordinator {
 | 
			
		||||
        id: viewCoordinator
 | 
			
		||||
    }
 | 
			
		||||
    property ViewCoordinator viewCoordinator: ViewCoordinator {}
 | 
			
		||||
 | 
			
		||||
    // Used to prevent the window from being visible until the
 | 
			
		||||
    // window geometry has been restored and the view stack has
 | 
			
		||||
@ -125,7 +116,8 @@ ApplicationWindow {
 | 
			
		||||
    function close(force = false) {
 | 
			
		||||
        // If we're in the onboarding wizard or 'MinimizeOnClose'
 | 
			
		||||
        // is set, then we can quit
 | 
			
		||||
        if (force || !UtilsAdapter.getAppValue(Settings.MinimizeOnClose) || !UtilsAdapter.getAccountListSize()) {
 | 
			
		||||
        var minimizeToTray = UtilsAdapter.getAppValue(Settings.MinimizeOnClose) && UtilsAdapter.isSystemTrayIconVisible();
 | 
			
		||||
        if (force || !minimizeToTray || !UtilsAdapter.getAccountListSize()) {
 | 
			
		||||
            Qt.quit();
 | 
			
		||||
        } else {
 | 
			
		||||
            layoutManager.closeToTray();
 | 
			
		||||
@ -234,17 +226,6 @@ ApplicationWindow {
 | 
			
		||||
        anchors.fill: parent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // QWK: Provide spacing for widgets that may be occluded by the system buttons.
 | 
			
		||||
    QtObject {
 | 
			
		||||
        id: qwkSystemButtonSpacing
 | 
			
		||||
        readonly property bool isMacOS: Qt.platform.os.toString() === "osx"
 | 
			
		||||
        readonly property bool isFullscreen: layoutManager.isFullScreen
 | 
			
		||||
        // macOS buttons are on the left.
 | 
			
		||||
        readonly property real left: useFrameless && isMacOS && viewCoordinator.isInSinglePaneMode ? 80 : 0
 | 
			
		||||
        // Windows and Linux buttons are on the right.
 | 
			
		||||
        readonly property real right: useFrameless && !isMacOS && !isFullscreen ? sysBtnsLoader.width + 24 : 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // QWK: Window Title bar
 | 
			
		||||
    Item {
 | 
			
		||||
        id: titleBar
 | 
			
		||||
@ -289,6 +270,12 @@ ApplicationWindow {
 | 
			
		||||
            raise();
 | 
			
		||||
            layoutManager.restoreApp();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        function onCurrentAccountRemoved() {
 | 
			
		||||
            if (UtilsAdapter.getAccountListSize() === 0) {
 | 
			
		||||
                viewCoordinator.present("WizardView");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Connections {
 | 
			
		||||
 | 
			
		||||
@ -227,7 +227,7 @@ AccountAdapter::createJAMSAccount(const QVariantMap& settings)
 | 
			
		||||
        &lrcInstance_->accountModel(),
 | 
			
		||||
        &lrc::api::AccountModel::accountAdded,
 | 
			
		||||
        [this](const QString& accountId) {
 | 
			
		||||
            if (!lrcInstance_->accountModel().getAccountList().size())
 | 
			
		||||
            if (!lrcInstance_->accountModel().getAccountCount())
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            Utils::oneShotConnect(&lrcInstance_->accountModel(),
 | 
			
		||||
 | 
			
		||||
@ -29,13 +29,42 @@ AccountListModel::AccountListModel(LRCInstance* instance, QObject* parent)
 | 
			
		||||
    : AbstractListModelBase(parent)
 | 
			
		||||
{
 | 
			
		||||
    lrcInstance_ = instance;
 | 
			
		||||
 | 
			
		||||
    // Avoid resetting/redrawing the model when the account status changes.
 | 
			
		||||
    QObject::connect(&lrcInstance_->accountModel(),
 | 
			
		||||
                     &AccountModel::accountStatusChanged,
 | 
			
		||||
                     this,
 | 
			
		||||
                     [&](const QString& accountId) {
 | 
			
		||||
                         auto accountList = lrcInstance_->accountModel().getAccountList();
 | 
			
		||||
                         auto index = accountList.indexOf(accountId);
 | 
			
		||||
                         if (index != -1) {
 | 
			
		||||
                             QModelIndex modelIndex = QAbstractListModel::index(index, 0);
 | 
			
		||||
                             Q_EMIT dataChanged(modelIndex, modelIndex /*, ALL ROLES */);
 | 
			
		||||
                         }
 | 
			
		||||
                     });
 | 
			
		||||
    // If there's a reorder, it's reasonable to reset the model for simplicity, instead
 | 
			
		||||
    // of computing the difference. The same goes for accounts being added and removed.
 | 
			
		||||
    // These operations will only occur when the list is hidden, unless dbus is used while
 | 
			
		||||
    // the list is visible.
 | 
			
		||||
    QObject::connect(&lrcInstance_->accountModel(),
 | 
			
		||||
                     &AccountModel::accountsReordered,
 | 
			
		||||
                     this,
 | 
			
		||||
                     &AccountListModel::reset);
 | 
			
		||||
    QObject::connect(&lrcInstance_->accountModel(),
 | 
			
		||||
                     &AccountModel::accountAdded,
 | 
			
		||||
                     this,
 | 
			
		||||
                     &AccountListModel::reset);
 | 
			
		||||
    QObject::connect(&lrcInstance_->accountModel(),
 | 
			
		||||
                     &AccountModel::accountRemoved,
 | 
			
		||||
                     this,
 | 
			
		||||
                     &AccountListModel::reset);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
AccountListModel::rowCount(const QModelIndex& parent) const
 | 
			
		||||
{
 | 
			
		||||
    if (!parent.isValid() && lrcInstance_) {
 | 
			
		||||
        return lrcInstance_->accountModel().getAccountList().size();
 | 
			
		||||
        return lrcInstance_->accountModel().getAccountCount();
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -71,7 +100,7 @@ AccountListModel::data(const QModelIndex& index, int role) const
 | 
			
		||||
void
 | 
			
		||||
AccountListModel::updateNotifications()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < lrcInstance_->accountModel().getAccountList().size(); ++i) {
 | 
			
		||||
    for (int i = 0; i < lrcInstance_->accountModel().getAccountCount(); ++i) {
 | 
			
		||||
        QModelIndex modelIndex = QAbstractListModel::index(i, 0);
 | 
			
		||||
        Q_EMIT dataChanged(modelIndex, modelIndex, {Role::NotificationCount});
 | 
			
		||||
    }
 | 
			
		||||
@ -91,6 +120,7 @@ AccountListModel::roleNames() const
 | 
			
		||||
void
 | 
			
		||||
AccountListModel::reset()
 | 
			
		||||
{
 | 
			
		||||
    // Used to invalidate proxy models.
 | 
			
		||||
    beginResetModel();
 | 
			
		||||
    endResetModel();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,8 @@
 | 
			
		||||
 | 
			
		||||
#include "appsettingsmanager.h"
 | 
			
		||||
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#include <QCoreApplication>
 | 
			
		||||
#include <QLibraryInfo>
 | 
			
		||||
 | 
			
		||||
@ -101,7 +103,7 @@ AppSettingsManager::loadTranslations()
 | 
			
		||||
    installedTr_.clear();
 | 
			
		||||
 | 
			
		||||
    QString locale_name = getLanguage();
 | 
			
		||||
    qDebug() << QString("Using locale: %1").arg(locale_name);
 | 
			
		||||
    C_INFO << QString("Using locale: %1").arg(locale_name);
 | 
			
		||||
    QString locale_lang = locale_name.split('_')[0];
 | 
			
		||||
 | 
			
		||||
    QTranslator* qtTranslator_lang = new QTranslator(qApp);
 | 
			
		||||
 | 
			
		||||
@ -43,11 +43,10 @@ extern const QString defaultDownloadPath;
 | 
			
		||||
 | 
			
		||||
// Common key-value pairs for both APPSTORE and non-APPSTORE builds
 | 
			
		||||
#define COMMON_KEYS \
 | 
			
		||||
    X(MinimizeOnClose, false) \
 | 
			
		||||
    X(MinimizeOnClose, true) \
 | 
			
		||||
    X(DownloadPath, defaultDownloadPath) \
 | 
			
		||||
    X(ScreenshotPath, {}) \
 | 
			
		||||
    X(EnableNotifications, true) \
 | 
			
		||||
    X(EnableTypingIndicator, true) \
 | 
			
		||||
    X(EnableReadReceipt, true) \
 | 
			
		||||
    X(AcceptTransferBelow, 20) \
 | 
			
		||||
    X(AutoAcceptFiles, true) \
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,11 @@
 | 
			
		||||
#include "api/devicemodel.h"
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
#include "screencastportal.h"
 | 
			
		||||
#include "xrectsel.h"
 | 
			
		||||
#ifndef ENABLE_LIBWRAP
 | 
			
		||||
#include <sys/prctl.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <QtConcurrent/QtConcurrent>
 | 
			
		||||
@ -58,6 +62,12 @@ AvAdapter::AvAdapter(LRCInstance* instance, QObject* parent)
 | 
			
		||||
            &lrc::api::AVModel::onRendererFpsChange,
 | 
			
		||||
            this,
 | 
			
		||||
            &AvAdapter::updateRenderersFPSInfo);
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    connect(&lrcInstance_->behaviorController(),
 | 
			
		||||
            &BehaviorController::callStatusChanged,
 | 
			
		||||
            this,
 | 
			
		||||
            &AvAdapter::onCallStatusChanged);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The top left corner of primary screen is (0, 0).
 | 
			
		||||
@ -119,6 +129,93 @@ AvAdapter::shareEntireScreen(int screenNumber)
 | 
			
		||||
        ->addMedia(callId, resource, lrc::api::CallModel::MediaRequestType::SCREENSHARING);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
static std::map<QString, std::unique_ptr<ScreenCastPortal>> callPortal;
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::onCallStatusChanged(const QString& accountId, const QString& callId)
 | 
			
		||||
{
 | 
			
		||||
    auto& accInfo = lrcInstance_->accountModel().getAccountInfo(accountId);
 | 
			
		||||
    auto& callModel = accInfo.callModel;
 | 
			
		||||
    const auto call = callModel->getCall(callId);
 | 
			
		||||
 | 
			
		||||
    if (call.status == lrc::api::call::Status::ENDED) {
 | 
			
		||||
        closePortal(callId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::closePortal(const QString& callId)
 | 
			
		||||
{
 | 
			
		||||
    if (callPortal.count(callId)) {
 | 
			
		||||
        lrcInstance_->avModel().stopPreview(callPortal[callId]->videoInputId);
 | 
			
		||||
        callPortal.erase(callId);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::shareWayland(bool entireScreen)
 | 
			
		||||
{
 | 
			
		||||
    QString callId = lrcInstance_->getCurrentCallId();
 | 
			
		||||
    closePortal(callId);
 | 
			
		||||
 | 
			
		||||
    PortalCaptureType captureType = entireScreen ? PortalCaptureType::SCREEN
 | 
			
		||||
                                                 : PortalCaptureType::WINDOW;
 | 
			
		||||
    auto portal = std::make_unique<ScreenCastPortal>(captureType);
 | 
			
		||||
 | 
			
		||||
    int err = portal->getPipewireFd();
 | 
			
		||||
    if (err == EACCES) {
 | 
			
		||||
        qInfo() << "Can't share screen: permission denied";
 | 
			
		||||
        return;
 | 
			
		||||
    } else if (err != 0) {
 | 
			
		||||
        qWarning() << "Failed to get PipeWire fd. Error code:" << err;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    QString resource = QString("%1%2pipewire pid:%3 fd:%4 node:%5")
 | 
			
		||||
                           .arg(libjami::Media::VideoProtocolPrefix::DISPLAY)
 | 
			
		||||
                           .arg(libjami::Media::VideoProtocolPrefix::SEPARATOR)
 | 
			
		||||
                           .arg(getpid())
 | 
			
		||||
                           .arg(portal->pipewireFd)
 | 
			
		||||
                           .arg(portal->pipewireNode);
 | 
			
		||||
#ifndef ENABLE_LIBWRAP
 | 
			
		||||
    // If the daemon is running as a separate process, then it can't directly use the
 | 
			
		||||
    // PipeWire file descriptor opened by the client, so it will attempt to duplicate
 | 
			
		||||
    // it using the pidfd_getfd system call. This requires the daemon process to have
 | 
			
		||||
    // ptrace permission on the client process. On some systems, this will be true by
 | 
			
		||||
    // default (as long as the client and daemon processes have the same uid), but it
 | 
			
		||||
    // may not be if the Yama Linux Security Module is used. The call to prctl below
 | 
			
		||||
    // will grant permission if the Yama LSM is enabled and set to mode 1.
 | 
			
		||||
    //
 | 
			
		||||
    // References:
 | 
			
		||||
    // https://man7.org/linux/man-pages/man2/pidfd_getfd.2.html
 | 
			
		||||
    // https://man7.org/linux/man-pages/man2/prctl.2.html
 | 
			
		||||
    // https://github.com/torvalds/linux/blob/master/Documentation/admin-guide/LSM/Yama.rst
 | 
			
		||||
    prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY);
 | 
			
		||||
#endif
 | 
			
		||||
    // We open the video input here (instead of letting the daemon do it) to ensure
 | 
			
		||||
    // that the daemon doesn't try to restart it while we still need it, since this
 | 
			
		||||
    // would require getting a new file descriptor for PipeWire.
 | 
			
		||||
    portal->videoInputId = lrcInstance_->avModel().startPreview(resource);
 | 
			
		||||
 | 
			
		||||
    callPortal[callId] = std::move(portal);
 | 
			
		||||
    muteCamera_ = !isCapturing();
 | 
			
		||||
    lrcInstance_->getCurrentCallModel()
 | 
			
		||||
        ->addMedia(callId, resource, lrc::api::CallModel::MediaRequestType::SCREENSHARING);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::shareEntireScreenWayland()
 | 
			
		||||
{
 | 
			
		||||
    shareWayland(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::shareWindowWayland()
 | 
			
		||||
{
 | 
			
		||||
    shareWayland(false);
 | 
			
		||||
}
 | 
			
		||||
#endif // Q_OS_LINUX
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
AvAdapter::shareAllScreens()
 | 
			
		||||
{
 | 
			
		||||
@ -204,10 +301,14 @@ AvAdapter::shareFile(const QString& filePath)
 | 
			
		||||
                              &lrc::api::AVModel::fileOpened,
 | 
			
		||||
                              this,
 | 
			
		||||
                              [this, callId, filePath, resource](bool hasAudio, bool hasVideo) {
 | 
			
		||||
                                    lrcInstance_->avModel().setAutoRestart(resource, true);
 | 
			
		||||
                                    lrcInstance_->getCurrentCallModel()
 | 
			
		||||
                                        ->addMedia(callId, filePath, lrc::api::CallModel::MediaRequestType::FILESHARING, false, hasAudio);
 | 
			
		||||
                                    lrcInstance_->avModel().pausePlayer(resource, false);
 | 
			
		||||
                                  lrcInstance_->avModel().setAutoRestart(resource, true);
 | 
			
		||||
                                  lrcInstance_->getCurrentCallModel()
 | 
			
		||||
                                      ->addMedia(callId,
 | 
			
		||||
                                                 filePath,
 | 
			
		||||
                                                 lrc::api::CallModel::MediaRequestType::FILESHARING,
 | 
			
		||||
                                                 false,
 | 
			
		||||
                                                 hasAudio);
 | 
			
		||||
                                  lrcInstance_->avModel().pausePlayer(resource, false);
 | 
			
		||||
                              });
 | 
			
		||||
 | 
			
		||||
        lrcInstance_->avModel().createMediaPlayer(resource);
 | 
			
		||||
@ -307,6 +408,9 @@ void
 | 
			
		||||
AvAdapter::stopSharing(const QString& source)
 | 
			
		||||
{
 | 
			
		||||
    auto callId = lrcInstance_->getCurrentCallId();
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    closePortal(callId);
 | 
			
		||||
#endif
 | 
			
		||||
    if (!source.isEmpty() && !callId.isEmpty()) {
 | 
			
		||||
        if (source.startsWith(libjami::Media::VideoProtocolPrefix::DISPLAY)) {
 | 
			
		||||
            qDebug() << "Stopping display: " << source;
 | 
			
		||||
 | 
			
		||||
@ -69,9 +69,18 @@ protected:
 | 
			
		||||
     */
 | 
			
		||||
    Q_INVOKABLE bool hasCamera() const;
 | 
			
		||||
 | 
			
		||||
    // Share the screen specificed by screen number.
 | 
			
		||||
    // Share the screen specificed by screen number (all platforms except Wayland).
 | 
			
		||||
    Q_INVOKABLE void shareEntireScreen(int screenNumber);
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    // Share a screen on Wayland.
 | 
			
		||||
    // Sharing a screen on Wayland requires getting permission from the user. The logic for
 | 
			
		||||
    // this is handled by the ScreenCastPortal class using xdg-desktop-portal.
 | 
			
		||||
    // The choice of screen is also handled by xdg-desktop-portal, which is why we don't need
 | 
			
		||||
    // an argument for it (whereas we do on other platforms, cf. shareEntireScreen above).
 | 
			
		||||
    Q_INVOKABLE void shareEntireScreenWayland();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Share the all screens connected.
 | 
			
		||||
    Q_INVOKABLE void shareAllScreens();
 | 
			
		||||
 | 
			
		||||
@ -87,9 +96,18 @@ protected:
 | 
			
		||||
    // Select screen area to display (from all screens).
 | 
			
		||||
    Q_INVOKABLE void shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned height);
 | 
			
		||||
 | 
			
		||||
    // Select window to display.
 | 
			
		||||
    // Select window to display (all platforms except Wayland).
 | 
			
		||||
    Q_INVOKABLE void shareWindow(const QString& windowProcessId, const QString& windowId);
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    // Share a window on Wayland.
 | 
			
		||||
    // Sharing a window on Wayland requires getting permission from the user. The logic for
 | 
			
		||||
    // this is handled by the ScreenCastPortal class using xdg-desktop-portal.
 | 
			
		||||
    // The choice of window is also handled by xdg-desktop-portal, which is why we don't need
 | 
			
		||||
    // arguments for it (whereas we do on other platforms, cf. shareWindow above).
 | 
			
		||||
    Q_INVOKABLE void shareWindowWayland();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Returns the screensharing resource
 | 
			
		||||
    Q_INVOKABLE QString getSharingResource(int screenId = -2,
 | 
			
		||||
                                           const QString& windowProcessId = "",
 | 
			
		||||
@ -121,11 +139,25 @@ private Q_SLOTS:
 | 
			
		||||
    void onAudioDeviceEvent();
 | 
			
		||||
    void onRendererStarted(const QString& id, const QSize& size);
 | 
			
		||||
    void onRendererStopped(const QString& id);
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    // This function needs to be called whenever a screen/window share stops on Wayland.
 | 
			
		||||
    // Failure to do so can cause subsequent sharing attempts to fail.
 | 
			
		||||
    void closePortal(const QString& callId);
 | 
			
		||||
 | 
			
		||||
    // On Wayland, we need to be informed of call status changes so that we can call
 | 
			
		||||
    // closePortal if a call ends while a screen/window share was in progress.
 | 
			
		||||
    void onCallStatusChanged(const QString& accountId, const QString& callId);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Get screens arrangement rect relative to primary screen.
 | 
			
		||||
    const QRect getAllScreensBoundingRect();
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
    // Used internally by shareEntireScreenWayland and shareWindowWayland
 | 
			
		||||
    void shareWayland(bool entireScreen);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    // Get the screen number
 | 
			
		||||
    int getScreenNumber(int screenId = 0) const;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -25,52 +25,74 @@
 | 
			
		||||
 | 
			
		||||
#include <QImage>
 | 
			
		||||
 | 
			
		||||
class AvatarImageProvider : public QuickImageProviderBase
 | 
			
		||||
class AsyncAvatarImageResponseRunnable : public AsyncImageResponseRunnable
 | 
			
		||||
{
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
public:
 | 
			
		||||
    AvatarImageProvider(LRCInstance* instance = nullptr)
 | 
			
		||||
        : QuickImageProviderBase(QQuickImageProvider::Image,
 | 
			
		||||
                                 QQmlImageProviderBase::ForceAsynchronousImageLoading,
 | 
			
		||||
                                 instance)
 | 
			
		||||
    AsyncAvatarImageResponseRunnable(const QString& id,
 | 
			
		||||
                                     const QSize& requestedSize,
 | 
			
		||||
                                     LRCInstance* lrcInstance)
 | 
			
		||||
        : AsyncImageResponseRunnable(id, requestedSize, lrcInstance)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    QImage requestImage(const QString& id, QSize* size, const QSize& requestedSize) override
 | 
			
		||||
    void run() override
 | 
			
		||||
    {
 | 
			
		||||
        Q_UNUSED(size)
 | 
			
		||||
 | 
			
		||||
        if (requestedSize == QSize(0, 0)) {
 | 
			
		||||
            qWarning() << Q_FUNC_INFO << "Image request has no dimensions";
 | 
			
		||||
            return {};
 | 
			
		||||
        // For avatar images, the requested size should be a square. Anything else
 | 
			
		||||
        // is a request made prior to an aspect ratio guard calculation.
 | 
			
		||||
        if (requestedSize_ == QSize(0, 0) || requestedSize_.width() != requestedSize_.height()) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // the first string is the item uri and the second is a uid
 | 
			
		||||
        // that is used for trigger a reload of the underlying image
 | 
			
		||||
        // data and can be discarded at this point
 | 
			
		||||
        auto idInfo = id.split("_");
 | 
			
		||||
        auto idInfo = id_.split("_");
 | 
			
		||||
 | 
			
		||||
        if (idInfo.size() < 2) {
 | 
			
		||||
            qWarning() << Q_FUNC_INFO << "Missing element(s) in the image url";
 | 
			
		||||
            return {};
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const auto& imageId = idInfo.at(1);
 | 
			
		||||
        if (!imageId.size()) {
 | 
			
		||||
            qWarning() << Q_FUNC_INFO << "Missing id in the image url";
 | 
			
		||||
            return {};
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        QImage image;
 | 
			
		||||
        const auto& type = idInfo.at(0);
 | 
			
		||||
 | 
			
		||||
        if (type == "conversation") {
 | 
			
		||||
            if (imageId == "temp")
 | 
			
		||||
                return Utils::tempConversationAvatar(requestedSize);
 | 
			
		||||
            return Utils::conversationAvatar(lrcInstance_, imageId, requestedSize);
 | 
			
		||||
                image = Utils::tempConversationAvatar(requestedSize_);
 | 
			
		||||
            else
 | 
			
		||||
                image = Utils::conversationAvatar(lrcInstance_, imageId, requestedSize_);
 | 
			
		||||
        } else if (type == "account") {
 | 
			
		||||
            image = Utils::accountPhoto(lrcInstance_, imageId, requestedSize_);
 | 
			
		||||
        } else if (type == "contact") {
 | 
			
		||||
            image = Utils::contactPhoto(lrcInstance_, imageId, requestedSize_);
 | 
			
		||||
        } else {
 | 
			
		||||
            qWarning() << Q_FUNC_INFO << "Missing valid prefix in the image url";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (type == "account")
 | 
			
		||||
            return Utils::accountPhoto(lrcInstance_, imageId, requestedSize);
 | 
			
		||||
        if (type == "contact")
 | 
			
		||||
            return Utils::contactPhoto(lrcInstance_, imageId, requestedSize);
 | 
			
		||||
 | 
			
		||||
        qWarning() << Q_FUNC_INFO << "Missing valid prefix in the image url";
 | 
			
		||||
        return {};
 | 
			
		||||
        Q_EMIT done(image);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class AvatarImageProvider : public AsyncImageProviderBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AvatarImageProvider(LRCInstance* instance = nullptr)
 | 
			
		||||
        : AsyncImageProviderBase(instance)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    QQuickImageResponse* requestImageResponse(const QString& id, const QSize& requestedSize) override
 | 
			
		||||
    {
 | 
			
		||||
        auto response = new AsyncImageResponse<AsyncAvatarImageResponseRunnable>(id,
 | 
			
		||||
                                                                                 requestedSize,
 | 
			
		||||
                                                                                 &pool_,
 | 
			
		||||
                                                                                 lrcInstance_);
 | 
			
		||||
        return response;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -33,8 +33,7 @@ AvatarRegistry::AvatarRegistry(LRCInstance* instance, QObject* parent)
 | 
			
		||||
    connect(&lrcInstance_->accountModel(),
 | 
			
		||||
            &AccountModel::profileUpdated,
 | 
			
		||||
            this,
 | 
			
		||||
            &AvatarRegistry::addOrUpdateImage,
 | 
			
		||||
            Qt::UniqueConnection);
 | 
			
		||||
            &AvatarRegistry::addOrUpdateImage);
 | 
			
		||||
 | 
			
		||||
    connect(lrcInstance_, &LRCInstance::base64SwarmAvatarChanged, this, [&] {
 | 
			
		||||
        addOrUpdateImage("temp");
 | 
			
		||||
 | 
			
		||||
@ -43,7 +43,7 @@ public:
 | 
			
		||||
    Q_INVOKABLE QString getUid(const QString& id);
 | 
			
		||||
 | 
			
		||||
    // add or update a specific image in the cache
 | 
			
		||||
    QString addOrUpdateImage(const QString& id);
 | 
			
		||||
    Q_SLOT QString addOrUpdateImage(const QString& id);
 | 
			
		||||
 | 
			
		||||
Q_SIGNALS:
 | 
			
		||||
    void avatarUidChanged(const QString& id);
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,9 @@
 | 
			
		||||
#include "bannedlistmodel.h"
 | 
			
		||||
 | 
			
		||||
#include "lrcinstance.h"
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#include <api/contact.h>
 | 
			
		||||
 | 
			
		||||
BannedListModel::BannedListModel(QObject* parent)
 | 
			
		||||
    : AbstractListModelBase(parent)
 | 
			
		||||
@ -106,7 +109,13 @@ void
 | 
			
		||||
BannedListModel::reset()
 | 
			
		||||
{
 | 
			
		||||
    beginResetModel();
 | 
			
		||||
    bannedlist_ = lrcInstance_->getCurrentAccountInfo().contactModel->getBannedContacts();
 | 
			
		||||
    auto contactModel = lrcInstance_->getCurrentContactModel();
 | 
			
		||||
    if (!contactModel) {
 | 
			
		||||
        C_DBG << "Contact model is not available.";
 | 
			
		||||
        bannedlist_.clear();
 | 
			
		||||
    } else {
 | 
			
		||||
        bannedlist_ = contactModel->getBannedContacts();
 | 
			
		||||
    }
 | 
			
		||||
    endResetModel();
 | 
			
		||||
    set_count(rowCount());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -354,10 +354,11 @@ CallAdapter::onCallInfosChanged(const QString& accountId, const QString& callId)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
CallAdapter::onCallAddedToConference(const QString& callId, const QString& confId)
 | 
			
		||||
CallAdapter::onCallAddedToConference(const QString& callId, const QString& conversationId, const QString& confId)
 | 
			
		||||
{
 | 
			
		||||
    Q_UNUSED(callId)
 | 
			
		||||
    Q_UNUSED(confId)
 | 
			
		||||
    Q_UNUSED(conversationId)
 | 
			
		||||
    saveConferenceSubcalls();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -389,16 +390,13 @@ CallAdapter::hangUpACall(const QString& accountId, const QString& convUid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
CallAdapter::setCallMedia(const QString& accountId, const QString& convUid, bool video)
 | 
			
		||||
CallAdapter::setCallMedia(const QString& accountId, const QString& convUid, bool videoMuted)
 | 
			
		||||
{
 | 
			
		||||
    const auto& convInfo = lrcInstance_->getConversationFromConvUid(convUid, accountId);
 | 
			
		||||
    if (convInfo.uid.isEmpty())
 | 
			
		||||
        return;
 | 
			
		||||
    try {
 | 
			
		||||
        lrcInstance_->getAccountInfo(accountId).callModel->updateCallMediaList(convInfo.callId,
 | 
			
		||||
                                                                               video);
 | 
			
		||||
    } catch (...) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lrcInstance_->getAccountInfo(accountId).callModel->setVideoMuted(convInfo.callId, videoMuted);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@ public:
 | 
			
		||||
    Q_INVOKABLE void placeAudioOnlyCall();
 | 
			
		||||
    Q_INVOKABLE void placeCall();
 | 
			
		||||
    Q_INVOKABLE void hangUpACall(const QString& accountId, const QString& convUid);
 | 
			
		||||
    Q_INVOKABLE void setCallMedia(const QString& accountId, const QString& convUid, bool video);
 | 
			
		||||
    Q_INVOKABLE void setCallMedia(const QString& accountId, const QString& convUid, bool videoMuted);
 | 
			
		||||
    Q_INVOKABLE void acceptACall(const QString& accountId, const QString& convUid);
 | 
			
		||||
 | 
			
		||||
    Q_INVOKABLE void connectCallModel(const QString& accountId);
 | 
			
		||||
@ -122,7 +122,7 @@ public Q_SLOTS:
 | 
			
		||||
    void onAccountChanged();
 | 
			
		||||
    void onCallStatusChanged(const QString& accountId, const QString& callId);
 | 
			
		||||
    void onCallStatusChanged(const QString& callId, int code);
 | 
			
		||||
    void onCallAddedToConference(const QString& callId, const QString& confId);
 | 
			
		||||
    void onCallAddedToConference(const QString& callId, const QString& conversationId, const QString& confId);
 | 
			
		||||
    void onCallStarted(const QString& callId);
 | 
			
		||||
    void onCallEnded(const QString& callId);
 | 
			
		||||
    void onCallInfosChanged(const QString& accountId, const QString& callId);
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,8 @@
 | 
			
		||||
 | 
			
		||||
#include "calloverlaymodel.h"
 | 
			
		||||
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#include <QEvent>
 | 
			
		||||
#include <QMouseEvent>
 | 
			
		||||
#include <QQuickWindow>
 | 
			
		||||
@ -360,23 +362,33 @@ CallOverlayModel::clearControls()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
CallOverlayModel::registerFilter(QQuickWindow* object, QQuickItem* item)
 | 
			
		||||
CallOverlayModel::setEventFilterActive(QObject* object, QQuickItem* item, bool isActive)
 | 
			
		||||
{
 | 
			
		||||
    if (!object || !item || watchedItems_.contains(item))
 | 
			
		||||
    QQuickWindow* window = qobject_cast<QQuickWindow*>(object);
 | 
			
		||||
    if (!window || !item) {
 | 
			
		||||
        C_WARN << "Attempting to" << (isActive ? "register" : "unregister")
 | 
			
		||||
               << "an invalid object or item" << window << item;
 | 
			
		||||
        return;
 | 
			
		||||
    watchedItems_.push_back(item);
 | 
			
		||||
    if (watchedItems_.size() == 1)
 | 
			
		||||
        object->installEventFilter(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
CallOverlayModel::unregisterFilter(QQuickWindow* object, QQuickItem* item)
 | 
			
		||||
{
 | 
			
		||||
    if (!object || !item || !watchedItems_.contains(item))
 | 
			
		||||
        return;
 | 
			
		||||
    watchedItems_.removeOne(item);
 | 
			
		||||
    if (watchedItems_.size() == 0)
 | 
			
		||||
        object->removeEventFilter(this);
 | 
			
		||||
    }
 | 
			
		||||
    if (isActive) {
 | 
			
		||||
        if (watchedItems_.contains(item)) {
 | 
			
		||||
            C_DBG << "Item already registered" << item;
 | 
			
		||||
        } else {
 | 
			
		||||
            watchedItems_.push_back(item);
 | 
			
		||||
            if (watchedItems_.size() == 1) {
 | 
			
		||||
                window->installEventFilter(this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (!watchedItems_.contains(item)) {
 | 
			
		||||
            C_DBG << "Item not registered" << item;
 | 
			
		||||
        } else {
 | 
			
		||||
            watchedItems_.removeOne(item);
 | 
			
		||||
            if (watchedItems_.size() == 0) {
 | 
			
		||||
                window->removeEventFilter(this);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
 | 
			
		||||
@ -137,8 +137,7 @@ public:
 | 
			
		||||
    Q_INVOKABLE QVariant overflowHiddenModel();
 | 
			
		||||
    Q_INVOKABLE QVariant pendingConferenceesModel();
 | 
			
		||||
 | 
			
		||||
    Q_INVOKABLE void registerFilter(QQuickWindow* object, QQuickItem* item);
 | 
			
		||||
    Q_INVOKABLE void unregisterFilter(QQuickWindow* object, QQuickItem* item);
 | 
			
		||||
    Q_INVOKABLE void setEventFilterActive(QObject* object, QQuickItem* item, bool isActive);
 | 
			
		||||
    bool eventFilter(QObject* object, QEvent* event) override;
 | 
			
		||||
 | 
			
		||||
Q_SIGNALS:
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@
 | 
			
		||||
import QtQuick
 | 
			
		||||
import QtQuick.Controls
 | 
			
		||||
import QtQuick.Layouts
 | 
			
		||||
import Qt5Compat.GraphicalEffects
 | 
			
		||||
import net.jami.Models 1.1
 | 
			
		||||
import net.jami.Adapters 1.1
 | 
			
		||||
import net.jami.Constants 1.1
 | 
			
		||||
@ -25,8 +26,10 @@ import net.jami.Constants 1.1
 | 
			
		||||
SBSMessageBase {
 | 
			
		||||
    id: root
 | 
			
		||||
 | 
			
		||||
    property var confId: ConfId
 | 
			
		||||
    property var currentCallId: CurrentCall.id
 | 
			
		||||
    component JoinCallButton: MaterialButton {
 | 
			
		||||
        visible: root.isActive
 | 
			
		||||
        visible: root.isActive && root.currentCallId !== root.confId
 | 
			
		||||
        toolTipText: JamiStrings.joinCall
 | 
			
		||||
        color: JamiTheme.blackColor
 | 
			
		||||
        background.opacity: hovered ? 0.2 : 0.1
 | 
			
		||||
@ -47,13 +50,15 @@ SBSMessageBase {
 | 
			
		||||
 | 
			
		||||
    bubble.border.color: CurrentConversation.color
 | 
			
		||||
    bubble.border.width: root.isActive ? 1.5 : 0
 | 
			
		||||
    bubble.color: JamiTheme.messageInBgColor
 | 
			
		||||
    bubble.opacity: 0.6
 | 
			
		||||
 | 
			
		||||
    Connections {
 | 
			
		||||
        target: CurrentConversation
 | 
			
		||||
        enabled: root.isActive
 | 
			
		||||
 | 
			
		||||
        function onActiveCallsChanged() {
 | 
			
		||||
            root.isActive = LRCInstance.indexOfActiveCall(ConfId, ActionUri, DeviceId) !== -1;
 | 
			
		||||
            root.isActive = LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1;
 | 
			
		||||
            if (root.isActive) {
 | 
			
		||||
                bubble.mask.border.color = CurrentConversation.color;
 | 
			
		||||
                bubble.mask.border.width = 1.5;
 | 
			
		||||
@ -62,10 +67,10 @@ SBSMessageBase {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    property bool isActive: LRCInstance.indexOfActiveCall(ConfId, ActionUri, DeviceId) !== -1
 | 
			
		||||
    visible: isActive || ConfId === "" || Duration > 0
 | 
			
		||||
    property bool isActive: LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1
 | 
			
		||||
    visible: isActive || root.confId === "" || Duration > 0
 | 
			
		||||
 | 
			
		||||
    property var baseColor: isOutgoing? CurrentConversation.color : JamiTheme.messageInBgColor
 | 
			
		||||
    property var baseColor: JamiTheme.messageInBgColor
 | 
			
		||||
 | 
			
		||||
    innerContent.children: [
 | 
			
		||||
        RowLayout {
 | 
			
		||||
@ -74,22 +79,60 @@ SBSMessageBase {
 | 
			
		||||
            spacing: 10
 | 
			
		||||
            visible: root.visible
 | 
			
		||||
 | 
			
		||||
            Label {
 | 
			
		||||
                id: callLabel
 | 
			
		||||
            Image {
 | 
			
		||||
                id: statusIcon
 | 
			
		||||
                Layout.leftMargin: 8
 | 
			
		||||
                width: 10
 | 
			
		||||
                height: 10
 | 
			
		||||
                verticalAlignment: Qt.AlignVCenter
 | 
			
		||||
                visible: !root.isActive
 | 
			
		||||
 | 
			
		||||
                source: {
 | 
			
		||||
                    if (root.isOutgoing) {
 | 
			
		||||
                        if (Duration > 0)
 | 
			
		||||
                            return "qrc:/icons/outgoing-call.svg";
 | 
			
		||||
                        else
 | 
			
		||||
                            return "qrc:/icons/missed-outgoing-call.svg";
 | 
			
		||||
                    } else {
 | 
			
		||||
                        if (Duration > 0)
 | 
			
		||||
                            return "qrc:/icons/incoming-call.svg";
 | 
			
		||||
                        else
 | 
			
		||||
                            return "qrc:/icons/missed-incoming-call.svg";
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                layer {
 | 
			
		||||
                    enabled: true
 | 
			
		||||
                    effect: ColorOverlay {
 | 
			
		||||
                        color: {
 | 
			
		||||
                            if (Duration > 0)
 | 
			
		||||
                                return UtilsAdapter.luma(root.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
 | 
			
		||||
                            return JamiTheme.redColor
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            TextEdit {
 | 
			
		||||
                id: callLabel
 | 
			
		||||
                objectName: "callLabel"
 | 
			
		||||
 | 
			
		||||
                topPadding: 8
 | 
			
		||||
                bottomPadding: 8
 | 
			
		||||
 | 
			
		||||
                Layout.margins: 8
 | 
			
		||||
                Layout.fillWidth: true
 | 
			
		||||
                Layout.rightMargin: root.isActive ? 0 : root.timeWidth + 16
 | 
			
		||||
                Layout.leftMargin: root.isActive ? 10 : 8
 | 
			
		||||
                Layout.rightMargin: root.isActive && root.currentCallId !== root.confId ? 0 : root.timeWidth + 16
 | 
			
		||||
                Layout.leftMargin: root.isActive ? 10 : -5 /* spacing is 10 and we want 5px with icon */
 | 
			
		||||
 | 
			
		||||
                text: {
 | 
			
		||||
                    if (root.isActive)
 | 
			
		||||
                        return JamiStrings.startedACall;
 | 
			
		||||
                    return Body;
 | 
			
		||||
                }
 | 
			
		||||
                verticalAlignment: Qt.AlignVCenter
 | 
			
		||||
                horizontalAlignment: Qt.AlignHCenter
 | 
			
		||||
 | 
			
		||||
                font.pointSize: JamiTheme.mediumFontSize
 | 
			
		||||
                font.pointSize: JamiTheme.smallFontSize
 | 
			
		||||
                font.hintingPreference: Font.PreferNoHinting
 | 
			
		||||
                renderType: Text.NativeRendering
 | 
			
		||||
                textFormat: Text.MarkdownText
 | 
			
		||||
@ -98,21 +141,23 @@ SBSMessageBase {
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            JoinCallButton {
 | 
			
		||||
                id: joinCallInAudio
 | 
			
		||||
                id: joinCallWithAudio
 | 
			
		||||
                objectName: "joinCallWithAudio"
 | 
			
		||||
                Layout.topMargin: 4
 | 
			
		||||
                Layout.bottomMargin: 4
 | 
			
		||||
 | 
			
		||||
                text: JamiStrings.joinInAudio
 | 
			
		||||
                onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, ConfId, true)
 | 
			
		||||
                text: JamiStrings.joinWithAudio
 | 
			
		||||
                onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId, true)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            JoinCallButton {
 | 
			
		||||
                id: joinCallInVideo
 | 
			
		||||
                text: JamiStrings.joinInVideo
 | 
			
		||||
                id: joinCallWithVideo
 | 
			
		||||
                objectName: "joinCallWithVideo"
 | 
			
		||||
                text: JamiStrings.joinWithVideo
 | 
			
		||||
                Layout.topMargin: 4
 | 
			
		||||
                Layout.bottomMargin: 4
 | 
			
		||||
 | 
			
		||||
                onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, ConfId)
 | 
			
		||||
                onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId)
 | 
			
		||||
                Layout.rightMargin: 4
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -125,7 +170,7 @@ SBSMessageBase {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    Component.onCompleted: {
 | 
			
		||||
        bubble.timestampItem.visible = !root.isActive;
 | 
			
		||||
        bubble.timestampItem.visible = !root.isActive || root.currentCallId === root.confId;
 | 
			
		||||
        opacity = 1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -40,23 +40,81 @@ Loader {
 | 
			
		||||
    property int seq: MsgSeq.single
 | 
			
		||||
    property string author: Author
 | 
			
		||||
    property string body: Body
 | 
			
		||||
    property var transferStatus: Status
 | 
			
		||||
    property var tid: TID
 | 
			
		||||
    property int transferStatus: TransferStatus
 | 
			
		||||
    onTidChanged: {
 | 
			
		||||
        if (tid === "") {
 | 
			
		||||
            sourceComponent = deletedMsgComp
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    onTransferStatusChanged: {
 | 
			
		||||
        if (tid === "") {
 | 
			
		||||
            sourceComponent = deletedMsgComp
 | 
			
		||||
            return;
 | 
			
		||||
        } else if (transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED) {
 | 
			
		||||
            mediaInfo = MessagesAdapter.getMediaInfo(root.body);
 | 
			
		||||
            if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE) {
 | 
			
		||||
                sourceComponent = localMediaMsgComp;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        sourceComponent = dataTransferMsgComp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    width: ListView.view ? ListView.view.width : 0
 | 
			
		||||
 | 
			
		||||
    sourceComponent: {
 | 
			
		||||
        if (root.transferStatus === Interaction.Status.TRANSFER_FINISHED) {
 | 
			
		||||
            mediaInfo = MessagesAdapter.getMediaInfo(root.body)
 | 
			
		||||
            if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE)
 | 
			
		||||
                return localMediaMsgComp
 | 
			
		||||
        }
 | 
			
		||||
        return dataTransferMsgComp
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opacity: 0
 | 
			
		||||
    Behavior on opacity { NumberAnimation { duration: 100 } }
 | 
			
		||||
    onLoaded: opacity = 1
 | 
			
		||||
 | 
			
		||||
    Component {
 | 
			
		||||
        id: deletedMsgComp
 | 
			
		||||
 | 
			
		||||
        SBSMessageBase {
 | 
			
		||||
            id: deletedItem
 | 
			
		||||
 | 
			
		||||
            isOutgoing: Author === CurrentAccount.uri
 | 
			
		||||
            showTime: root.showTime
 | 
			
		||||
            seq: root.seq
 | 
			
		||||
            author: Author
 | 
			
		||||
            readers: Readers
 | 
			
		||||
            timestamp: root.timestamp
 | 
			
		||||
            formattedTime: root.formattedTime
 | 
			
		||||
            formattedDay: root.formattedTime
 | 
			
		||||
            extraHeight: 0
 | 
			
		||||
            textContentWidth: textEditId.width
 | 
			
		||||
            textContentHeight: textEditId.height
 | 
			
		||||
            innerContent.children: [
 | 
			
		||||
                TextEdit {
 | 
			
		||||
                    id: textEditId
 | 
			
		||||
 | 
			
		||||
                    anchors.right: isOutgoing ? parent.right : undefined
 | 
			
		||||
                    anchors.rightMargin: isOutgoing ? timeWidth : 0
 | 
			
		||||
                    bottomPadding: 6
 | 
			
		||||
                    topPadding: 6
 | 
			
		||||
                    leftPadding: 10
 | 
			
		||||
                    text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMedia ;
 | 
			
		||||
                    horizontalAlignment: Text.AlignLeft
 | 
			
		||||
                    width:  Math.min((2 / 3) * parent.width, implicitWidth + 18, innerContent.width - senderMargin + 18)
 | 
			
		||||
 | 
			
		||||
                    font.pointSize: JamiTheme.smallFontSize
 | 
			
		||||
                    font.hintingPreference: Font.PreferNoHinting
 | 
			
		||||
                    renderType: Text.NativeRendering
 | 
			
		||||
                    textFormat: Text.RichText
 | 
			
		||||
                    clip: true
 | 
			
		||||
                    readOnly: true
 | 
			
		||||
                    color: getBaseColor()
 | 
			
		||||
                    opacity: 0.5
 | 
			
		||||
 | 
			
		||||
                    function getBaseColor() {
 | 
			
		||||
                        bubble.isDeleted = true
 | 
			
		||||
                        return UtilsAdapter.luma(bubble.color) ? "white" : "dark"
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component {
 | 
			
		||||
        id: dataTransferMsgComp
 | 
			
		||||
 | 
			
		||||
@ -65,7 +123,7 @@ Loader {
 | 
			
		||||
 | 
			
		||||
            transferId: Id
 | 
			
		||||
            property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
 | 
			
		||||
            property bool canOpen: root.transferStatus === Interaction.Status.TRANSFER_FINISHED || isOutgoing
 | 
			
		||||
            property bool canOpen: root.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
 | 
			
		||||
            property real maxMsgWidth: root.width - senderMargin -
 | 
			
		||||
                                       2 * hPadding - avatarBlockWidth
 | 
			
		||||
                                       - buttonsLoader.width - 24 - 6 - 24
 | 
			
		||||
@ -111,18 +169,18 @@ Loader {
 | 
			
		||||
 | 
			
		||||
                        sourceComponent: {
 | 
			
		||||
                            switch (root.transferStatus) {
 | 
			
		||||
                            case Interaction.Status.TRANSFER_CREATED:
 | 
			
		||||
                            case Interaction.Status.TRANSFER_FINISHED:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_CREATED:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_FINISHED:
 | 
			
		||||
                                iconSource = JamiResources.link_black_24dp_svg
 | 
			
		||||
                                return terminatedComp
 | 
			
		||||
                            case Interaction.Status.TRANSFER_CANCELED:
 | 
			
		||||
                            case Interaction.Status.TRANSFER_ERROR:
 | 
			
		||||
                            case Interaction.Status.TRANSFER_UNJOINABLE_PEER:
 | 
			
		||||
                            case Interaction.Status.TRANSFER_TIMEOUT_EXPIRED:
 | 
			
		||||
                            case Interaction.Status.TRANSFER_AWAITING_HOST:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_CANCELED:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_ERROR:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_UNJOINABLE_PEER:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_TIMEOUT_EXPIRED:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_AWAITING_HOST:
 | 
			
		||||
                                iconSource = JamiResources.download_black_24dp_svg
 | 
			
		||||
                                return optionsComp
 | 
			
		||||
                            case Interaction.Status.TRANSFER_ONGOING:
 | 
			
		||||
                            case Interaction.TransferStatus.TRANSFER_ONGOING:
 | 
			
		||||
                                iconSource = JamiResources.close_black_24dp_svg
 | 
			
		||||
                                return optionsComp
 | 
			
		||||
                            default:
 | 
			
		||||
@ -157,7 +215,7 @@ Loader {
 | 
			
		||||
                                normalColor: JamiTheme.chatviewBgColor
 | 
			
		||||
                                imageColor: JamiTheme.chatviewButtonColor
 | 
			
		||||
                                onClicked: {
 | 
			
		||||
                                    if (root.transferStatus === Interaction.Status.TRANSFER_ONGOING) {
 | 
			
		||||
                                    if (root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
 | 
			
		||||
                                        return MessagesAdapter.cancelFile(transferId)
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        return MessagesAdapter.acceptFile(transferId)
 | 
			
		||||
@ -190,7 +248,7 @@ Loader {
 | 
			
		||||
                                onClicked: function (mouse) {
 | 
			
		||||
                                    if (canOpen) {
 | 
			
		||||
                                        dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location)
 | 
			
		||||
                                        Qt.openUrlExternally(new Url(dataTransferItem.hoveredLink))
 | 
			
		||||
                                        Qt.openUrlExternally(new URL(dataTransferItem.hoveredLink))
 | 
			
		||||
                                    } else {
 | 
			
		||||
                                        dataTransferItem.hoveredLink = ""
 | 
			
		||||
                                    }
 | 
			
		||||
@ -222,11 +280,11 @@ Loader {
 | 
			
		||||
                                   : JamiTheme.chatviewTextColorDark
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                ,ProgressBar {
 | 
			
		||||
                },
 | 
			
		||||
                ProgressBar {
 | 
			
		||||
                    id: progressBar
 | 
			
		||||
 | 
			
		||||
                    visible: root.transferStatus === Interaction.Status.TRANSFER_ONGOING
 | 
			
		||||
                    visible: root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
 | 
			
		||||
                    height: visible * implicitHeight
 | 
			
		||||
                    value: transferStats.progress / transferStats.totalSize
 | 
			
		||||
                    width: transferItem.width
 | 
			
		||||
@ -294,8 +352,6 @@ Loader {
 | 
			
		||||
                        return avComp
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    Component {
 | 
			
		||||
                        id: avComp
 | 
			
		||||
 | 
			
		||||
@ -304,7 +360,7 @@ Loader {
 | 
			
		||||
                                var qml = WITH_WEBENGINE ?
 | 
			
		||||
                                            "qrc:/webengine/MediaPreviewBase.qml" :
 | 
			
		||||
                                            "qrc:/nowebengine/MediaPreviewBase.qml"
 | 
			
		||||
                                setSource( qml, { isVideo: mediaInfo.isVideo, html:mediaInfo.html } )
 | 
			
		||||
                                setSource( qml, { isVideo: mediaInfo.isVideo, html: mediaInfo.html } )
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@ -383,9 +439,11 @@ Loader {
 | 
			
		||||
                            antialiasing: true
 | 
			
		||||
                            autoTransform: true
 | 
			
		||||
                            asynchronous: true
 | 
			
		||||
                            source: Body !== undefined ? UtilsAdapter.urlFromLocalPath(Body) : ''
 | 
			
		||||
 | 
			
		||||
                            Component.onCompleted: localMediaMsgItem.bubble.imgSource = source
 | 
			
		||||
                            Component.onCompleted: {
 | 
			
		||||
                                source = UtilsAdapter.urlFromLocalPath(Body);
 | 
			
		||||
                                localMediaMsgItem.bubble.imgSource = source;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // The sourceSize represents the maximum source dimensions.
 | 
			
		||||
                            // This should not be a dynamic binding, as property changes
 | 
			
		||||
@ -401,7 +459,6 @@ Loader {
 | 
			
		||||
                                if (img.status == Image.Ready && aspectRatio) {
 | 
			
		||||
                                    height = Qt.binding(() => JamiQmlUtils.clamp(idealWidth / aspectRatio, 64, 256))
 | 
			
		||||
                                    width = Qt.binding(() => height * aspectRatio)
 | 
			
		||||
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -73,7 +73,7 @@ BaseModalDialog {
 | 
			
		||||
            Layout.bottomMargin: 5
 | 
			
		||||
 | 
			
		||||
            color: JamiTheme.textColor
 | 
			
		||||
            text: JamiStrings.confirmDeleteQuestion
 | 
			
		||||
            text: JamiStrings.confirmDeleteAccount
 | 
			
		||||
 | 
			
		||||
            font.pointSize: JamiTheme.textFontSize
 | 
			
		||||
            font.kerning: true
 | 
			
		||||
 | 
			
		||||
@ -121,10 +121,7 @@ Item {
 | 
			
		||||
                    font.pixelSize : text.length > 16 ? JamiTheme.jamiIdSmallFontSize : JamiTheme.bigFontSize
 | 
			
		||||
                    property string registeredName: CurrentAccount.registeredName
 | 
			
		||||
                    property string infohash: CurrentAccount.uri
 | 
			
		||||
                    text: registeredName ? registeredName : infohash
 | 
			
		||||
                    onRegisteredNameChanged: {
 | 
			
		||||
                        text = registeredName ? registeredName : infohash
 | 
			
		||||
                    }
 | 
			
		||||
                    text: (btnId.clicked && registeredName) ? registeredName : infohash
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -231,11 +228,9 @@ Item {
 | 
			
		||||
                    toolTipText: JamiStrings.identifierURI
 | 
			
		||||
                    onClicked: {
 | 
			
		||||
                        if (clicked) {
 | 
			
		||||
                            usernameLabel.text = Qt.binding(function() {return CurrentAccount.uri} );
 | 
			
		||||
                            usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.uri} );
 | 
			
		||||
                            btnId.toolTipText = JamiStrings.identifierRegisterName;
 | 
			
		||||
                        } else {
 | 
			
		||||
                            usernameLabel.text = Qt.binding(function() {return CurrentAccount.registeredName} );
 | 
			
		||||
                            usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.registeredName} );
 | 
			
		||||
                            btnId.toolTipText = JamiStrings.identifierURI;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
@ -1,83 +1,97 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2024 Savoir-faire Linux Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
import QtQuick
 | 
			
		||||
import QtQuick.Controls
 | 
			
		||||
import net.jami.Adapters 1.1
 | 
			
		||||
import net.jami.Constants 1.1
 | 
			
		||||
 | 
			
		||||
// A SplitView that supports dynamic RTL and splitView state saving.
 | 
			
		||||
SplitView {
 | 
			
		||||
    id: root
 | 
			
		||||
 | 
			
		||||
    property bool isRTL: UtilsAdapter.isRTL
 | 
			
		||||
    property bool isSinglePane: false
 | 
			
		||||
    property bool isSwapped: false
 | 
			
		||||
 | 
			
		||||
    onIsRTLChanged: {
 | 
			
		||||
        if (isRTL && isSinglePane && !isSwapped)
 | 
			
		||||
            return
 | 
			
		||||
        if ((isRTL && !isSwapped) || (!isRTL && isSwapped))
 | 
			
		||||
            swapItems()
 | 
			
		||||
    }
 | 
			
		||||
    onIsSinglePaneChanged: {
 | 
			
		||||
        if (isSwapped || isRTL)
 | 
			
		||||
            swapItems()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    property string splitViewStateKey: objectName
 | 
			
		||||
    property bool autoManageState: !(parent instanceof BaseView)
 | 
			
		||||
 | 
			
		||||
    function saveSplitViewState() {
 | 
			
		||||
        UtilsAdapter.setAppValue("sv_" + splitViewStateKey, root.saveState());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function restoreSplitViewState() {
 | 
			
		||||
        root.restoreState(UtilsAdapter.getAppValue("sv_" + splitViewStateKey));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onResizingChanged: if (!resizing)
 | 
			
		||||
        saveSplitViewState()
 | 
			
		||||
    onVisibleChanged: {
 | 
			
		||||
        if (!autoManageState)
 | 
			
		||||
            return;
 | 
			
		||||
        visible ? restoreSplitViewState() : saveSplitViewState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function swapItems() {
 | 
			
		||||
        isSwapped = !isSwapped
 | 
			
		||||
        var qqci = children[0];
 | 
			
		||||
        if (qqci.children.length > 1) {
 | 
			
		||||
            // swap the children
 | 
			
		||||
            var tempPane = qqci.children[0];
 | 
			
		||||
            qqci.children[0] = qqci.children[1];
 | 
			
		||||
            qqci.children.push(tempPane);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handle: Rectangle {
 | 
			
		||||
        visible: !isSinglePane
 | 
			
		||||
        implicitWidth: JamiTheme.splitViewHandlePreferredWidth
 | 
			
		||||
        implicitHeight: root.height
 | 
			
		||||
        color: JamiTheme.primaryBackgroundColor
 | 
			
		||||
        Rectangle {
 | 
			
		||||
            anchors.left: parent.left
 | 
			
		||||
            implicitWidth: 1
 | 
			
		||||
            implicitHeight: root.height
 | 
			
		||||
            color: JamiTheme.tabbarBorderColor
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2024 Savoir-faire Linux Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
import QtQuick
 | 
			
		||||
import QtQuick.Controls
 | 
			
		||||
import net.jami.Adapters 1.1
 | 
			
		||||
import net.jami.Constants 1.1
 | 
			
		||||
 | 
			
		||||
// A SplitView that supports dynamic RTL and splitView state saving.
 | 
			
		||||
SplitView {
 | 
			
		||||
    id: control
 | 
			
		||||
 | 
			
		||||
    property bool isRTL: UtilsAdapter.isRTL
 | 
			
		||||
    property bool isSinglePane: false
 | 
			
		||||
    property bool isSwapped: false
 | 
			
		||||
    property real handleSize: 1
 | 
			
		||||
 | 
			
		||||
    onIsRTLChanged: {
 | 
			
		||||
        if (isRTL && isSinglePane && !isSwapped)
 | 
			
		||||
            return
 | 
			
		||||
        if ((isRTL && !isSwapped) || (!isRTL && isSwapped))
 | 
			
		||||
            swapItems()
 | 
			
		||||
    }
 | 
			
		||||
    onIsSinglePaneChanged: {
 | 
			
		||||
        if (isSwapped || isRTL)
 | 
			
		||||
            swapItems()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    property string splitViewStateKey: objectName
 | 
			
		||||
    property bool autoManageState: !(parent instanceof BaseView)
 | 
			
		||||
 | 
			
		||||
    function saveSplitViewState() {
 | 
			
		||||
        UtilsAdapter.setAppValue("sv_" + splitViewStateKey, control.saveState());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function restoreSplitViewState() {
 | 
			
		||||
        control.restoreState(UtilsAdapter.getAppValue("sv_" + splitViewStateKey));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onResizingChanged: if (!resizing)
 | 
			
		||||
        saveSplitViewState()
 | 
			
		||||
    onVisibleChanged: {
 | 
			
		||||
        if (!autoManageState)
 | 
			
		||||
            return;
 | 
			
		||||
        visible ? restoreSplitViewState() : saveSplitViewState();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function swapItems() {
 | 
			
		||||
        isSwapped = !isSwapped
 | 
			
		||||
        var qqci = children[0];
 | 
			
		||||
        if (qqci.children.length > 1) {
 | 
			
		||||
            // swap the children
 | 
			
		||||
            var tempPane = qqci.children[0];
 | 
			
		||||
            qqci.children[0] = qqci.children[1];
 | 
			
		||||
            qqci.children.push(tempPane);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    handle: Rectangle {
 | 
			
		||||
        id: handleRoot
 | 
			
		||||
 | 
			
		||||
        readonly property int defaultSize: control.handleSize
 | 
			
		||||
 | 
			
		||||
        implicitWidth: control.orientation === Qt.Horizontal ? handleRoot.defaultSize : control.width
 | 
			
		||||
        implicitHeight: control.orientation === Qt.Horizontal ? control.height : handleRoot.defaultSize
 | 
			
		||||
 | 
			
		||||
        color: JamiTheme.tabbarBorderColor
 | 
			
		||||
 | 
			
		||||
        containmentMask: Item {
 | 
			
		||||
            // In the default configuration, the total handle size is the sum of the default size of the
 | 
			
		||||
            // handle and the extra handle size (4). If the layout is not right-to-left (RTL), the handle
 | 
			
		||||
            // is positioned at 0 on the X-axis, otherwise it's positioned to the left by the extra handle
 | 
			
		||||
            // size (4 pixels). This is done to make it easier to grab small scroll-view handles that are
 | 
			
		||||
            // adjacent to the SplitView handle. Note: vertically oriented handles are not offset.
 | 
			
		||||
            readonly property real extraHandleSize: 4
 | 
			
		||||
            readonly property real handleXPosition: !UtilsAdapter.isRTL ? 0 : -extraHandleSize
 | 
			
		||||
            readonly property real handleSize: handleRoot.defaultSize + extraHandleSize
 | 
			
		||||
 | 
			
		||||
            x: control.orientation === Qt.Horizontal ? handleXPosition : 0
 | 
			
		||||
            width: control.orientation === Qt.Horizontal ? handleSize : handleRoot.width
 | 
			
		||||
            height: control.orientation === Qt.Horizontal ? handleRoot.height : handleSize
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -23,19 +23,28 @@ import net.jami.Adapters 1.1
 | 
			
		||||
VideoView {
 | 
			
		||||
    id: root
 | 
			
		||||
 | 
			
		||||
    property bool visibilityCondition: true
 | 
			
		||||
 | 
			
		||||
    crop: true
 | 
			
		||||
    visible: isRendering && visibilityCondition
 | 
			
		||||
 | 
			
		||||
    Component.onDestruction: VideoDevices.stopDevice(rendererId);
 | 
			
		||||
 | 
			
		||||
    function startWithId(id, force = false) {
 | 
			
		||||
        if (id !== undefined && id.length === 0) {
 | 
			
		||||
            VideoDevices.stopDevice(rendererId);
 | 
			
		||||
            rendererId = id;
 | 
			
		||||
        } else {
 | 
			
		||||
            const forceRestart = rendererId === id;
 | 
			
		||||
            if (!forceRestart) {
 | 
			
		||||
                // Stop previous device
 | 
			
		||||
                VideoDevices.stopDevice(rendererId);
 | 
			
		||||
            }
 | 
			
		||||
            rendererId = VideoDevices.startDevice(id, forceRestart);
 | 
			
		||||
            stop();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const forceRestart = rendererId === id || force;
 | 
			
		||||
        if (!forceRestart) {
 | 
			
		||||
            // Stop previous device
 | 
			
		||||
            VideoDevices.stopDevice(rendererId);
 | 
			
		||||
        }
 | 
			
		||||
        rendererId = VideoDevices.startDevice(id, forceRestart);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    function stop() {
 | 
			
		||||
        VideoDevices.stopDevice(rendererId);
 | 
			
		||||
        rendererId = "";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -164,7 +164,7 @@ BaseModalDialog {
 | 
			
		||||
                                appWindow,
 | 
			
		||||
                                "commoncomponents/JamiFileDialog.qml",
 | 
			
		||||
                                {
 | 
			
		||||
                                    title: JamiStrings.selectAvatarImage,
 | 
			
		||||
                                    title: JamiStrings.selectProfilePicture,
 | 
			
		||||
                                    fileMode: JamiFileDialog.OpenFile,
 | 
			
		||||
                                    folder: StandardPaths.writableLocation(
 | 
			
		||||
                                                StandardPaths.PicturesLocation),
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,17 @@ Rectangle {
 | 
			
		||||
    property int status: Account.Status.REGISTERED
 | 
			
		||||
    property int size: 15
 | 
			
		||||
 | 
			
		||||
    MaterialToolTip {
 | 
			
		||||
        visible: text !== "" && hoverHandler.hovered
 | 
			
		||||
        delay: Qt.styleHints.mousePressAndHoldInterval
 | 
			
		||||
        text: status === 2 ? qsTr("Connected") : status === 1 ? qsTr("Available") : ""
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HoverHandler {
 | 
			
		||||
        id: hoverHandler
 | 
			
		||||
        target: parent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    width: size
 | 
			
		||||
    height: size
 | 
			
		||||
    radius: size * 0.5
 | 
			
		||||
@ -41,6 +52,10 @@ Rectangle {
 | 
			
		||||
            return JamiTheme.presenceGreen;
 | 
			
		||||
        else if (status === Account.Status.TRYING)
 | 
			
		||||
            return JamiTheme.unPresenceOrange;
 | 
			
		||||
        else if (status === 2)
 | 
			
		||||
            return JamiTheme.presenceGreen;
 | 
			
		||||
        else if (status === 1)
 | 
			
		||||
            return JamiTheme.unPresenceOrange;
 | 
			
		||||
        return JamiTheme.notificationRed;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -98,10 +98,18 @@ Control {
 | 
			
		||||
            Layout.fillHeight: true
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Label {
 | 
			
		||||
            id: username
 | 
			
		||||
            text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author)
 | 
			
		||||
 | 
			
		||||
            wrapMode: Text.NoWrap
 | 
			
		||||
            text: textMetricsUsername.elidedText
 | 
			
		||||
            TextMetrics {
 | 
			
		||||
                id: textMetricsUsername
 | 
			
		||||
 | 
			
		||||
                text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author)
 | 
			
		||||
                elideWidth: 200
 | 
			
		||||
                elide: Qt.ElideMiddle
 | 
			
		||||
            }
 | 
			
		||||
            visible: (seq === MsgSeq.first || seq === MsgSeq.single) && !isOutgoing && !isReply
 | 
			
		||||
 | 
			
		||||
            font.pointSize: JamiTheme.smallFontSize
 | 
			
		||||
@ -141,7 +149,15 @@ Control {
 | 
			
		||||
                    Label {
 | 
			
		||||
                        id: replyTo
 | 
			
		||||
 | 
			
		||||
                        text: isOutgoing ? JamiStrings.inReplyTo : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + JamiStrings.repliedTo
 | 
			
		||||
                        wrapMode: Text.NoWrap
 | 
			
		||||
                        text: textMetricsUsername1.elidedText
 | 
			
		||||
                        TextMetrics {
 | 
			
		||||
                            id: textMetricsUsername1
 | 
			
		||||
                            text: isOutgoing ? JamiStrings.inReplyTo : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + JamiStrings.repliedTo
 | 
			
		||||
                            elideWidth: 200
 | 
			
		||||
                            elide: Qt.ElideMiddle
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        color: JamiTheme.messageReplyColor
 | 
			
		||||
                        font.pointSize: JamiTheme.textFontSize
 | 
			
		||||
                        font.kerning: true
 | 
			
		||||
@ -166,7 +182,15 @@ Control {
 | 
			
		||||
                    Label {
 | 
			
		||||
                        id: replyToUserName
 | 
			
		||||
 | 
			
		||||
                        text: replyItem.isSelf ? JamiStrings.inReplyToMe : replyToLayout.replyUserName
 | 
			
		||||
                        wrapMode: Text.NoWrap
 | 
			
		||||
                        text: textMetricsUsername2.elidedText
 | 
			
		||||
                        TextMetrics {
 | 
			
		||||
                            id: textMetricsUsername2
 | 
			
		||||
                            text: replyItem.isSelf ? JamiStrings.inReplyToMe : replyToLayout.replyUserName
 | 
			
		||||
                            elideWidth: 200
 | 
			
		||||
                            elide: Qt.ElideMiddle
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        color: JamiTheme.messageReplyColor
 | 
			
		||||
                        font.pointSize: JamiTheme.textFontSize
 | 
			
		||||
                        font.kerning: true
 | 
			
		||||
@ -254,7 +278,7 @@ Control {
 | 
			
		||||
 | 
			
		||||
                    anchors.right: isOutgoing ? bubble.left : undefined
 | 
			
		||||
                    anchors.left: !isOutgoing ? bubble.right : undefined
 | 
			
		||||
                    width: JamiTheme.emojiPushButtonSize * 2
 | 
			
		||||
                    width: JamiTheme.emojiPushButtonSize * 4
 | 
			
		||||
                    height: JamiTheme.emojiPushButtonSize
 | 
			
		||||
                    anchors.verticalCenter: bubble.verticalCenter
 | 
			
		||||
 | 
			
		||||
@ -275,27 +299,24 @@ Control {
 | 
			
		||||
                        anchors.verticalCenter: parent.verticalCenter
 | 
			
		||||
                        anchors.right: isOutgoing ? optionButtonItem.right : undefined
 | 
			
		||||
                        anchors.left: !isOutgoing ? optionButtonItem.left : undefined
 | 
			
		||||
                        visible: CurrentAccount.type !== Profile.Type.SIP
 | 
			
		||||
                                 && root.type !== Interaction.Type.CALL
 | 
			
		||||
                                 && Body !== ""
 | 
			
		||||
                                 && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered)
 | 
			
		||||
                        visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || share.hovered || bgHandler.hovered)
 | 
			
		||||
                        source: JamiResources.more_vert_24dp_svg
 | 
			
		||||
                        width: optionButtonItem.width / 2
 | 
			
		||||
                        width: optionButtonItem.width / 4
 | 
			
		||||
                        height: optionButtonItem.height
 | 
			
		||||
                        circled: false
 | 
			
		||||
                        property bool isOpen: false
 | 
			
		||||
                        property var obj: undefined
 | 
			
		||||
 | 
			
		||||
                        function bind() {
 | 
			
		||||
                        function setBindings() {
 | 
			
		||||
                            more.isOpen = false;
 | 
			
		||||
                            visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered));
 | 
			
		||||
                            visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || share.hovered || bgHandler.hovered));
 | 
			
		||||
                            imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
 | 
			
		||||
                            normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        onClicked: {
 | 
			
		||||
                            if (more.isOpen) {
 | 
			
		||||
                                more.bind();
 | 
			
		||||
                                more.setBindings();
 | 
			
		||||
                                obj.close();
 | 
			
		||||
                            } else {
 | 
			
		||||
                                var component = Qt.createComponent("qrc:/commoncomponents/ShowMoreMenu.qml");
 | 
			
		||||
@ -311,7 +332,7 @@ Control {
 | 
			
		||||
                                    });
 | 
			
		||||
                                obj.open();
 | 
			
		||||
                                more.isOpen = true;
 | 
			
		||||
                                visible = true;
 | 
			
		||||
                                visible = true; // the button stay visible as long the popup is open even if it's not hovered
 | 
			
		||||
                                imageColor = JamiTheme.chatViewFooterImgHoverColor;
 | 
			
		||||
                                normalColor = JamiTheme.hoveredButtonColor;
 | 
			
		||||
                            }
 | 
			
		||||
@ -327,22 +348,75 @@ Control {
 | 
			
		||||
                        normalColor: JamiTheme.primaryBackgroundColor
 | 
			
		||||
                        toolTipText: JamiStrings.reply
 | 
			
		||||
                        source: JamiResources.reply_black_24dp_svg
 | 
			
		||||
                        width: optionButtonItem.width / 2
 | 
			
		||||
                        width: optionButtonItem.width / 4
 | 
			
		||||
                        height: optionButtonItem.height
 | 
			
		||||
                        anchors.verticalCenter: parent.verticalCenter
 | 
			
		||||
                        anchors.rightMargin: 5
 | 
			
		||||
                        anchors.right: isOutgoing ? more.left : undefined
 | 
			
		||||
                        anchors.left: !isOutgoing ? more.right : undefined
 | 
			
		||||
                        visible: CurrentAccount.type !== Profile.Type.SIP
 | 
			
		||||
                                 && root.type !== Interaction.Type.CALL
 | 
			
		||||
                                 && Body !== ""
 | 
			
		||||
                                 && (bubbleArea.bubbleHovered || hovered || more.hovered || bgHandler.hovered)
 | 
			
		||||
                        visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || share.hovered || bgHandler.hovered)
 | 
			
		||||
 | 
			
		||||
                        onClicked: {
 | 
			
		||||
                            MessagesAdapter.editId = "";
 | 
			
		||||
                            MessagesAdapter.replyToId = Id;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    PushButton {
 | 
			
		||||
                        id: share
 | 
			
		||||
                        objectName: "share"
 | 
			
		||||
 | 
			
		||||
                        circled: false
 | 
			
		||||
                        imageColor: hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
 | 
			
		||||
                        normalColor: JamiTheme.primaryBackgroundColor
 | 
			
		||||
                        toolTipText: JamiStrings.share
 | 
			
		||||
                        source: JamiResources.share_black_24dp_svg
 | 
			
		||||
 | 
			
		||||
                        width: optionButtonItem.width / 4
 | 
			
		||||
                        height: optionButtonItem.height
 | 
			
		||||
                        anchors.verticalCenter: parent.verticalCenter
 | 
			
		||||
                        anchors.rightMargin: 5
 | 
			
		||||
                        anchors.right: isOutgoing ? reply.left : undefined
 | 
			
		||||
                        anchors.left: !isOutgoing ? reply.right : undefined
 | 
			
		||||
                        visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || more.hovered || bgHandler.hovered)
 | 
			
		||||
                        property bool isOpen: false
 | 
			
		||||
                        property var obj: undefined
 | 
			
		||||
 | 
			
		||||
                        function setBindings() { // when the popup is closed, setBindings is called to reset the icon's visual settings
 | 
			
		||||
                            share.isOpen = false;
 | 
			
		||||
                            visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || more.hovered || bgHandler.hovered));
 | 
			
		||||
                            imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
 | 
			
		||||
                            normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        onClicked: {
 | 
			
		||||
                            if (share.isOpen) {
 | 
			
		||||
                                share.setBindings();
 | 
			
		||||
                                obj.close();
 | 
			
		||||
                            } else {
 | 
			
		||||
                                if (root.type === 2 || root.type === 5) {
 | 
			
		||||
                                    // 2=TEXT and 5=DATA_TRANSFER (any kind of file) defined in interaction.h
 | 
			
		||||
                                    var component = Qt.createComponent("qrc:/commoncomponents/ShareMessageMenu.qml");
 | 
			
		||||
                                    obj = component.createObject(share, {
 | 
			
		||||
                                            "isOutgoing": isOutgoing,
 | 
			
		||||
                                            "msgId": Id,
 | 
			
		||||
                                            "msgBody": Body,
 | 
			
		||||
                                            "type": root.type,
 | 
			
		||||
                                            "transferName": TransferName,
 | 
			
		||||
                                            "msgBubble": bubble,
 | 
			
		||||
                                            "listView": listView,
 | 
			
		||||
                                            "author": UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author),
 | 
			
		||||
                                            "formattedTime": formattedTime
 | 
			
		||||
                                        });
 | 
			
		||||
                                    obj.open();
 | 
			
		||||
                                    share.isOpen = true;
 | 
			
		||||
                                    visible = true; // the PushButton stay visible as long the popup is open even if it's not hovered
 | 
			
		||||
                                    imageColor = JamiTheme.chatViewFooterImgHoverColor;
 | 
			
		||||
                                    normalColor = JamiTheme.hoveredButtonColor;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                MessageBubble {
 | 
			
		||||
@ -364,14 +438,14 @@ Control {
 | 
			
		||||
                    property bool bubbleHovered
 | 
			
		||||
                    property string imgSource
 | 
			
		||||
 | 
			
		||||
                    width: (root.type === Interaction.Type.TEXT ? root.textContentWidth + ( IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth): innerContent.childrenRect.width)
 | 
			
		||||
                    width: (root.type === Interaction.Type.TEXT || isDeleted ? root.textContentWidth + (IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth) : innerContent.childrenRect.width)
 | 
			
		||||
                    height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) + (root.bigMsg ? 15 : 0)
 | 
			
		||||
 | 
			
		||||
                    HoverHandler {
 | 
			
		||||
                        target: root
 | 
			
		||||
                        enabled: root.type === Interaction.Type.DATA_TRANSFER
 | 
			
		||||
                        onHoveredChanged: {
 | 
			
		||||
                            root.hoveredLink = enabled && hovered ? bubble.imgSource : ""
 | 
			
		||||
                            root.hoveredLink = enabled && hovered ? bubble.imgSource : "";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
@ -381,12 +455,12 @@ Control {
 | 
			
		||||
                        showTime: IsEmojiOnly && !(root.seq === MsgSeq.last || root.seq === MsgSeq.single) ? false : true
 | 
			
		||||
                        formattedTime: root.formattedTime
 | 
			
		||||
 | 
			
		||||
                        timeColor: IsEmojiOnly || root.timeUnderBubble? (JamiTheme.darkTheme ? "white" : "dark") : (UtilsAdapter.luma(bubble.color) ? "white" : "dark")
 | 
			
		||||
                        timeColor: IsEmojiOnly || root.timeUnderBubble ? (JamiTheme.darkTheme ? "white" : "dark") : (UtilsAdapter.luma(bubble.color) ? "white" : "dark")
 | 
			
		||||
                        timeLabel.opacity: 0.5
 | 
			
		||||
 | 
			
		||||
                        anchors.bottom: parent.bottom
 | 
			
		||||
                        anchors.right: IsEmojiOnly ? (isOutgoing ? parent.right : undefined) : parent.right
 | 
			
		||||
                        anchors.left: ((IsEmojiOnly|| root.timeUnderBubble) && !isOutgoing) ? parent.left : undefined
 | 
			
		||||
                        anchors.left: ((IsEmojiOnly || root.timeUnderBubble) && !isOutgoing) ? parent.left : undefined
 | 
			
		||||
                        anchors.leftMargin: (IsEmojiOnly && !isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0
 | 
			
		||||
                        anchors.rightMargin: IsEmojiOnly ? ((isOutgoing && emojiReactions.visible) ? bubble.timePosition : 0) : (root.timeUnderBubble ? 0 : 10)
 | 
			
		||||
                        timeLabel.Layout.bottomMargin: {
 | 
			
		||||
@ -396,6 +470,8 @@ Control {
 | 
			
		||||
                                return -20;
 | 
			
		||||
                            if (root.bigMsg || bubble.isDeleted)
 | 
			
		||||
                                return 5;
 | 
			
		||||
                            if (root.type === Interaction.Type.CALL)
 | 
			
		||||
                                return 8;
 | 
			
		||||
                            return 9;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
@ -404,9 +480,9 @@ Control {
 | 
			
		||||
                        id: editedRow
 | 
			
		||||
                        anchors.left: root.bigMsg ? bubble.left : timestampItem.left
 | 
			
		||||
                        anchors.bottom: parent.bottom
 | 
			
		||||
                        anchors.bottomMargin: root.bigMsg || bubble.isDeleted ? 6 : 10
 | 
			
		||||
                        anchors.leftMargin: root.bigMsg ? 10 : - timestampItem.width - 16
 | 
			
		||||
                        visible: bubble.isEdited
 | 
			
		||||
                        anchors.bottomMargin: root.bigMsg ? 6 : 10
 | 
			
		||||
                        anchors.leftMargin: root.bigMsg ? 10 : -timestampItem.width - 16
 | 
			
		||||
                        visible: bubble.isEdited && !bubble.isDeleted
 | 
			
		||||
                        z: 1
 | 
			
		||||
                        ResponsiveImage {
 | 
			
		||||
                            id: editedImage
 | 
			
		||||
@ -446,6 +522,11 @@ Control {
 | 
			
		||||
                                MessagesAdapter.openUrl(root.hoveredLink);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        onDoubleClicked: {
 | 
			
		||||
                            MessagesAdapter.editId = "";
 | 
			
		||||
                            MessagesAdapter.replyToId = Id;
 | 
			
		||||
                        }
 | 
			
		||||
                        property bool bubbleHovered: containsMouse || textHovered
 | 
			
		||||
                        cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
 | 
			
		||||
                    }
 | 
			
		||||
@ -462,7 +543,7 @@ Control {
 | 
			
		||||
                    borderColor: root.getBaseColor()
 | 
			
		||||
                    maxWidth: 2 / 3 * maxMsgWidth - JamiTheme.emojiMargins
 | 
			
		||||
 | 
			
		||||
                    state: root.isOutgoing ? "anchorsRight" : (IsEmojiOnly ? "anchorsLeft" :(emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight"))
 | 
			
		||||
                    state: root.isOutgoing ? "anchorsRight" : (IsEmojiOnly ? "anchorsLeft" : (emojiReactions.width > bubble.width - JamiTheme.emojiMargins ? "anchorsLeft" : "anchorsRight"))
 | 
			
		||||
 | 
			
		||||
                    TapHandler {
 | 
			
		||||
                        onTapped: {
 | 
			
		||||
@ -570,7 +651,7 @@ Control {
 | 
			
		||||
                    radius: width / 2
 | 
			
		||||
                    width: 12
 | 
			
		||||
                    height: 12
 | 
			
		||||
                    border.color: JamiTheme.tintedBlue
 | 
			
		||||
                    border.color: JamiTheme.sending
 | 
			
		||||
                    border.width: 1
 | 
			
		||||
                    color: JamiTheme.transparentColor
 | 
			
		||||
                    visible: isOutgoing && Status === Interaction.Status.SENDING
 | 
			
		||||
@ -578,18 +659,27 @@ Control {
 | 
			
		||||
                    anchors.bottom: parent.bottom
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ResponsiveImage {
 | 
			
		||||
                    id: sent
 | 
			
		||||
 | 
			
		||||
                    containerHeight: 12
 | 
			
		||||
                    containerWidth: 12
 | 
			
		||||
 | 
			
		||||
                    width: 12
 | 
			
		||||
                    height: 12
 | 
			
		||||
 | 
			
		||||
                    visible: IsLastSent === true && root.readers.length === 0
 | 
			
		||||
                    anchors.bottom: parent.bottom
 | 
			
		||||
 | 
			
		||||
                    source: JamiResources.receive_svg
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ReadStatus {
 | 
			
		||||
                    id: readsOne
 | 
			
		||||
 | 
			
		||||
                    visible: root.readers.length === 1 && CurrentAccount.sendReadReceipt
 | 
			
		||||
 | 
			
		||||
                    width: {
 | 
			
		||||
                        if (root.readers.length === 0)
 | 
			
		||||
                            return 0;
 | 
			
		||||
                        var nbAvatars = root.readers.length;
 | 
			
		||||
                        var margin = JamiTheme.avatarReadReceiptSize / 3;
 | 
			
		||||
                        return nbAvatars * JamiTheme.avatarReadReceiptSize - (nbAvatars - 1) * margin;
 | 
			
		||||
                    }
 | 
			
		||||
                    width: JamiTheme.avatarReadReceiptSize
 | 
			
		||||
                    height: JamiTheme.avatarReadReceiptSize
 | 
			
		||||
 | 
			
		||||
                    anchors.bottom: parent.bottom
 | 
			
		||||
@ -613,14 +703,23 @@ Control {
 | 
			
		||||
 | 
			
		||||
            ReadStatus {
 | 
			
		||||
                id: readsMultiple
 | 
			
		||||
                visible: root.readers.length > 1 && CurrentAccount.sendReadReceipt
 | 
			
		||||
                visible: {
 | 
			
		||||
                    if (!readers)
 | 
			
		||||
                        return false;
 | 
			
		||||
                    return readers.length > 1 && CurrentAccount.sendReadReceipt;
 | 
			
		||||
                }
 | 
			
		||||
                width: {
 | 
			
		||||
                    if (root.readers.length === 0)
 | 
			
		||||
                    if (readers.length === 0)
 | 
			
		||||
                        return 0;
 | 
			
		||||
                    var nbAvatars = root.readers.length;
 | 
			
		||||
                    var nbAvatars = readers.length;
 | 
			
		||||
                    var margin = JamiTheme.avatarReadReceiptSize / 3;
 | 
			
		||||
                    return nbAvatars * JamiTheme.avatarReadReceiptSize - (nbAvatars - 1) * margin;
 | 
			
		||||
                }
 | 
			
		||||
                height: {
 | 
			
		||||
                    if (readers.length === 0)
 | 
			
		||||
                        return 0;
 | 
			
		||||
                    return JamiTheme.avatarReadReceiptSize;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                anchors.right: parent.right
 | 
			
		||||
                anchors.top: parent.top
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										264
									
								
								src/app/commoncomponents/ShareMessageMenu.qml
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,264 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2024 Savoir-faire Linux Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * 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 <https://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
import QtQuick
 | 
			
		||||
import QtQuick.Controls
 | 
			
		||||
import QtQuick.Layouts
 | 
			
		||||
import Qt5Compat.GraphicalEffects
 | 
			
		||||
import net.jami.Constants 1.1
 | 
			
		||||
import net.jami.Models 1.1
 | 
			
		||||
import net.jami.Adapters 1.1
 | 
			
		||||
import SortFilterProxyModel 0.2
 | 
			
		||||
import "contextmenu"
 | 
			
		||||
import "../commoncomponents"
 | 
			
		||||
import "../mainview/components"
 | 
			
		||||
 | 
			
		||||
BaseContextMenu {
 | 
			
		||||
    id: mainMenu
 | 
			
		||||
 | 
			
		||||
    height: 330 + Math.min(messageInput.height, textareaMaxHeight)
 | 
			
		||||
    width: 400
 | 
			
		||||
 | 
			
		||||
    required property string msgId
 | 
			
		||||
    required property string msgBody
 | 
			
		||||
    required property bool isOutgoing
 | 
			
		||||
    required property int type
 | 
			
		||||
    required property string transferName
 | 
			
		||||
    required property Item msgBubble
 | 
			
		||||
    required property ListView listView
 | 
			
		||||
    required property string author
 | 
			
		||||
    required property string formattedTime
 | 
			
		||||
 | 
			
		||||
    property var selectedUids: []
 | 
			
		||||
    property string shareToId: msgId
 | 
			
		||||
    property string fileLink: msgBody
 | 
			
		||||
    property int textareaMaxHeight: 350
 | 
			
		||||
    function xPosition(width) {
 | 
			
		||||
        // Use the width at function scope to retrigger property evaluation.
 | 
			
		||||
        const listViewWidth = listView.width;
 | 
			
		||||
        const parentX = parent.x;
 | 
			
		||||
        if (isOutgoing) {
 | 
			
		||||
            return parentX - width - 20;
 | 
			
		||||
        } else {
 | 
			
		||||
            return parentX + 20;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    x: xPosition(width)
 | 
			
		||||
    y: parent.y
 | 
			
		||||
 | 
			
		||||
    function xPositionProvider(width) {
 | 
			
		||||
        // Use the width at function scope to retrigger property evaluation.
 | 
			
		||||
        const listViewWidth = listView.width;
 | 
			
		||||
        if (isOutgoing) {
 | 
			
		||||
            return -5 - width;
 | 
			
		||||
        } else {
 | 
			
		||||
            const rightMargin = listViewWidth - (msgBubble.x + width);
 | 
			
		||||
            return width > rightMargin + 35 ? -5 - width : 35;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    function yPositionProvider(height) {
 | 
			
		||||
        const topOffset = msgBubble.mapToItem(listView, 0, 0).y;
 | 
			
		||||
        const listViewHeight = listView.height;
 | 
			
		||||
        const bottomMargin = listViewHeight - height - topOffset;
 | 
			
		||||
        if (bottomMargin < 0 || (topOffset < 0 && topOffset + height > 0)) {
 | 
			
		||||
            return 30 - height;
 | 
			
		||||
        } else {
 | 
			
		||||
            return 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SortFilterProxyModel {
 | 
			
		||||
        id: shareConvProxyModel
 | 
			
		||||
 | 
			
		||||
        sourceModel: ConversationsAdapter.convListProxyModel
 | 
			
		||||
        filterCaseSensitivity: Qt.CaseInsensitive
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle {
 | 
			
		||||
        id: header
 | 
			
		||||
 | 
			
		||||
        width: parent.width
 | 
			
		||||
        height: 0
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle {
 | 
			
		||||
        id: sendButton
 | 
			
		||||
 | 
			
		||||
        height: JamiTheme.chatViewFooterButtonSize
 | 
			
		||||
        anchors.right: parent.right
 | 
			
		||||
        anchors.rightMargin: 10
 | 
			
		||||
        anchors.topMargin: 10
 | 
			
		||||
        anchors.top: header.bottom
 | 
			
		||||
        color: JamiTheme.transparentColor
 | 
			
		||||
 | 
			
		||||
        PushButton {
 | 
			
		||||
            id: shareMessageButton
 | 
			
		||||
 | 
			
		||||
            height: JamiTheme.chatViewFooterButtonSize
 | 
			
		||||
            width: scale * JamiTheme.chatViewFooterButtonSize
 | 
			
		||||
            anchors.right: parent.right
 | 
			
		||||
 | 
			
		||||
            visible: true
 | 
			
		||||
 | 
			
		||||
            radius: JamiTheme.chatViewFooterButtonRadius
 | 
			
		||||
            preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
 | 
			
		||||
            imageContainerWidth: 25
 | 
			
		||||
            imageContainerHeight: 25
 | 
			
		||||
 | 
			
		||||
            toolTipText: JamiStrings.share
 | 
			
		||||
 | 
			
		||||
            mirror: UtilsAdapter.isRTL
 | 
			
		||||
 | 
			
		||||
            source: JamiResources.send_black_24dp_svg
 | 
			
		||||
 | 
			
		||||
            hoverEnabled: enabled
 | 
			
		||||
            normalColor: enabled ? JamiTheme.chatViewFooterSendButtonColor : JamiTheme.chatViewFooterSendButtonDisableColor
 | 
			
		||||
            imageColor: enabled ? JamiTheme.chatViewFooterSendButtonImgColor : JamiTheme.chatViewFooterSendButtonImgColorDisable
 | 
			
		||||
            hoveredColor: JamiTheme.buttonTintedBlueHovered
 | 
			
		||||
            pressedColor: hoveredColor
 | 
			
		||||
 | 
			
		||||
            opacity: 1
 | 
			
		||||
            scale: opacity
 | 
			
		||||
 | 
			
		||||
            MouseArea {
 | 
			
		||||
                anchors.fill: parent
 | 
			
		||||
 | 
			
		||||
                onClicked: {
 | 
			
		||||
                    var selectedContacts = mainMenu.selectedUids;
 | 
			
		||||
                    var hasText = messageInput.text && selectedContacts.length > 0;
 | 
			
		||||
                    function sendMessageOrFile(uid) {
 | 
			
		||||
                        if (Type === 2) {
 | 
			
		||||
                            // 2=TEXT and 5=DATA_TRANSFER (any kind of file) defined in interaction.h
 | 
			
		||||
                            MessagesAdapter.sendMessageToUid(msgBody, uid);
 | 
			
		||||
                        } else {
 | 
			
		||||
                            MessagesAdapter.sendFileToUid(fileLink, uid);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    for (var i = 0; i < selectedContacts.length; i++) {
 | 
			
		||||
                        var uid = selectedContacts[i];
 | 
			
		||||
                        sendMessageOrFile(uid);
 | 
			
		||||
                        if (hasText) {
 | 
			
		||||
                            MessagesAdapter.sendMessageToUid(messageInput.text, uid);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    messageInput.text = "";
 | 
			
		||||
                    mainMenu.destroy();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle {
 | 
			
		||||
        id: searchConv
 | 
			
		||||
 | 
			
		||||
        height: 300
 | 
			
		||||
        width: parent.width
 | 
			
		||||
        anchors.top: header.bottom
 | 
			
		||||
        anchors.topMargin: 10
 | 
			
		||||
 | 
			
		||||
        property int type: ContactList.CONVERSATION
 | 
			
		||||
 | 
			
		||||
        color: JamiTheme.transparentColor
 | 
			
		||||
        ColumnLayout {
 | 
			
		||||
            id: contactPickerPopupRectColumnLayout
 | 
			
		||||
 | 
			
		||||
            anchors.fill: parent
 | 
			
		||||
            Searchbar {
 | 
			
		||||
                id: contactPickerContactSearchBar
 | 
			
		||||
 | 
			
		||||
                width: parent.width - 20 - JamiTheme.chatViewFooterButtonSize
 | 
			
		||||
                anchors.leftMargin: 10
 | 
			
		||||
                Layout.preferredHeight: 35
 | 
			
		||||
                placeHolderText: "Share to..."
 | 
			
		||||
                onSearchBarTextChanged: function (text) {
 | 
			
		||||
                    shareConvProxyModel.filterRole = shareConvProxyModel.roleForName("Title");
 | 
			
		||||
                    shareConvProxyModel.filterPattern = text;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            JamiListView {
 | 
			
		||||
                id: contactPickerListView
 | 
			
		||||
 | 
			
		||||
                Layout.alignment: Qt.AlignCenter
 | 
			
		||||
                Layout.fillWidth: true
 | 
			
		||||
                Layout.preferredHeight: 255
 | 
			
		||||
                Layout.bottomMargin: JamiTheme.preferredMarginSize
 | 
			
		||||
                Layout.topMargin: 5
 | 
			
		||||
 | 
			
		||||
                model: shareConvProxyModel
 | 
			
		||||
 | 
			
		||||
                delegate: ConversationPickerItemDelegate {
 | 
			
		||||
                    id: conversationDelegate
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Flickable {
 | 
			
		||||
        id: messageInputContainer
 | 
			
		||||
 | 
			
		||||
        height: Math.min(contentHeight, mainMenu.textareaMaxHeight)
 | 
			
		||||
        width: parent.width - 20
 | 
			
		||||
        contentHeight: messageInput.height
 | 
			
		||||
        anchors.left: parent.left
 | 
			
		||||
        anchors.leftMargin: 10
 | 
			
		||||
        anchors.rightMargin: 10
 | 
			
		||||
        anchors.topMargin: 10
 | 
			
		||||
        anchors.top: searchConv.bottom
 | 
			
		||||
 | 
			
		||||
        flickableDirection: Flickable.VerticalFlick
 | 
			
		||||
        clip: true
 | 
			
		||||
 | 
			
		||||
        ScrollBar.vertical: JamiScrollBar {
 | 
			
		||||
            policy: ScrollBar.AsNeeded
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        onContentHeightChanged: {
 | 
			
		||||
            if (contentHeight > height) {
 | 
			
		||||
                contentY = contentHeight - height;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        TextArea {
 | 
			
		||||
            id: messageInput
 | 
			
		||||
 | 
			
		||||
            height: contentHeight + 12
 | 
			
		||||
            width: parent.width
 | 
			
		||||
            placeholderText: "Add a comment"
 | 
			
		||||
            placeholderTextColor: JamiTheme.messageBarPlaceholderTextColor
 | 
			
		||||
            font.pointSize: JamiTheme.textFontSize + 2
 | 
			
		||||
            color: JamiTheme.textColor
 | 
			
		||||
            wrapMode: Text.WordWrap
 | 
			
		||||
 | 
			
		||||
            background: Rectangle {
 | 
			
		||||
                color: JamiTheme.transparentColor
 | 
			
		||||
                radius: 5
 | 
			
		||||
                border.color: JamiTheme.chatViewFooterRectangleBorderColor
 | 
			
		||||
                border.width: 2
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // destroy() and setBindings() are needed to unselect the share icon from SBSMessageBase
 | 
			
		||||
 | 
			
		||||
    onAboutToHide: {
 | 
			
		||||
        mainMenu.destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component.onDestruction: {
 | 
			
		||||
        parent.setBindings();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -153,7 +153,7 @@ BaseContextMenu {
 | 
			
		||||
        GeneralMenuItem {
 | 
			
		||||
            id: removeLocally
 | 
			
		||||
 | 
			
		||||
            canTrigger: type === Interaction.Type.DATA_TRANSFER && Status === Interaction.Status.TRANSFER_FINISHED
 | 
			
		||||
            canTrigger: type === Interaction.Type.DATA_TRANSFER && TransferStatus === Interaction.TransferStatus.TRANSFER_FINISHED
 | 
			
		||||
            iconSource: JamiResources.trash_black_24dp_svg
 | 
			
		||||
            itemName: JamiStrings.removeLocally
 | 
			
		||||
            onClicked: {
 | 
			
		||||
@ -175,7 +175,7 @@ BaseContextMenu {
 | 
			
		||||
        GeneralMenuItem {
 | 
			
		||||
            id: deleteMessage
 | 
			
		||||
 | 
			
		||||
            canTrigger: root.isOutgoing && type === Interaction.Type.TEXT
 | 
			
		||||
            canTrigger: root.isOutgoing && (type === Interaction.Type.TEXT || type === Interaction.Type.DATA_TRANSFER)
 | 
			
		||||
            iconSource: JamiResources.delete_svg
 | 
			
		||||
            itemName: JamiStrings.deleteMessage
 | 
			
		||||
            onClicked: {
 | 
			
		||||
@ -198,11 +198,13 @@ BaseContextMenu {
 | 
			
		||||
        root.loadMenuItems(menuItems);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // destroy() and setBindings() are needed to unselect the share icon from SBSMessageBase
 | 
			
		||||
 | 
			
		||||
    onAboutToHide: {
 | 
			
		||||
        root.destroy();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component.onDestruction: {
 | 
			
		||||
        parent.bind();
 | 
			
		||||
        parent.setBindings();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -29,6 +29,10 @@ Item {
 | 
			
		||||
    property real invAspectRatio: (videoOutput.sourceRect.height / videoOutput.sourceRect.width) || 0.5625 // 16:9 default
 | 
			
		||||
    property bool crop: false
 | 
			
		||||
    property bool flip: false
 | 
			
		||||
    property real blurRadius: 0
 | 
			
		||||
 | 
			
		||||
    // We need to know if the frames are being rendered to the screen or not.
 | 
			
		||||
    readonly property bool isRendering: videoProvider.activeRenderers[rendererId] === true
 | 
			
		||||
 | 
			
		||||
    // This rect describes the actual rendered content rectangle
 | 
			
		||||
    // as the VideoOutput component may use PreserveAspectFit
 | 
			
		||||
@ -55,7 +59,7 @@ Item {
 | 
			
		||||
 | 
			
		||||
        antialiasing: true
 | 
			
		||||
        anchors.fill: parent
 | 
			
		||||
        opacity: videoProvider.activeRenderers[rendererId] === true
 | 
			
		||||
        opacity: isRendering
 | 
			
		||||
        visible: opacity
 | 
			
		||||
 | 
			
		||||
        fillMode: crop ? VideoOutput.PreserveAspectCrop : VideoOutput.PreserveAspectFit
 | 
			
		||||
@ -70,7 +74,7 @@ Item {
 | 
			
		||||
        layer.effect: FastBlur {
 | 
			
		||||
            source: videoOutput
 | 
			
		||||
            anchors.fill: root
 | 
			
		||||
            radius: (1. - opacity) * 100
 | 
			
		||||
            radius: blurRadius ? blurRadius : (1. - opacity) * 100
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        transform: Scale {
 | 
			
		||||
 | 
			
		||||
@ -16,6 +16,8 @@
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#ifndef _WIN32
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <gio/gio.h>
 | 
			
		||||
@ -171,10 +173,10 @@ static void
 | 
			
		||||
logConnectionInfo(NMActiveConnection* connection)
 | 
			
		||||
{
 | 
			
		||||
    if (connection) {
 | 
			
		||||
        qDebug() << "primary network connection:" << nm_active_connection_get_uuid(connection)
 | 
			
		||||
                 << "default: " << (nm_active_connection_get_default(connection) ? "yes" : "no");
 | 
			
		||||
        C_INFO << "primary network connection:" << nm_active_connection_get_uuid(connection)
 | 
			
		||||
               << "default: " << (nm_active_connection_get_default(connection) ? "yes" : "no");
 | 
			
		||||
    } else {
 | 
			
		||||
        qWarning() << "no primary network connection detected, check network settings";
 | 
			
		||||
        C_WARN << "no primary network connection detected, check network settings";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -191,11 +193,10 @@ nmClientCallback(G_GNUC_UNUSED GObject* source_object, GAsyncResult* result, Con
 | 
			
		||||
{
 | 
			
		||||
    GError* error = nullptr;
 | 
			
		||||
    if (auto nm_client = nm_client_new_finish(result, &error)) {
 | 
			
		||||
        qDebug() << "NetworkManager client initialized, version: "
 | 
			
		||||
                 << nm_client_get_version(nm_client)
 | 
			
		||||
                 << ", daemon running:" << (nm_client_get_nm_running(nm_client) ? "yes" : "no")
 | 
			
		||||
                 << ", networking enabled:"
 | 
			
		||||
                 << (nm_client_networking_get_enabled(nm_client) ? "yes" : "no");
 | 
			
		||||
        C_INFO << "NetworkManager client initialized, version: " << nm_client_get_version(nm_client)
 | 
			
		||||
               << ", daemon running:" << (nm_client_get_nm_running(nm_client) ? "yes" : "no")
 | 
			
		||||
               << ", networking enabled:"
 | 
			
		||||
               << (nm_client_networking_get_enabled(nm_client) ? "yes" : "no");
 | 
			
		||||
 | 
			
		||||
        auto connection = nm_client_get_primary_connection(nm_client);
 | 
			
		||||
        logConnectionInfo(connection);
 | 
			
		||||
@ -205,7 +206,7 @@ nmClientCallback(G_GNUC_UNUSED GObject* source_object, GAsyncResult* result, Con
 | 
			
		||||
                         cm);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        qWarning() << "error initializing NetworkManager client: " << error->message;
 | 
			
		||||
        C_WARN << "error initializing NetworkManager client: " << error->message;
 | 
			
		||||
        g_clear_error(&error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -222,7 +223,7 @@ ConnectivityMonitor::ConnectivityMonitor(QObject* parent)
 | 
			
		||||
 | 
			
		||||
ConnectivityMonitor::~ConnectivityMonitor()
 | 
			
		||||
{
 | 
			
		||||
    qDebug() << "Destroying connectivity monitor";
 | 
			
		||||
    C_DBG << "Destroying connectivity monitor";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
 | 
			
		||||
@ -81,7 +81,7 @@ ContactAdapter::getContactSelectableModel(int type)
 | 
			
		||||
    }
 | 
			
		||||
    case SmartListModel::Type::CONFERENCE:
 | 
			
		||||
        selectableProxyModel_->setPredicate([](const QModelIndex& index, const QRegularExpression&) {
 | 
			
		||||
            return index.data(Role::Presence).toBool();
 | 
			
		||||
            return index.data(Role::Presence).toInt();
 | 
			
		||||
        });
 | 
			
		||||
        break;
 | 
			
		||||
    case SmartListModel::Type::TRANSFER:
 | 
			
		||||
@ -259,7 +259,7 @@ ContactAdapter::connectSignals()
 | 
			
		||||
            &ContactAdapter::bannedStatusChanged,
 | 
			
		||||
            Qt::UniqueConnection);
 | 
			
		||||
    connect(lrcInstance_->getCurrentContactModel(),
 | 
			
		||||
            &ContactModel::modelUpdated,
 | 
			
		||||
            &ContactModel::contactAdded,
 | 
			
		||||
            this,
 | 
			
		||||
            &ContactAdapter::onModelUpdated,
 | 
			
		||||
            Qt::UniqueConnection);
 | 
			
		||||
 | 
			
		||||
@ -112,7 +112,8 @@ ConversationListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
 | 
			
		||||
    using namespace ConversationList;
 | 
			
		||||
    if (index.data(Role::Uris).toStringList().isEmpty()) {
 | 
			
		||||
        // TODO: Find out why, and fix in libjami/libjamiclient.
 | 
			
		||||
        qCritical() << "Filtering 0 member conversation. Fix me";
 | 
			
		||||
        qCritical() << "Filtering 0 member conversation. Fix me"
 | 
			
		||||
                    << index.data(Role::UID).toString();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -142,7 +143,7 @@ ConversationListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        Q_FOREACH (const auto& filter, toFilter)
 | 
			
		||||
            if (rx.match(filter).hasMatch()) {
 | 
			
		||||
            if (rx.isValid() && rx.match(filter).hasMatch()) {
 | 
			
		||||
                match = true;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,10 @@
 | 
			
		||||
 | 
			
		||||
#include "conversationlistmodelbase.h"
 | 
			
		||||
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#include <api/contact.h>
 | 
			
		||||
 | 
			
		||||
ConversationListModelBase::ConversationListModelBase(LRCInstance* instance, QObject* parent)
 | 
			
		||||
    : AbstractListModelBase(parent)
 | 
			
		||||
{
 | 
			
		||||
@ -121,7 +125,11 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
 | 
			
		||||
            if (interaction.type == interaction::Type::UPDATE_PROFILE) {
 | 
			
		||||
                lastInteractionBody = interaction::getProfileUpdatedString();
 | 
			
		||||
            } else if (interaction.type == interaction::Type::DATA_TRANSFER) {
 | 
			
		||||
                lastInteractionBody = interaction.commit.value("displayName");
 | 
			
		||||
                if (interaction.commit.value("tid").isEmpty()) {
 | 
			
		||||
                    lastInteractionBody = tr("Deleted media");
 | 
			
		||||
                } else {
 | 
			
		||||
                    lastInteractionBody = interaction.commit.value("displayName");
 | 
			
		||||
                }
 | 
			
		||||
            } else if (interaction.type == lrc::api::interaction::Type::CALL) {
 | 
			
		||||
                const auto isOutgoing = interaction.authorUri == accInfo.profileInfo.uri;
 | 
			
		||||
                lastInteractionBody = interaction::getCallInteractionString(isOutgoing, interaction);
 | 
			
		||||
@ -169,18 +177,19 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    case Role::Presence: {
 | 
			
		||||
        // The conversation can show a green dot if at least one peer is present
 | 
			
		||||
        // A conversation presence is the max of the members presence
 | 
			
		||||
        auto maxPresence = 0;
 | 
			
		||||
        Q_FOREACH (const auto& peerUri, model_->peersForConversation(item.uid))
 | 
			
		||||
            try {
 | 
			
		||||
                auto& accInfo = lrcInstance_->getAccountInfo(accountId_);
 | 
			
		||||
                if (peerUri == accInfo.profileInfo.uri)
 | 
			
		||||
                    return true; // Self account
 | 
			
		||||
                    return 2; // Self account
 | 
			
		||||
                auto contact = accInfo.contactModel->getContact(peerUri);
 | 
			
		||||
                if (contact.isPresent)
 | 
			
		||||
                    return true;
 | 
			
		||||
                if (contact.presence > maxPresence)
 | 
			
		||||
                    maxPresence = contact.presence;
 | 
			
		||||
            } catch (const std::exception&) {
 | 
			
		||||
            }
 | 
			
		||||
        return false;
 | 
			
		||||
        return maxPresence;
 | 
			
		||||
    };
 | 
			
		||||
    default:
 | 
			
		||||
        break;
 | 
			
		||||
@ -215,9 +224,9 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
 | 
			
		||||
        try {
 | 
			
		||||
            contact = contactModel->getContact(peerUri);
 | 
			
		||||
        } catch (const std::exception&) {
 | 
			
		||||
            qWarning() << Q_FUNC_INFO << "Can't find contact" << peerUri << " for account "
 | 
			
		||||
                       << lrcInstance_->accountModel().bestNameForAccount(accInfo.id)
 | 
			
		||||
                       << " - Conv: " << item.uid;
 | 
			
		||||
            C_WARN << "Can't find contact" << peerUri << "for account"
 | 
			
		||||
                   << lrcInstance_->accountModel().bestNameForAccount(accInfo.id)
 | 
			
		||||
                   << "- Conv:" << item.uid;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        switch (role) {
 | 
			
		||||
 | 
			
		||||
@ -23,8 +23,9 @@
 | 
			
		||||
#include "systemtray.h"
 | 
			
		||||
 | 
			
		||||
#ifdef Q_OS_LINUX
 | 
			
		||||
#include "namedirectory.h"
 | 
			
		||||
#include <namedirectory.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <api/contact.h>
 | 
			
		||||
 | 
			
		||||
#include <QApplication>
 | 
			
		||||
#include <QJsonObject>
 | 
			
		||||
@ -602,9 +603,11 @@ ConversationsAdapter::openDialogConversationWith(const QString& peerUri)
 | 
			
		||||
void
 | 
			
		||||
ConversationsAdapter::onCurrentAccountRemoved()
 | 
			
		||||
{
 | 
			
		||||
    // Unbind proxy model source models.
 | 
			
		||||
    convModel_->bindSourceModel(nullptr);
 | 
			
		||||
    searchModel_->bindSourceModel(nullptr);
 | 
			
		||||
    // Unbind proxy model source models if there is no current account
 | 
			
		||||
    if (lrcInstance_->get_currentAccountId().isEmpty()) {
 | 
			
		||||
        convModel_->bindSourceModel(nullptr);
 | 
			
		||||
        searchModel_->bindSourceModel(nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
 | 
			
		||||
@ -144,7 +144,9 @@ CurrentAccount::updateData()
 | 
			
		||||
        set_deviceId(accConfig.deviceId);
 | 
			
		||||
        set_peerDiscovery(accConfig.peerDiscovery, true);
 | 
			
		||||
        set_sendReadReceipt(accConfig.sendReadReceipt, true);
 | 
			
		||||
        set_sendComposing(accConfig.sendComposing, true);
 | 
			
		||||
        set_isRendezVous(accConfig.isRendezVous, true);
 | 
			
		||||
        set_dhtPort(accConfig.dhtPort, true);
 | 
			
		||||
        set_autoAnswer(accConfig.autoAnswer, true);
 | 
			
		||||
        set_proxyEnabled(accConfig.proxyEnabled, true);
 | 
			
		||||
        set_upnpEnabled(accConfig.upnpEnabled, true);
 | 
			
		||||
 | 
			
		||||
@ -116,8 +116,10 @@ class CurrentAccount final : public QObject
 | 
			
		||||
    QML_RO_PROPERTY(lrc::api::profile::Type, type)
 | 
			
		||||
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, keepAliveEnabled)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(int, dhtPort)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, peerDiscovery)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, sendReadReceipt)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, sendComposing)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, isRendezVous)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, autoAnswer)
 | 
			
		||||
    QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, proxyEnabled)
 | 
			
		||||
 | 
			
		||||
@ -18,6 +18,7 @@
 | 
			
		||||
#include "currentcall.h"
 | 
			
		||||
 | 
			
		||||
#include "callparticipantsmodel.h"
 | 
			
		||||
#include "global.h"
 | 
			
		||||
 | 
			
		||||
#include <api/callparticipantsmodel.h>
 | 
			
		||||
#include <api/devicemodel.h>
 | 
			
		||||
@ -223,43 +224,14 @@ CurrentCall::updateCallInfo()
 | 
			
		||||
    set_isGrid(callInfo.layout == call::Layout::GRID);
 | 
			
		||||
    set_isAudioOnly(callInfo.isAudioOnly);
 | 
			
		||||
 | 
			
		||||
    bool isAudioMuted {};
 | 
			
		||||
    bool isVideoMuted {};
 | 
			
		||||
    bool isSharing {};
 | 
			
		||||
    QString sharingSource {};
 | 
			
		||||
    bool isCapturing {};
 | 
			
		||||
    QString previewId {};
 | 
			
		||||
    using namespace libjami::Media;
 | 
			
		||||
    if (callInfo.status != lrc::api::call::Status::ENDED) {
 | 
			
		||||
        for (const auto& media : callInfo.mediaList) {
 | 
			
		||||
            if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_VIDEO) {
 | 
			
		||||
                if (media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::DISPLAY)
 | 
			
		||||
                    || media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::FILE)) {
 | 
			
		||||
                    isSharing = true;
 | 
			
		||||
                    sharingSource = media[MediaAttributeKey::SOURCE];
 | 
			
		||||
                }
 | 
			
		||||
                if (media[MediaAttributeKey::ENABLED] == TRUE_STR
 | 
			
		||||
                    && media[MediaAttributeKey::MUTED] == FALSE_STR && previewId.isEmpty()) {
 | 
			
		||||
                    previewId = media[libjami::Media::MediaAttributeKey::SOURCE];
 | 
			
		||||
                }
 | 
			
		||||
                if (media[libjami::Media::MediaAttributeKey::SOURCE].startsWith(
 | 
			
		||||
                        libjami::Media::VideoProtocolPrefix::CAMERA)) {
 | 
			
		||||
                    isVideoMuted |= media[MediaAttributeKey::MUTED] == TRUE_STR;
 | 
			
		||||
                    isCapturing = media[MediaAttributeKey::MUTED] == FALSE_STR;
 | 
			
		||||
                }
 | 
			
		||||
            } else if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_AUDIO) {
 | 
			
		||||
                if (media[MediaAttributeKey::LABEL] == "audio_0") {
 | 
			
		||||
                    isAudioMuted |= media[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    set_previewId(previewId);
 | 
			
		||||
    set_isAudioMuted(isAudioMuted);
 | 
			
		||||
    set_isVideoMuted(isVideoMuted);
 | 
			
		||||
    set_isSharing(isSharing);
 | 
			
		||||
    set_sharingSource(sharingSource);
 | 
			
		||||
    set_isCapturing(isCapturing);
 | 
			
		||||
    auto callInfoEx = callInfo.getCallInfoEx();
 | 
			
		||||
    set_previewId(callInfoEx["preview_id"].toString());
 | 
			
		||||
    set_isAudioMuted(callInfoEx["is_audio_muted"].toBool());
 | 
			
		||||
    set_isVideoMuted(callInfoEx["is_video_muted"].toBool());
 | 
			
		||||
    set_isSharing(callInfoEx["is_sharing"].toBool());
 | 
			
		||||
    set_sharingSource(isSharing_ ? callInfoEx["preview_id"].toString() : QString());
 | 
			
		||||
    set_isCapturing(callInfoEx["is_capturing"].toBool());
 | 
			
		||||
 | 
			
		||||
    set_isHandRaised(callModel->isHandRaised(id_));
 | 
			
		||||
    set_isModerator(callModel->isModerator(id_));
 | 
			
		||||
 | 
			
		||||
@ -377,7 +349,7 @@ CurrentCall::onCurrentAccountIdChanged()
 | 
			
		||||
        auto& accInfo = lrcInstance_->getCurrentAccountInfo();
 | 
			
		||||
        set_isSIP(accInfo.profileInfo.type == profile::Type::SIP);
 | 
			
		||||
    } catch (const std::exception& e) {
 | 
			
		||||
        qWarning() << "Can't update current call type" << e.what();
 | 
			
		||||
        C_DBG << "Can't update current call type" << e.what();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connectModel();
 | 
			
		||||
 | 
			
		||||