mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-10-30 07:53:33 +08:00
Compare commits
71 Commits
nightly/20
...
beta/20250
| Author | SHA1 | Date | |
|---|---|---|---|
| 82eb5c59a6 | |||
| 84a9ba4196 | |||
| 6dac4d2ee3 | |||
| 674bf38766 | |||
| 52f3a9bc28 | |||
| abce881b50 | |||
| 666b149033 | |||
| eb10ccbd4a | |||
| f513358236 | |||
| 3c00829afb | |||
| 84a59889e3 | |||
| 6c35561817 | |||
| 6ffdda7b81 | |||
| a51078c900 | |||
| 76a710e2ab | |||
| bc324aa8bb | |||
| 5c772960bc | |||
| da2acefced | |||
| 524c9b0ed4 | |||
| 8677349c4a | |||
| 905b2e858e | |||
| 6fc2e75a33 | |||
| c738caa3a4 | |||
| cb13d4f771 | |||
| 436e11a6a4 | |||
| 869aef8929 | |||
| e0f939318e | |||
| 136dea011f | |||
| af09269d81 | |||
| 5a5ef4711d | |||
| 1dd745d446 | |||
| 3dd2d26d86 | |||
| eb6b6a2b93 | |||
| b15d692a0e | |||
| e76bcbd555 | |||
| b5a979e6b1 | |||
| 898444dd3c | |||
| 99f246016d | |||
| e24f3d91e8 | |||
| 3a7850b398 | |||
| 1e1750024b | |||
| 2ba53a2e40 | |||
| ceec1f95b9 | |||
| 1ac3db4f33 | |||
| 93d3d18c7b | |||
| d4b7891f48 | |||
| d7c294edd0 | |||
| 945cfe176d | |||
| fa3a153896 | |||
| e9106b2bcc | |||
| a967518d45 | |||
| 7ebed53e97 | |||
| ca05963c40 | |||
| df98c6c3fd | |||
| 05501e33e9 | |||
| 91780ae400 | |||
| 4900ca9f1b | |||
| 0f965aae28 | |||
| f8c29fc4a1 | |||
| 2e1889caf1 | |||
| 8070d1bfc2 | |||
| 4ee1a309a1 | |||
| 0333016c44 | |||
| 32b7525ee3 | |||
| 32b941ab96 | |||
| e4932abd39 | |||
| 718d1d266d | |||
| 8d55f352b4 | |||
| 2a72da564e | |||
| 88d0539085 | |||
| 4b1c299a1d |
4
.gitmodules
vendored
4
.gitmodules
vendored
@ -31,3 +31,7 @@
|
||||
path = 3rdparty/zxing-cpp
|
||||
url = https://github.com/nu-book/zxing-cpp.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/hunspell"]
|
||||
path = 3rdparty/hunspell
|
||||
url = https://gitlab.savoirfairelinux.com/jami/hunspell.git
|
||||
ignore = dirty
|
||||
|
||||
1
3rdparty/hunspell
vendored
Submodule
1
3rdparty/hunspell
vendored
Submodule
Submodule 3rdparty/hunspell added at 749cd84a0b
105
CMakeLists.txt
105
CMakeLists.txt
@ -84,10 +84,8 @@ if(WIN32)
|
||||
if(BETA)
|
||||
message(STATUS "Beta config enabled")
|
||||
add_definitions(-DBETA)
|
||||
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Beta)
|
||||
else()
|
||||
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Release)
|
||||
endif()
|
||||
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
@ -246,7 +244,7 @@ set(CMAKE_MODULE_PATH
|
||||
${CMAKE_MODULE_PATH} "${EXTRAS_DIR}/build/cmake/modules")
|
||||
find_package(LibJami REQUIRED)
|
||||
if(LIBJAMI_FOUND)
|
||||
include_directories(${LIBJAMI_INCLUDE_DIRS})
|
||||
include_directories(${LIBJAMI_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
include(FindPython3)
|
||||
@ -255,7 +253,7 @@ 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
|
||||
# Touch the file to ensure it exists at configure time as
|
||||
# we add it to the target_sources below.
|
||||
file(TOUCH ${VERSION_FILE})
|
||||
add_custom_target(
|
||||
@ -266,6 +264,7 @@ add_custom_target(
|
||||
-DAPP_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||
-DCORE_SOURCE_DIR=${DAEMON_DIR}
|
||||
-DCPP_INT_FILE=${VERSION_INFO_DIR}/version_info.cpp.in
|
||||
-DBUILD_VERSION=${BUILD_VERSION}
|
||||
-P ${CMAKE_SCRIPTS_DIR}/generate_version_info.cmake
|
||||
)
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${VERSION_INFO_DIR})
|
||||
@ -347,6 +346,8 @@ set(COMMON_SOURCES
|
||||
${APP_SRC_DIR}/conversationlistmodel.cpp
|
||||
${APP_SRC_DIR}/searchresultslistmodel.cpp
|
||||
${APP_SRC_DIR}/calloverlaymodel.cpp
|
||||
${APP_SRC_DIR}/spellcheckdictionarylistmodel.cpp
|
||||
${APP_SRC_DIR}/spellcheckadapter.cpp
|
||||
${APP_SRC_DIR}/filestosendlistmodel.cpp
|
||||
${APP_SRC_DIR}/wizardviewstepmodel.cpp
|
||||
${APP_SRC_DIR}/avatarregistry.cpp
|
||||
@ -361,13 +362,13 @@ set(COMMON_SOURCES
|
||||
${APP_SRC_DIR}/currentcall.cpp
|
||||
${APP_SRC_DIR}/messageparser.cpp
|
||||
${APP_SRC_DIR}/previewengine.cpp
|
||||
${APP_SRC_DIR}/imagedownloader.cpp
|
||||
${APP_SRC_DIR}/filedownloader.cpp
|
||||
${APP_SRC_DIR}/pluginversionmanager.cpp
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.cpp
|
||||
${APP_SRC_DIR}/pluginversionmanager.cpp
|
||||
${APP_SRC_DIR}/linkdevicemodel.cpp
|
||||
${APP_SRC_DIR}/qrcodescannermodel.cpp
|
||||
)
|
||||
${APP_SRC_DIR}/spellchecker.cpp)
|
||||
|
||||
set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/global.h
|
||||
@ -377,7 +378,6 @@ set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/appversionmanager.h
|
||||
${APP_SRC_DIR}/utils.h
|
||||
${APP_SRC_DIR}/bannedlistmodel.h
|
||||
${APP_SRC_DIR}/version.h
|
||||
${APP_SRC_DIR}/accountlistmodel.h
|
||||
${APP_SRC_DIR}/instancemanager.h
|
||||
${APP_SRC_DIR}/connectivitymonitor.h
|
||||
@ -419,6 +419,8 @@ set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/conversationlistmodel.h
|
||||
${APP_SRC_DIR}/searchresultslistmodel.h
|
||||
${APP_SRC_DIR}/calloverlaymodel.h
|
||||
${APP_SRC_DIR}/spellcheckdictionarylistmodel.h
|
||||
${APP_SRC_DIR}/spellcheckadapter.h
|
||||
${APP_SRC_DIR}/filestosendlistmodel.h
|
||||
${APP_SRC_DIR}/wizardviewstepmodel.h
|
||||
${APP_SRC_DIR}/avatarregistry.h
|
||||
@ -433,7 +435,7 @@ set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/currentcall.h
|
||||
${APP_SRC_DIR}/messageparser.h
|
||||
${APP_SRC_DIR}/htmlparser.h
|
||||
${APP_SRC_DIR}/imagedownloader.h
|
||||
${APP_SRC_DIR}/filedownloader.h
|
||||
${APP_SRC_DIR}/pluginversionmanager.h
|
||||
${APP_SRC_DIR}/connectioninfolistmodel.h
|
||||
${APP_SRC_DIR}/pttlistener.h
|
||||
@ -441,7 +443,7 @@ set(COMMON_HEADERS
|
||||
${APP_SRC_DIR}/crashreporter.h
|
||||
${APP_SRC_DIR}/linkdevicemodel.h
|
||||
${APP_SRC_DIR}/qrcodescannermodel.h
|
||||
)
|
||||
${APP_SRC_DIR}/spellchecker.h)
|
||||
|
||||
# For libavutil/avframe.
|
||||
set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib")
|
||||
@ -469,6 +471,25 @@ if(ENABLE_CRASHREPORTS)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
# hunspell
|
||||
pkg_search_module(hunspell IMPORTED_TARGET hunspell)
|
||||
if(hunspell_FOUND)
|
||||
message(STATUS "hunspell found")
|
||||
set(HUNSPELL_LIBRARIES PkgConfig::hunspell)
|
||||
else()
|
||||
message(STATUS "hunspell not found - building hunspell")
|
||||
|
||||
set(HUNSPELL_DIR ${PROJECT_SOURCE_DIR}/3rdparty/hunspell)
|
||||
|
||||
# Build using the submodule and its CMakeLists.txt
|
||||
add_subdirectory(${HUNSPELL_DIR} hunspell_build EXCLUDE_FROM_ALL)
|
||||
|
||||
set(HUNSPELL_INCLUDE_DIR ${HUNSPELL_DIR}/src)
|
||||
set(HUNSPELL_LIBRARIES hunspell::hunspell)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
set(WINDOWS_SYS_LIBS
|
||||
windowsapp.lib
|
||||
@ -531,8 +552,6 @@ elseif (NOT APPLE)
|
||||
${APP_SRC_DIR}/screencastportal.h)
|
||||
list(APPEND QT_MODULES DBus)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
pkg_check_modules(GLIB REQUIRED glib-2.0)
|
||||
if(GLIB_FOUND)
|
||||
add_definitions(${GLIB_CFLAGS_OTHER})
|
||||
@ -615,6 +634,13 @@ else() # APPLE
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Adding HUNSPELL_INCLUDE_DIR" ${HUNSPELL_INCLUDE_DIR})
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${HUNSPELL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/hunspell/src)
|
||||
|
||||
message(STATUS "Adding HUNSPELL_LIBRARIES" ${HUNSPELL_INCLUDE_DIR})
|
||||
list(APPEND CLIENT_LIBS ${HUNSPELL_LIBRARIES})
|
||||
|
||||
# Qt find package
|
||||
if(QT6_VER AND QT6_PATH)
|
||||
message(STATUS "Using custom Qt version")
|
||||
@ -668,20 +694,34 @@ 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)
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${MD4C_SOURCE_DIR}/src)
|
||||
list(APPEND CLIENT_LIBS md4c-html)
|
||||
find_package(md4c)
|
||||
if(md4c_FOUND)
|
||||
message(STATUS "Using system-provided md4c-html")
|
||||
list(APPEND CLIENT_LIBS md4c::md4c-html)
|
||||
else()
|
||||
message("Using bundled md4c-html library")
|
||||
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)
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${MD4C_SOURCE_DIR}/src)
|
||||
list(APPEND CLIENT_LIBS md4c-html)
|
||||
endif()
|
||||
|
||||
# tidy-html5
|
||||
set(BUILD_SHARED_LIB OFF CACHE BOOL "Don't build shared tidy library" FORCE)
|
||||
set(SUPPORT_CONSOLE_APP OFF CACHE BOOL "Don't build tidy console app" FORCE)
|
||||
add_subdirectory(3rdparty/tidy-html5 EXCLUDE_FROM_ALL)
|
||||
list(APPEND CLIENT_LINK_DIRS ${tidy_BINARY_DIR}/Release)
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${tidy_SOURCE_DIR}/include)
|
||||
list(APPEND CLIENT_LIBS tidy-static)
|
||||
pkg_check_modules(tidy IMPORTED_TARGET tidy)
|
||||
if(tidy_FOUND)
|
||||
message(STATUS "Using system-provided tidy")
|
||||
list(APPEND CLIENT_LIBS PkgConfig::tidy)
|
||||
else()
|
||||
message("Using bundled tidy library")
|
||||
set(BUILD_SHARED_LIB OFF CACHE BOOL "Don't build shared tidy library" FORCE)
|
||||
set(SUPPORT_CONSOLE_APP OFF CACHE BOOL "Don't build tidy console app" FORCE)
|
||||
add_subdirectory(3rdparty/tidy-html5 EXCLUDE_FROM_ALL)
|
||||
list(APPEND CLIENT_LINK_DIRS ${tidy_BINARY_DIR}/Release)
|
||||
list(APPEND CLIENT_INCLUDE_DIRS ${tidy_SOURCE_DIR}/include)
|
||||
list(APPEND CLIENT_LIBS tidy-static)
|
||||
endif()
|
||||
|
||||
# ZXing-cpp configuration
|
||||
set(BUILD_EXAMPLES OFF CACHE BOOL "")
|
||||
@ -701,9 +741,12 @@ qt_add_executable(
|
||||
${COMMON_SOURCES}
|
||||
${QML_RESOURCES}
|
||||
${QML_RESOURCES_QML}
|
||||
${SFPM_OBJECTS})
|
||||
${SFPM_OBJECTS}
|
||||
src/app/spellcheckadapter.h src/app/spellcheckadapter.cpp)
|
||||
|
||||
# Make sure we can find the generated version file
|
||||
#add_dependencies(${PROJECT_NAME} hunspell)
|
||||
|
||||
# Ensure the generated version file can be found.
|
||||
add_dependencies(${PROJECT_NAME} generate_version_info)
|
||||
|
||||
foreach(MODULE ${QT_MODULES})
|
||||
@ -797,14 +840,19 @@ elseif (NOT APPLE)
|
||||
PRIVATE
|
||||
JAMI_INSTALL_PREFIX="${JAMI_DATA_PREFIX}")
|
||||
|
||||
target_compile_definitions(
|
||||
${PROJECT_NAME}
|
||||
PRIVATE
|
||||
HUNSPELL_INSTALL_DIR="${HUNSPELL_DICT_DIR}")
|
||||
|
||||
# Logos
|
||||
install(
|
||||
FILES resources/images/jami.svg
|
||||
FILES resources/images/net.jami.Jami.svg
|
||||
DESTINATION
|
||||
${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
|
||||
|
||||
install(
|
||||
FILES resources/images/jami-48px.png
|
||||
FILES resources/images/net.jami.Jami-48px.png
|
||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps
|
||||
RENAME jami.png)
|
||||
|
||||
@ -982,5 +1030,6 @@ qt_finalize_executable(${PROJECT_NAME})
|
||||
# tests
|
||||
if(BUILD_TESTING)
|
||||
message("Add Jami tests")
|
||||
enable_testing()
|
||||
add_subdirectory(${TESTS_DIR})
|
||||
endif()
|
||||
|
||||
@ -189,7 +189,7 @@ Only 64-bit MSVC build can be compiled.
|
||||
|
||||
- Download [Qt (Open Source)](https://www.qt.io/download-open-source?hsCtaTracking=9f6a2170-a938-42df-a8e2-a9f0b1d6cdce%7C6cb0de4f-9bb5-4778-ab02-bfb62735f3e5)
|
||||
|
||||
- Using the online installer, install the following Qt 6.6.1 components:
|
||||
- Using the online installer, install the following Qt 6.6.2 components:
|
||||
|
||||
- Git 2.10.2
|
||||
- MSVC 2019 64-bit
|
||||
@ -244,6 +244,7 @@ Only 64-bit MSVC build can be compiled.
|
||||
```bash
|
||||
python build.py --install --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.2/msvc2019_64)
|
||||
```
|
||||
> **CMake** Note: The build script does not specify what CMake generator should be used. This means CMake will search the system for the appropriate generator, which might not always select the right one if, for instance, Ninja is installed. To resolve that, the CMAKE_GENERATOR environment variable can be used, set to "Visual Studio 16 2019" or "Visual Studio 19 2022" depending on the installed Visual Studio version.
|
||||
|
||||
> **SDK** Note:
|
||||
> Jami can be build with more recent Windows SDK than the one specified in the table above. However, if your have another version than SDK 10.0.18362.0 installed, you need to identify it according to the example below. And you still need to have the required version in addition to the one you chose.
|
||||
|
||||
@ -4,10 +4,5 @@
|
||||
<?define ExeName="Jami" ?>
|
||||
<?define AppName="Jami" ?>
|
||||
<?define Manufacturer="Savoir-Faire Linux"?>
|
||||
|
||||
<?if $(var.Configuration) = Release ?>
|
||||
<?define ReleaseDir="..\x64\Release"?>
|
||||
<?else?>
|
||||
<?define ReleaseDir="..\x64\Beta"?>
|
||||
<?endif ?>
|
||||
</Include>
|
||||
|
||||
@ -16,9 +16,9 @@
|
||||
<InstallerPlatform>x64</InstallerPlatform>
|
||||
<DefineSolutionProperties>false</DefineSolutionProperties>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||
<PropertyGroup>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
|
||||
<DefineConstants>AppHarvestPath=..\x64\Release;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
|
||||
<SuppressPdbOutput>True</SuppressPdbOutput>
|
||||
<CompilerAdditionalOptions>
|
||||
@ -26,16 +26,6 @@
|
||||
<WixVariables>
|
||||
</WixVariables>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Beta|x64' ">
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
|
||||
<DefineConstants>AppHarvestPath=..\x64\Beta;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
|
||||
<SuppressPdbOutput>True</SuppressPdbOutput>
|
||||
<CompilerAdditionalOptions>
|
||||
</CompilerAdditionalOptions>
|
||||
<WixVariables>
|
||||
</WixVariables>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Product.wxs" />
|
||||
<Compile Include="AppComponents.wxs" />
|
||||
@ -70,7 +60,7 @@
|
||||
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
|
||||
</Target>
|
||||
<Target Name="BeforeBuild">
|
||||
<HeatDirectory Directory="..\x64\$(Configuration)"
|
||||
<HeatDirectory Directory="..\x64\Release"
|
||||
PreprocessorVariable="var.AppHarvestPath"
|
||||
OutputFile="AppComponents.wxs"
|
||||
ComponentGroupName="AppHeatGenerated"
|
||||
|
||||
8
build.py
8
build.py
@ -112,7 +112,7 @@ ZYPPER_CLIENT_DEPENDENCIES = [
|
||||
'qt6-svg-devel', 'qt6-multimedia-devel', 'qt6-multimedia-imports',
|
||||
'qt6-declarative-devel', 'qt6-qmlcompiler-private-devel',
|
||||
'qt6-quickcontrols2-devel', 'qt6-shadertools-devel',
|
||||
'qrencode-devel', 'NetworkManager-devel'
|
||||
'qrencode-devel', 'NetworkManager-devel', 'hunspell-devel', 'libhunspell-devel'
|
||||
]
|
||||
|
||||
ZYPPER_QT_WEBENGINE = [
|
||||
@ -139,7 +139,7 @@ DNF_CLIENT_DEPENDENCIES = [
|
||||
'libnotify-devel',
|
||||
'qt6-qtbase-devel',
|
||||
'qt6-qtsvg-devel', 'qt6-qtmultimedia-devel', 'qt6-qtdeclarative-devel',
|
||||
'qrencode-devel', 'NetworkManager-libnm-devel'
|
||||
'qrencode-devel', 'NetworkManager-libnm-devel', 'hunspell-devel', 'libhunspell-devel'
|
||||
]
|
||||
|
||||
DNF_QT_WEBENGINE = ['qt6-qtwebengine-devel']
|
||||
@ -171,7 +171,7 @@ APT_CLIENT_DEPENDENCIES = [
|
||||
'qml6-module-qtquick-dialogs', 'qml6-module-qtquick-layouts',
|
||||
'qml6-module-qtquick-shapes', 'qml6-module-qtquick-window',
|
||||
'qml6-module-qtquick-templates', 'qml6-module-qt-labs-platform',
|
||||
'libqrencode-dev', 'libnm-dev'
|
||||
'libqrencode-dev', 'libnm-dev', 'hunspell', 'libhunspell-dev'
|
||||
]
|
||||
|
||||
APT_QT_WEBENGINE = [
|
||||
@ -194,7 +194,7 @@ PACMAN_CLIENT_DEPENDENCIES = [
|
||||
'qt6-declarative', 'qt6-5compat', 'qt6-multimedia',
|
||||
'qt6-networkauth', 'qt6-shadertools',
|
||||
'qt6-svg', 'qt6-tools',
|
||||
'qrencode', 'libnm'
|
||||
'qrencode', 'libnm', 'hunspell'
|
||||
]
|
||||
|
||||
PACMAN_QT_WEBENGINE = ['qt6-webengine']
|
||||
|
||||
2
daemon
2
daemon
Submodule daemon updated: 68fc552fca...33400db731
@ -24,6 +24,7 @@ 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)
|
||||
set(BUILD_VERSION_STRING ${BUILD_VERSION})
|
||||
|
||||
# Get output file names with the .in extension removed
|
||||
get_filename_component(VERSION_CPP_FILENAME ${CPP_INT_FILE} NAME_WE)
|
||||
|
||||
@ -16,30 +16,19 @@
|
||||
|
||||
# Once done, this find module will set:
|
||||
#
|
||||
# LIBJAMI_INCLUDE_DIRS - libjami include directories
|
||||
# LIBJAMI_INCLUDE_DIR - libjami include directory
|
||||
# LIBJAMI_FOUND - whether it was able to find the include directories
|
||||
# LIBJAMI_LIB - path to libjami or libring library
|
||||
|
||||
set(LIBJAMI_FOUND true)
|
||||
|
||||
if(WITH_DAEMON_SUBMODULE)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${DAEMON_DIR}/src/jami)
|
||||
set(LIBJAMI_INCLUDE_DIR ${DAEMON_DIR}/src/jami)
|
||||
else()
|
||||
if(EXISTS ${LIBJAMI_INCLUDE_DIR}/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${LIBJAMI_INCLUDE_DIR})
|
||||
elseif(EXISTS ${LIBJAMI_BUILD_DIR}/jami/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${LIBJAMI_BUILD_DIR}/jami)
|
||||
elseif(EXISTS ${RING_INCLUDE_DIR}/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${RING_INCLUDE_DIR})
|
||||
elseif(EXISTS ${RING_BUILD_DIR}/jami/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${RING_BUILD_DIR}/jami)
|
||||
elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/include/jami/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include/jami)
|
||||
elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami/jami.h)
|
||||
set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami)
|
||||
else()
|
||||
find_path(LIBJAMI_INCLUDE_DIR jami.h PATH_SUFFIXES jami)
|
||||
if(NOT LIBJAMI_INCLUDE_DIR)
|
||||
message(STATUS "Jami daemon headers not found!
|
||||
Set -DLIBJAMI_BUILD_DIR or -DCMAKE_INSTALL_PREFIX")
|
||||
To build using the daemon git submodule, set -DWITH_DAEMON_SUBMODULE")
|
||||
set(LIBJAMI_FOUND false)
|
||||
endif()
|
||||
endif()
|
||||
@ -121,5 +110,5 @@ endif()
|
||||
# Restore the original value of CMAKE_FIND_LIBRARY_SUFFIXES.
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_orig})
|
||||
|
||||
message(STATUS "Jami daemon headers are in " ${LIBJAMI_INCLUDE_DIRS})
|
||||
message(STATUS "Jami daemon headers are in " ${LIBJAMI_INCLUDE_DIR})
|
||||
message(STATUS "Jami daemon library is at " ${LIBJAMI_LIB})
|
||||
|
||||
@ -4,11 +4,24 @@ ENV DEBIAN_FRONTEND noninteractive
|
||||
ENV QT_QUICK_BACKEND software
|
||||
ENV QT_QPA_PLATFORM offscreen
|
||||
|
||||
RUN apt-get clean
|
||||
RUN apt-get update && \
|
||||
apt-get install -y devscripts equivs
|
||||
apt-get install -y --no-install-recommends ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Use only the custom Savoir-faire Linux Ubuntu mirror
|
||||
RUN rm -f /etc/apt/sources.list /etc/apt/sources.list.d/* && \
|
||||
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy main restricted universe multiverse" > /etc/apt/sources.list && \
|
||||
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy-updates main restricted universe multiverse" >> /etc/apt/sources.list && \
|
||||
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy-security main restricted universe multiverse" >> /etc/apt/sources.list
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
devscripts \
|
||||
equivs \
|
||||
gnupg \
|
||||
dirmngr \
|
||||
curl
|
||||
|
||||
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_22.04/ jami main' > /etc/apt/sources.list.d/jami.list"
|
||||
RUN apt-get update && apt-get install libqt-jami -y
|
||||
@ -69,7 +82,8 @@ RUN apt-get install -y pandoc \
|
||||
libcppunit-dev \
|
||||
googletest \
|
||||
libgtest-dev \
|
||||
wget
|
||||
wget && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install a recent version of CMake
|
||||
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
|
||||
|
||||
@ -85,7 +85,7 @@
|
||||
<id>net.jami.daemon</id>
|
||||
</requires>
|
||||
<launchable type="desktop-id">net.jami.Jami.desktop</launchable>
|
||||
<icon type="stock">jami</icon>
|
||||
<icon type="stock">net.jami.Jami</icon>
|
||||
<url type="homepage">https://jami.net/</url>
|
||||
<url type="bugtracker">https://git.jami.net/savoirfairelinux/jami-client-qt/issues</url>
|
||||
<url type="faq">https://docs.jami.net/user/faq.html</url>
|
||||
|
||||
@ -1,14 +1,83 @@
|
||||
[Desktop Entry]
|
||||
Name=Jami
|
||||
GenericName=Jami
|
||||
Comment=Privacy-oriented voice, video, chat, and conference platform
|
||||
Comment[hu]=Adatvédelem-orientált hang-, video-, csevegés- és konferenciaplatform
|
||||
Comment[ru]=Jami — приложение для защищённой связи с распределённой архитектурой
|
||||
Comment=Share, freely and privately
|
||||
Comment[ab]=Ацеиҩшара, хақәиҭла, хала
|
||||
Comment[af]=Deel, vrylik en privaat
|
||||
Comment[am]=በነጻ እና በግል ያካፍሉ።
|
||||
Comment[ar]=شارك بحرية وبشكل خاص
|
||||
Comment[az]=Sərbəst və gizli şəkildə paylaşın
|
||||
Comment[be]=Падзяліцеся свабодна і прыватна
|
||||
Comment[bg]=Споделяйте, свободно и частно
|
||||
Comment[bn]=শেয়ার করুন, অবাধে এবং গোপনে
|
||||
Comment[ca]=Comparteix, lliurement i de forma privada
|
||||
Comment[cs]=Sdílejte svobodně a soukromě
|
||||
Comment[da]=Del, frit og privat
|
||||
Comment[de]=Teilen, frei und privat
|
||||
Comment[el]=Κοινοποιήστε, ελεύθερα και ιδιωτικά
|
||||
Comment[eo]=Kunhavigu, libere kaj private
|
||||
Comment[es]=Comparte, libre y privadamente
|
||||
Comment[et]=Jaga, vabalt ja privaatselt
|
||||
Comment[fa]=به اشتراک بگذارید، آزادانه و خصوصی
|
||||
Comment[fi]=Jaa, vapaasti ja yksityisesti
|
||||
Comment[fil]=Ibahagi, libre at pribado
|
||||
Comment[fr]=Partagez, librement, gratuitement et en toute confidentialité
|
||||
Comment[gl]=Comparte, de xeito libre e privado
|
||||
Comment[he]=שתפו, באופן חופשי ופרטי
|
||||
Comment[hi]=स्वतंत्र रूप से और निजी तौर पर साझा करें
|
||||
Comment[hr]=Dijelite, slobodno i privatno
|
||||
Comment[hu]=Megosztás, szabadon és bizalmasan
|
||||
Comment[hy]=Տարածեք, ազատ և մասնավոր
|
||||
Comment[id]=Berbagi, secara bebas dan pribadi
|
||||
Comment[is]=Deildu, frjálslega og einslega
|
||||
Comment[it]=Condividere, liberamente e privatamente
|
||||
Comment[ja]=自由に、プライベートに共有
|
||||
Comment[ka]=გააზიარეთ, თავისუფლად და პირადად
|
||||
Comment[km]=ចែករំលែកដោយសេរី និងឯកជន
|
||||
Comment[kn]=ಮುಕ್ತವಾಗಿ ಮತ್ತು ಖಾಸಗಿಯಾಗಿ ಹಂಚಿಕೊಳ್ಳಿ
|
||||
Comment[ko]=자유롭고 비공개적으로 공유하세요
|
||||
Comment[ky]=Бөлүшүү, эркин жана купуя
|
||||
Comment[la]=Communicantes, libere et privatim
|
||||
Comment[lo]=ແບ່ງປັນ, ຢ່າງເສລີແລະເປັນສ່ວນຕົວ
|
||||
Comment[lt]=Dalintis, laisvai ir privačiai
|
||||
Comment[lv]=Kopīgojiet, brīvi un privāti
|
||||
Comment[mk]=Споделете, слободно и приватно
|
||||
Comment[ml]=സ്വതന്ത്രമായും സ്വകാര്യമായും പങ്കിടുക
|
||||
Comment[mn]=Чөлөөт, хувийн байдлаар хуваалцах
|
||||
Comment[mr]=सामायिक करा, मुक्तपणे आणि खाजगीरित्या
|
||||
Comment[ms]=Kongsi, secara bebas dan peribadi
|
||||
Comment[my]=လွတ်လပ်စွာ သီးသန့်မျှဝေပါ။
|
||||
Comment[ne]=स्वतन्त्र र गोप्य रूपमा सेयर गर्नुहोस्
|
||||
Comment[nl]=Deel, vrij en privé
|
||||
Comment[no]=Del, fritt og privat
|
||||
Comment[pl]=Udostępniaj swobodnie i prywatnie
|
||||
Comment[pt_BR]=Compartilhe, livre e privadamente
|
||||
Comment[pt_PT]=Partilhe, livre e privadamente
|
||||
Comment[ro]=Distribuie, în mod liber și privat
|
||||
Comment[ru]=Делитесь, свободно и конфиденциально
|
||||
Comment[si]=නිදහසේ සහ පෞද්ගලිකව බෙදා ගන්න
|
||||
Comment[sk]=Zdieľajte, slobodne a súkromne
|
||||
Comment[sl]=Delite brezplačno in zasebno
|
||||
Comment[sq]=Shpërndaje, lirisht dhe privatisht
|
||||
Comment[sr]=Делите, слободно и приватно
|
||||
Comment[sv]=Dela, fritt och privat
|
||||
Comment[sw]=Shiriki, kwa uhuru na kwa faragha
|
||||
Comment[ta]=பகிரவும், சுதந்திரமாகவும் தனிப்பட்ட முறையிலும்
|
||||
Comment[te]=ఉచితంగా మరియు ప్రైవేట్గా షేర్ చేయండి
|
||||
Comment[th]=แบ่งปันได้อย่างอิสระและเป็นส่วนตัว
|
||||
Comment[tl]=Ibahagi, libre at pribado
|
||||
Comment[tr]=Özgürce ve özel olarak paylaşın
|
||||
Comment[uk]=Поділіться вільно та приватно
|
||||
Comment[vi]=Chia sẻ, tự do và riêng tư
|
||||
Comment[zh_CN]=自由且私密地分享
|
||||
Comment[zh_HK]=自由且私密地分享
|
||||
Comment[zh_TW]=自由且私密地分享
|
||||
Comment[zu]=Yabelana, ngokukhululekile nangasese
|
||||
Exec=jami %u
|
||||
Icon=jami
|
||||
Icon=net.jami.Jami
|
||||
StartupNotify=true
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Network;Telephony;
|
||||
Categories=Chat;FileTransfer;InstantMessaging;Network;P2P;Telephony;VideoConference;
|
||||
Keywords=Qt;chat;talk;im;message;voip;
|
||||
MimeType=x-scheme-handler/jami;
|
||||
MimeType=x-scheme-handler/jami;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
7
extras/packaging/gnu-linux/Jenkinsfile
vendored
7
extras/packaging/gnu-linux/Jenkinsfile
vendored
@ -34,7 +34,8 @@ def SUBMODULES = ['daemon',
|
||||
'3rdparty/SortFilterProxyModel',
|
||||
'3rdparty/md4c',
|
||||
'3rdparty/tidy-html5',
|
||||
'3rdparty/zxing-cpp']
|
||||
'3rdparty/zxing-cpp',
|
||||
'3rdparty/hunspell']
|
||||
def TARGETS = [:]
|
||||
def REMOTE_HOST = env.SSH_HOST_DL_RING_CX
|
||||
def REMOTE_BASE_DIR = '/srv/repository/ring'
|
||||
@ -84,6 +85,10 @@ pipeline {
|
||||
|
||||
environment {
|
||||
TARBALLS = '/var/cache/jami' // set the cache directory
|
||||
BUILD_VERSION = sh(
|
||||
returnStdout: true,
|
||||
script: 'date +"%Y%m%d%H%M"'
|
||||
).trim()
|
||||
}
|
||||
|
||||
stages {
|
||||
|
||||
@ -128,7 +128,8 @@ $(RELEASE_TARBALL_FILENAME): tarballs.manifest
|
||||
./3rdparty/SortFilterProxyModel \
|
||||
./3rdparty/md4c \
|
||||
./3rdparty/tidy-html5 \
|
||||
./3rdparty/zxing-cpp; do \
|
||||
./3rdparty/zxing-cpp \
|
||||
./3rdparty/hunspell; do \
|
||||
(cd "$$m" && git archive --prefix "$$m/" HEAD \
|
||||
| tar xf - -C $(TMPDIR)/$(RELEASE_DIRNAME)); \
|
||||
done
|
||||
@ -166,13 +167,11 @@ DISTRIBUTIONS := \
|
||||
ubuntu_20.04 \
|
||||
ubuntu_22.04 \
|
||||
ubuntu_24.04 \
|
||||
ubuntu_24.10 \
|
||||
ubuntu_25.04 \
|
||||
fedora_39 \
|
||||
fedora_40 \
|
||||
fedora_41 \
|
||||
fedora_42 \
|
||||
alma_9 \
|
||||
opensuse-leap_15.5 \
|
||||
alma_10 \
|
||||
opensuse-leap_15.6 \
|
||||
snap
|
||||
|
||||
@ -192,6 +191,7 @@ $(1)-docker-image-name := jami-packaging-$(1)
|
||||
$(1)-docker-image-file := .docker-image-$$($(1)-docker-image-name)
|
||||
$(1)-docker-run-command := docker run \
|
||||
--rm --privileged --security-opt apparmor=docker-default \
|
||||
-e BUILD_VERSION=${BUILD_VERSION} \
|
||||
-e RELEASE_VERSION="$(RELEASE_VERSION)" \
|
||||
-e RELEASE_DIRNAME="$(RELEASE_DIRNAME)" \
|
||||
-e RELEASE_TARBALL_FILENAME="$(RELEASE_TARBALL_FILENAME)" \
|
||||
@ -251,7 +251,7 @@ define guix-pack-command
|
||||
guix pack -C xz -f $(1) -m $(CURDIR)/extras/packaging/gnu-linux/guix/guix-pack-manifest.scm -v3 \
|
||||
-S /usr/bin/jami=bin/jami \
|
||||
-S /usr/share/applications/net.jami.Jami.desktop=share/applications/net.jami.Jami.desktop \
|
||||
-S /usr/share/icons/hicolor/scalable/apps/jami.svg=share/icons/hicolor/scalable/apps/jami.svg \
|
||||
-S /usr/share/icons/hicolor/scalable/apps/net.jami.Jami.svg=share/icons/hicolor/scalable/apps/net.jami.Jami.svg \
|
||||
-S /usr/share/icons/hicolor/48x48/apps/jami.png=share/icons/hicolor/48x48/apps/jami.png \
|
||||
-S /usr/share/metainfo/net.jami.Jami.metainfo.xml=share/metainfo/net.jami.Jami.metainfo.xml \
|
||||
-S /usr/share/swcatalog/xml/jami.xml=share/swcatalog/xml/jami.xml \
|
||||
|
||||
@ -1,105 +1,93 @@
|
||||
FROM fedora:39
|
||||
|
||||
RUN dnf clean all
|
||||
RUN dnf update -y
|
||||
|
||||
FROM almalinux:10
|
||||
RUN dnf clean all && dnf update -y
|
||||
RUN dnf install -y epel-release
|
||||
RUN dnf install -y 'dnf-command(config-manager)'
|
||||
RUN dnf config-manager --set-enabled crb
|
||||
RUN dnf config-manager --set-enabled appstream
|
||||
RUN dnf install -y dnf-command\(builddep\) rpmdevtools && \
|
||||
dnf install -y mock
|
||||
|
||||
RUN dnf groupinstall -y "X Software Development"
|
||||
|
||||
RUN yum install -y xorg-x11-xauth
|
||||
RUN dnf install -y \
|
||||
git \
|
||||
rpm-build \
|
||||
tar \
|
||||
make \
|
||||
alsa-lib-devel \
|
||||
astyle \
|
||||
autoconf \
|
||||
automake \
|
||||
nasm \
|
||||
speexdsp-devel \
|
||||
pulseaudio-libs-devel \
|
||||
libcanberra-devel \
|
||||
libcurl-devel \
|
||||
libtool \
|
||||
mesa-libgbm-devel \
|
||||
mesa-dri-drivers \
|
||||
bison \
|
||||
check \
|
||||
chrpath \
|
||||
clang15-devel \
|
||||
cmake \
|
||||
cryptopp-devel \
|
||||
cups-devel \
|
||||
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 \
|
||||
fmt-devel \
|
||||
gcc-c++ \
|
||||
gettext-devel \
|
||||
git \
|
||||
gnutls-devel \
|
||||
gperf \
|
||||
gsm-devel \
|
||||
gstreamer1 gstreamer1-devel \
|
||||
gstreamer1-plugins-bad-free-devel \
|
||||
gstreamer1-plugins-base-devel \
|
||||
gstreamer1-plugins-good \
|
||||
gstreamer1-plugins-bad-free-devel \
|
||||
nss-devel \
|
||||
jsoncpp-devel \
|
||||
libX11-devel \
|
||||
libXext-devel \
|
||||
libXfixes-devel \
|
||||
libXrender-devel \
|
||||
libappindicator-gtk3-devel \
|
||||
libargon2-devel \
|
||||
libcanberra-devel \
|
||||
libcurl-devel \
|
||||
libdrm \
|
||||
libnatpmp-devel \
|
||||
libnotify \
|
||||
libnotify-devel \
|
||||
libsndfile-devel \
|
||||
libstdc++-static \
|
||||
libtool \
|
||||
libupnp-devel \
|
||||
libuuid-devel \
|
||||
libva-devel \
|
||||
libvdpau-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 \
|
||||
llvm15-devel \
|
||||
make \
|
||||
mesa-dri-drivers \
|
||||
mesa-libgbm-devel \
|
||||
msgpack-devel \
|
||||
nasm \
|
||||
nettle-devel \
|
||||
NetworkManager-libnm-devel \
|
||||
ninja-build \
|
||||
clang \
|
||||
cmake \
|
||||
fmt-devel \
|
||||
python3.10 \
|
||||
cups-devel \
|
||||
pipewire-devel
|
||||
|
||||
nodejs \
|
||||
nss-devel \
|
||||
openssl-devel \
|
||||
opus-devel \
|
||||
pcre2-devel \
|
||||
perl-English \
|
||||
perl-generators \
|
||||
pipewire-devel \
|
||||
pulseaudio-libs-devel \
|
||||
python3-html5lib \
|
||||
qrencode-devel \
|
||||
speex-devel \
|
||||
speexdsp-devel \
|
||||
sqlite-devel \
|
||||
systemd-devel \
|
||||
uuid-devel \
|
||||
vulkan-devel \
|
||||
webkitgtk6.0-devel \
|
||||
wget \
|
||||
which \
|
||||
xcb-util-* \
|
||||
xkeyboard-config \
|
||||
yaml-cpp-devel \
|
||||
yasm
|
||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
|
||||
|
||||
CMD ["/opt/build-package-rpm.sh"]
|
||||
CMD ["/opt/build-package-rpm.sh"]
|
||||
@ -70,9 +70,8 @@ RUN dnf install -y \
|
||||
libdrm \
|
||||
gperf \
|
||||
bison \
|
||||
clang \
|
||||
clang-devel \
|
||||
llvm-devel \
|
||||
clang16-devel \
|
||||
llvm16-devel \
|
||||
nodejs \
|
||||
flex \
|
||||
gstreamer1 gstreamer1-devel \
|
||||
@ -96,7 +95,6 @@ RUN dnf install -y \
|
||||
perl-English \
|
||||
libxshmfence-devel \
|
||||
ninja-build \
|
||||
clang \
|
||||
cmake \
|
||||
fmt-devel \
|
||||
python3-html5lib \
|
||||
|
||||
@ -11,14 +11,6 @@ RUN apt-get update && \
|
||||
libdbus-1-dev \
|
||||
wget
|
||||
|
||||
# As of January 2024, the default compiler on Debian unstable is GCC 13.2.0, which
|
||||
# is unable to build one of Qt 6.6.1's dependencies, see:
|
||||
# https://github.com/qt/qtquick3d-assimp/commit/253f8bfa621a9fa6cd2c36291cdaa8c60c99322c
|
||||
# The linked commit above fixes the problem and is included in more recent versions of Qt.
|
||||
# For now, we use GCC 12 as a temporary workaround:
|
||||
ADD extras/packaging/gnu-linux/scripts/install-gcc-debian.sh /opt/install-gcc-debian.sh
|
||||
RUN /opt/install-gcc-debian.sh 12
|
||||
|
||||
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
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
FROM fedora:40
|
||||
FROM fedora:42
|
||||
|
||||
RUN dnf clean all
|
||||
RUN dnf update -y
|
||||
@ -6,12 +6,10 @@ 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 group install -y x-software-development
|
||||
|
||||
RUN dnf install -y \
|
||||
git \
|
||||
rpm-build \
|
||||
tar \
|
||||
make \
|
||||
autoconf \
|
||||
automake \
|
||||
@ -22,13 +20,10 @@ RUN dnf install -y \
|
||||
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 \
|
||||
@ -37,16 +32,15 @@ RUN dnf install -y \
|
||||
astyle \
|
||||
uuid-c++-devel \
|
||||
gettext-devel \
|
||||
gcc-c++ \
|
||||
gcc14 \
|
||||
gcc14-c++ \
|
||||
which \
|
||||
alsa-lib-devel \
|
||||
systemd-devel \
|
||||
libuuid-devel \
|
||||
uuid-devel \
|
||||
gnutls-devel \
|
||||
nettle-devel \
|
||||
opus-devel \
|
||||
patch \
|
||||
jsoncpp-devel \
|
||||
libnatpmp-devel \
|
||||
webkitgtk4-devel \
|
||||
@ -64,28 +58,20 @@ RUN dnf install -y \
|
||||
qrencode-devel \
|
||||
libargon2-devel \
|
||||
libsndfile-devel \
|
||||
libdrm \
|
||||
gperf \
|
||||
bison \
|
||||
clang \
|
||||
clang-devel \
|
||||
llvm-devel \
|
||||
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 \
|
||||
@ -93,13 +79,19 @@ RUN dnf install -y \
|
||||
perl-English \
|
||||
libxshmfence-devel \
|
||||
ninja-build \
|
||||
clang \
|
||||
cmake \
|
||||
fmt-devel \
|
||||
python3.10 \
|
||||
cups-devel \
|
||||
pipewire-devel
|
||||
|
||||
# Use GCC 14 instead of GCC 15 (the default on Fedora 42)
|
||||
# because Qt 6.6.3 fails to build when using the latter.
|
||||
RUN rm /usr/bin/gcc /usr/bin/g++ /usr/bin/c++ && \
|
||||
ln -s /usr/bin/gcc-14 /usr/bin/gcc && \
|
||||
ln -s /usr/bin/g++-14 /usr/bin/g++ && \
|
||||
ln -s /usr/bin/g++-14 /usr/bin/c++
|
||||
|
||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
|
||||
|
||||
CMD ["/opt/build-package-rpm.sh"]
|
||||
@ -1,117 +0,0 @@
|
||||
FROM opensuse/leap:15.5
|
||||
|
||||
RUN zypper --gpg-auto-import-keys refresh
|
||||
|
||||
RUN zypper --non-interactive install -y \
|
||||
dnf \
|
||||
dnf-command\(builddep\) \
|
||||
rpmdevtools \
|
||||
Mesa-dri-devel Mesa-dri \
|
||||
git \
|
||||
gcc10 \
|
||||
gcc10-c++ \
|
||||
rpm-build \
|
||||
tar \
|
||||
make \
|
||||
autoconf \
|
||||
automake \
|
||||
nasm \
|
||||
speexdsp-devel \
|
||||
libpulse-devel \
|
||||
libcanberra-devel \
|
||||
libcurl-devel \
|
||||
libtool \
|
||||
pcre-devel \
|
||||
yaml-cpp-devel \
|
||||
libXext-devel \
|
||||
libXfixes-devel \
|
||||
yasm \
|
||||
speex-devel \
|
||||
libgsm-devel \
|
||||
chrpath \
|
||||
check \
|
||||
astyle \
|
||||
gettext-devel \
|
||||
which \
|
||||
alsa-lib-devel \
|
||||
systemd-devel \
|
||||
libuuid-devel \
|
||||
uuid-devel \
|
||||
libopus-devel \
|
||||
patch \
|
||||
jsoncpp-devel \
|
||||
webkit2gtk3-devel \
|
||||
libcryptopp-devel \
|
||||
libva-devel \
|
||||
libvdpau-devel \
|
||||
msgpack-c-devel \
|
||||
msgpack-cxx-devel \
|
||||
clutter-devel \
|
||||
openssl-devel \
|
||||
clutter-gtk-devel \
|
||||
libnma-devel \
|
||||
libcryptopp-devel \
|
||||
libexpat-devel \
|
||||
gnome-icon-theme-symbolic \
|
||||
libgsm-devel \
|
||||
gtk3-devel \
|
||||
libappindicator-devel \
|
||||
sqlite-devel \
|
||||
ffmpeg-4-libavutil-devel \
|
||||
gtk3-devel\
|
||||
qrencode-devel \
|
||||
python310 \
|
||||
python3-python-dateutil \
|
||||
python3-html5lib \
|
||||
libsndfile-devel \
|
||||
libdrm \
|
||||
gperf \
|
||||
bison \
|
||||
flex \
|
||||
ffmpeg ffmpeg-devel \
|
||||
nodejs20 \
|
||||
mozilla-nss-devel \
|
||||
python-xml \
|
||||
python3-six \
|
||||
python3-importlib-metadata \
|
||||
libxcb* \
|
||||
libxkb* \
|
||||
libX11-devel \
|
||||
libXrender-devel \
|
||||
libfreetype6 \
|
||||
xcb-util-image-devel \
|
||||
xcb-util-keysyms-devel \
|
||||
xcb-util-renderutil-devel \
|
||||
xcb-util-wm-devel \
|
||||
xorg-x11-devel \
|
||||
xz \
|
||||
xkeyboard-config \
|
||||
libnotify \
|
||||
argon2-devel \
|
||||
libxshmfence-devel \
|
||||
xproto-devel \
|
||||
xcb-proto-devel \
|
||||
xcb-* \
|
||||
xorg-* \
|
||||
vulkan-devel \
|
||||
ninja \
|
||||
gstreamer-devel \
|
||||
gstreamer-plugins-good \
|
||||
gstreamer-plugins-bad-devel \
|
||||
gstreamer-plugins-base-devel \
|
||||
cmake \
|
||||
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
|
||||
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.10 /usr/bin/python3
|
||||
|
||||
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 50
|
||||
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 50
|
||||
|
||||
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
|
||||
|
||||
ENV CC=gcc
|
||||
ENV CXX=g++
|
||||
CMD ["/opt/build-package-rpm.sh"]
|
||||
@ -36,12 +36,6 @@ RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/sna
|
||||
RUN mkdir -p /snap/snapcraft
|
||||
RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap
|
||||
|
||||
# Fix Python3 installation: Make sure we use the interpreter from
|
||||
# the snapcraft snap:
|
||||
RUN unlink /snap/snapcraft/current/usr/bin/python3
|
||||
RUN ln -s /snap/snapcraft/current/usr/bin/python3.* /snap/snapcraft/current/usr/bin/python3
|
||||
RUN echo /snap/snapcraft/current/lib/python3.*/site-packages >> /snap/snapcraft/current/usr/lib/python3/dist-packages/site-packages.pth
|
||||
|
||||
# Create a snapcraft runner
|
||||
RUN mkdir -p /snap/bin
|
||||
RUN echo "#!/bin/sh" > /snap/bin/snapcraft
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
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"]
|
||||
@ -24,7 +24,10 @@
|
||||
(list
|
||||
;; Minimal requirements of the daemon contrib build system.
|
||||
"coreutils"
|
||||
"gcc-toolchain"
|
||||
;; When using GCC 15, Jami fails to link with errors like:
|
||||
;; ld: CMakeFiles/jami.dir/src/app/main.cpp.o:(.rodata+0x0):
|
||||
;; multiple definition of `QtPrivate::IsFloatType_v<_Float16>'
|
||||
"gcc-toolchain@14"
|
||||
"git-minimal"
|
||||
"grep"
|
||||
"gzip"
|
||||
@ -42,18 +45,12 @@
|
||||
"alsa-lib"
|
||||
"autoconf"
|
||||
"automake"
|
||||
"asio"
|
||||
"bash"
|
||||
"bzip2"
|
||||
"cmake"
|
||||
"dbus"
|
||||
;; Bundled because broken with GCC 7 upstream (unmaintained). When
|
||||
;; attempting to use it, it would cause confusing errors such as
|
||||
;; "ld: ../src/.libs/libring.a(libupnpcontrol_la-upnp_context.o): in
|
||||
;; function `jami::upnp::UPnPContext::updateMappingList(bool)':
|
||||
;; upnp_context.cpp:(.text+0xa4be): undefined reference to
|
||||
;; `std::__cxx11::basic_ostringstream<char, std::char_traits<char>,
|
||||
;; std::allocator<char> >::basic_ostringstream()'
|
||||
;;"dbus-c++" ;for dbusxx-xml2cpp
|
||||
;;"dhtnet" ;bundled because tightly coupled
|
||||
"diffutils"
|
||||
"doxygen"
|
||||
"eudev" ;udev library
|
||||
@ -67,6 +64,7 @@
|
||||
"gsm"
|
||||
"gtk-doc"
|
||||
"http-parser"
|
||||
"jack@0"
|
||||
"jsoncpp"
|
||||
"libarchive"
|
||||
"libgit2"
|
||||
@ -84,16 +82,24 @@
|
||||
"patch"
|
||||
"pcre"
|
||||
"perl"
|
||||
"pipewire"
|
||||
;;"pjproject" ;bundled because patched
|
||||
"pulseaudio"
|
||||
"sdbus-c++@1"
|
||||
"speex"
|
||||
"speexdsp"
|
||||
"webrtc-audio-processing@0"
|
||||
"which"
|
||||
"yaml-cpp"
|
||||
"yasm"
|
||||
|
||||
;; For the Qt client.
|
||||
"glib"
|
||||
"hunspell"
|
||||
"libnotify"
|
||||
"libxcb"
|
||||
"libxkbcommon"
|
||||
"md4c"
|
||||
"network-manager" ;libnm
|
||||
"qrencode"
|
||||
"qtbase"
|
||||
@ -103,10 +109,13 @@
|
||||
"qtnetworkauth"
|
||||
"qtpositioning"
|
||||
"qtsvg"
|
||||
"qwindowkit"
|
||||
"qttools"
|
||||
"qtwebchannel"
|
||||
"qtwebengine"
|
||||
"tidy-html"
|
||||
"vulkan-headers"
|
||||
"zxing-cpp"
|
||||
|
||||
;; For tests and debugging.
|
||||
"file"
|
||||
|
||||
@ -261,7 +261,7 @@ Build-Depends: debhelper (>= 9),
|
||||
gperf,
|
||||
khronos-api,
|
||||
# libasound2-dev [linux-any],
|
||||
libavcodec-dev (>= 7:3.4.8~),
|
||||
libavcodec-dev (>= 7:3.4.8~) | libavcodec-extra-dev (>= 7:3.4.8~),
|
||||
libavformat-dev (>= 7:3.4.8~),
|
||||
libavutil-dev (>= 7:3.4.8~),
|
||||
libcap-dev [linux-any],
|
||||
|
||||
@ -30,7 +30,7 @@ Build-Depends: debhelper (>= 9),
|
||||
libspeex-dev,
|
||||
libspeexdsp-dev,
|
||||
uuid-dev,
|
||||
libavcodec-dev,
|
||||
libavcodec-dev | libavcodec-extra-dev,
|
||||
libavutil-dev,
|
||||
libavformat-dev,
|
||||
libswscale-dev,
|
||||
|
||||
@ -101,8 +101,6 @@ if [ -f /etc/os-release ]; then
|
||||
ENDTAG="ubuntu_22.04"
|
||||
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 [ "${UBUNTU_CODENAME}" = "plucky" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_25.04" ]; then
|
||||
ENDTAG="ubuntu_25.04"
|
||||
elif [ "${ID}" = "debian" ] && \
|
||||
|
||||
@ -74,7 +74,7 @@ override_dh_auto_build:
|
||||
--disable-gsm \
|
||||
--disable-speexdsp \
|
||||
--disable-natpmp \
|
||||
--enable-gnutls $(BUNDLED_PKGS) && \
|
||||
$(BUNDLED_PKGS) && \
|
||||
make list && \
|
||||
make -j$(NO_CPUS) V=1
|
||||
cd daemon && \
|
||||
@ -91,6 +91,7 @@ override_dh_auto_build:
|
||||
mkdir build && \
|
||||
cd build && \
|
||||
cmake \
|
||||
-DBUILD_VERSION=$(BUILD_VERSION) \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DLIBJAMI_BUILD_DIR=$(CURDIR)/daemon/src \
|
||||
-DENABLE_LIBWRAP=true \
|
||||
|
||||
@ -49,7 +49,7 @@ BuildRequires: libXfixes-devel
|
||||
BuildRequires: libuuid-devel
|
||||
BuildRequires: libva-devel
|
||||
BuildRequires: libvdpau-devel
|
||||
BuildRequires: pcre-devel
|
||||
BuildRequires: (pcre-devel or pcre2-devel)
|
||||
BuildRequires: pipewire-devel
|
||||
BuildRequires: uuid-devel
|
||||
BuildRequires: yaml-cpp-devel
|
||||
|
||||
@ -31,6 +31,7 @@ URL: https://jami.net/
|
||||
Source: jami-libqt-%{version}.tar.xz
|
||||
Patch0: 0001-fix-gcc14.patch
|
||||
Patch1: 0002-qtwebengine-add-missing-chromium-dependencies.patch
|
||||
Patch2: 0003-fix-embree-linking-errors.patch
|
||||
|
||||
%global gst 0.10
|
||||
%if 0%{?fedora} || 0%{?rhel} > 7
|
||||
@ -68,6 +69,7 @@ This package contains Qt libraries for Jami.
|
||||
%setup -n qt-everywhere-src-%{version}
|
||||
%patch -P 0 -p1
|
||||
%patch -P 1 -p1
|
||||
%patch -P 2 -p1
|
||||
|
||||
%build
|
||||
echo "Building Qt using %{job_count} parallel jobs"
|
||||
|
||||
@ -1,16 +1,7 @@
|
||||
%define name jami
|
||||
%define version RELEASE_VERSION
|
||||
%define release 0
|
||||
|
||||
# The AppStream 1.0 spec says that the catalog file must be put in /usr/share/swcatalog/xml
|
||||
# (see https://www.freedesktop.org/software/appstream/docs/chap-CatalogData.html).
|
||||
#
|
||||
# However, openSUSE Leap still uses the legacy path /usr/share/app-info/xmls as of version 15.5.
|
||||
%if 0%{?sle_version} && 0%{?sle_version} <= 150500
|
||||
%define appstream_catalog_dir /share/app-info/xmls
|
||||
%else
|
||||
%define appstream_catalog_dir /share/swcatalog/xml
|
||||
%endif
|
||||
|
||||
# Exclude vendored Qt6 from dependency generator
|
||||
%define __requires_exclude ^libQt6.*$
|
||||
@ -82,6 +73,7 @@ cd %{_builddir}/jami-%{version} && \
|
||||
-DAPPSTREAM_CATALOG_DIR=%{appstream_catalog_dir} \
|
||||
-DWITH_DAEMON_SUBMODULE=true \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_VERSION=${BUILD_VERSION} \
|
||||
..
|
||||
make -C %{_builddir}/jami-%{version}/build %{_smp_mflags} V=2
|
||||
|
||||
@ -93,7 +85,7 @@ DESTDIR=%{buildroot} make -C %{_builddir}/jami-%{version}/build install V=2
|
||||
%{_bindir}/jami
|
||||
%{_datadir}/applications/net.jami.Jami.desktop
|
||||
%{_datadir}/jami/net.jami.Jami.desktop
|
||||
%{_datadir}/icons/hicolor/scalable/apps/jami.svg
|
||||
%{_datadir}/icons/hicolor/scalable/apps/net.jami.Jami.svg
|
||||
%{_datadir}/icons/hicolor/48x48/apps/jami.png
|
||||
%{_datadir}/pixmaps/jami.xpm
|
||||
%{_datadir}/metainfo/net.jami.Jami.metainfo.xml
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
From 709d0b0cf45b920f63960a70725138dbaf7ec721 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, 18 Jun 2025 15:53:55 -0400
|
||||
Subject: [PATCH] Fix embree linking errors
|
||||
|
||||
Patch taken from:
|
||||
https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=37bd373cd33c36f8dd44e71be25fa6ea24cf4588
|
||||
---
|
||||
qtquick3d/src/3rdparty/embree/CMakeLists.txt | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/qtquick3d/src/3rdparty/embree/CMakeLists.txt b/qtquick3d/src/3rdparty/embree/CMakeLists.txt
|
||||
index cf27196de2..332bbd17ca 100644
|
||||
--- a/qtquick3d/src/3rdparty/embree/CMakeLists.txt
|
||||
+++ b/qtquick3d/src/3rdparty/embree/CMakeLists.txt
|
||||
@@ -62,6 +62,9 @@ if (IOS)
|
||||
endif()
|
||||
|
||||
# Use SSE2 only, ignore AVX/SSE4.2 for now
|
||||
+if (TEST_architecture_arch STREQUAL x86_64)
|
||||
+ qt_internal_extend_target(BundledEmbree COMPILE_OPTIONS -mno-avx -mno-sse4.2)
|
||||
+endif()
|
||||
qt_internal_extend_target(BundledEmbree DEFINES
|
||||
EMBREE_TARGET_SSE2
|
||||
__SSE2__
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@ -270,7 +270,7 @@ parts:
|
||||
ls
|
||||
snapcraftctl pull
|
||||
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/net.jami.Jami.desktop
|
||||
sed -i -E 's|^Icon=.*|Icon=${SNAP}/usr/share/icons/hicolor/scalable/apps/net.jami.Jami.svg|' extras/data/net.jami.Jami.desktop
|
||||
override-build: |
|
||||
$SNAPCRAFT_PART_BUILD/extras/packaging/gnu-linux/scripts/install-pipewire-from-source.sh
|
||||
|
||||
@ -293,7 +293,8 @@ parts:
|
||||
cmake .. -DENABLE_LIBWRAP=true \
|
||||
-DLIBJAMI_BUILD_DIR=$SNAPCRAFT_PART_BUILD/daemon/src \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DBUILD_VERSION=BUILD_VERSION_PLACEHOLDER
|
||||
make -j$SNAPCRAFT_PARALLEL_BUILD_COUNT
|
||||
DESTDIR=$SNAPCRAFT_PART_INSTALL make install
|
||||
build-packages:
|
||||
|
||||
@ -101,14 +101,14 @@ if [ ! -f "${RPM_PATH}" ]; then
|
||||
# Cache the built Qt RPM package.
|
||||
if [[ "${DISTRIBUTION:0:4}" == "rhel" ]]; then
|
||||
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el8.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}" == "fedora_42" ]]; then
|
||||
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc42.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}"
|
||||
elif [[ "${DISTRIBUTION}" == "alma_10" ]]; then
|
||||
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el10.x86_64.rpm "${RPM_PATH}"
|
||||
else
|
||||
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-*.rpm "${RPM_PATH}"
|
||||
fi
|
||||
@ -132,7 +132,7 @@ rpmbuild --define "debug_package %{nil}" -ba jami-libclient.spec
|
||||
rpmbuild --define "debug_package %{nil}" -ba jami-qt.spec
|
||||
|
||||
# Build the Qt client.
|
||||
rpmbuild --define "debug_package %{nil}" -ba jami.spec
|
||||
rpmbuild --define "debug_package %{nil}" --define "BUILD_VERSION ${BUILD_VERSION}" -ba jami.spec
|
||||
|
||||
# Move the built packages to the output directory.
|
||||
mv /root/rpmbuild/RPMS/*/* /opt/output
|
||||
|
||||
@ -29,6 +29,9 @@ cp -r extras/packaging/gnu-linux/rules/snap/${SNAP_PKG_NAME}/snapcraft.yaml .
|
||||
# set the version and tarball filename
|
||||
sed -i "s/RELEASE_VERSION/${RELEASE_VERSION}/g" snapcraft.yaml
|
||||
|
||||
# set the build version of the app
|
||||
sed -i "s/BUILD_VERSION_PLACEHOLDER/${BUILD_VERSION}/g" snapcraft.yaml
|
||||
|
||||
snapcraft # requires snapcraft >= 4.8
|
||||
|
||||
# move the built snap to output
|
||||
|
||||
@ -212,6 +212,7 @@ def init_submodules():
|
||||
"3rdparty/md4c",
|
||||
"3rdparty/tidy-html5",
|
||||
"3rdparty/zxing-cpp",
|
||||
"3rdparty/hunspell",
|
||||
]
|
||||
if execute_cmd(["git", "submodule", "update", "--init" ] + submodules,
|
||||
False):
|
||||
@ -262,7 +263,7 @@ def cmake_build(config_str, env_vars, cmake_build_dir):
|
||||
return True
|
||||
|
||||
|
||||
def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None):
|
||||
def build(config_str, qt_dir, tests, build_version, enable_crash_reports, crash_report_url=None):
|
||||
"""Use cmake to build the project."""
|
||||
print("Building with Qt at " + qt_dir)
|
||||
|
||||
@ -293,6 +294,9 @@ def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None
|
||||
else:
|
||||
cmake_options.append("-DENABLE_CRASHREPORTS=OFF")
|
||||
|
||||
if build_version:
|
||||
cmake_options.append("-DBUILD_VERSION=" + build_version)
|
||||
|
||||
# Make sure the build directory exists.
|
||||
if not os.path.exists(build_dir):
|
||||
os.makedirs(build_dir)
|
||||
@ -306,11 +310,11 @@ def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def deploy_runtimes(config_str, qt_dir):
|
||||
def deploy_runtimes(qt_dir):
|
||||
"""Deploy the dependencies to the runtime directory."""
|
||||
print("Deploying runtime dependencies")
|
||||
|
||||
runtime_dir = os.path.join(repo_root_dir, "x64", config_str)
|
||||
runtime_dir = os.path.join(repo_root_dir, "x64", "Release")
|
||||
stamp_file = os.path.join(runtime_dir, ".deploy.stamp")
|
||||
if os.path.exists(stamp_file):
|
||||
return
|
||||
@ -469,6 +473,8 @@ def parse_args():
|
||||
help='Sets the Qt root path')
|
||||
parser.add_argument(
|
||||
"-a", "--arch", default="x64", help="Sets the build architecture")
|
||||
parser.add_argument(
|
||||
"--build-version", help="Sets the build version string used for defining app build version")
|
||||
parser.add_argument(
|
||||
"-t", "--tests", action="store_true", help="Build and run tests")
|
||||
parser.add_argument(
|
||||
@ -551,10 +557,11 @@ def main():
|
||||
def do_build(do_tests):
|
||||
if not parsed_args.skip_build:
|
||||
build(config_str, parsed_args.qt, do_tests,
|
||||
parsed_args.build_version,
|
||||
parsed_args.enable_crash_reports,
|
||||
parsed_args.crash_report_url)
|
||||
if not parsed_args.skip_deploy:
|
||||
deploy_runtimes(config_str, parsed_args.qt)
|
||||
deploy_runtimes(parsed_args.qt)
|
||||
|
||||
if parsed_args.subcommand == "pack":
|
||||
do_build(False)
|
||||
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
382
resources/misc/available_dictionaries.json
Normal file
382
resources/misc/available_dictionaries.json
Normal file
@ -0,0 +1,382 @@
|
||||
{
|
||||
"af_ZA": {
|
||||
"nativeName": "Afrikaans (Suid-Afrika)",
|
||||
"path": "af_ZA/af_ZA"
|
||||
},
|
||||
"an_ES": {
|
||||
"nativeName": "aragonés (España)",
|
||||
"path": "an_ES/an_ES"
|
||||
},
|
||||
"ar": {
|
||||
"nativeName": "العربية",
|
||||
"path": "ar/ar"
|
||||
},
|
||||
"as_IN": {
|
||||
"nativeName": "অসমীয়া (भारत)",
|
||||
"path": "as_IN/as_IN"
|
||||
},
|
||||
"be-official": {
|
||||
"nativeName": "беларуская",
|
||||
"path": "be_BY/be-official"
|
||||
},
|
||||
"bg_BG": {
|
||||
"nativeName": "български",
|
||||
"path": "bg_BG/bg_BG"
|
||||
},
|
||||
"bn_BD": {
|
||||
"nativeName": "বাঙ্গালি (বাংলাদেশ)",
|
||||
"path": "bn_BD/bn_BD"
|
||||
},
|
||||
"bn_IN": {
|
||||
"nativeName": "বাঙ্গালি (ভারত)",
|
||||
"path": "bn_BD/bn_IN"
|
||||
},
|
||||
"bo": {
|
||||
"nativeName": "བོད་སྐད་",
|
||||
"path": "bo/bo"
|
||||
},
|
||||
"br_FR": {
|
||||
"nativeName": "breton (France)",
|
||||
"path": "br_FR/br_FR"
|
||||
},
|
||||
"bs_BA": {
|
||||
"nativeName": "bosanski",
|
||||
"path": "bs_BA/bs_BA"
|
||||
},
|
||||
"cs_CZ": {
|
||||
"nativeName": "čeština",
|
||||
"path": "cs_CZ/cs_CZ"
|
||||
},
|
||||
"da_DK": {
|
||||
"nativeName": "dansk",
|
||||
"path": "da_DK/da_DK"
|
||||
},
|
||||
"de_AT_frami": {
|
||||
"nativeName": "Deutsch (Österreich)",
|
||||
"path": "de/de_AT_frami"
|
||||
},
|
||||
"de_CH_frami": {
|
||||
"nativeName": "Deutsch (Schweiz)",
|
||||
"path": "de/de_CH_frami"
|
||||
},
|
||||
"de_DE_frami": {
|
||||
"nativeName": "Deutsch (Deutschland)",
|
||||
"path": "de/de_DE_frami"
|
||||
},
|
||||
"el_GR": {
|
||||
"nativeName": "Ελληνικά",
|
||||
"path": "el_GR/el_GR"
|
||||
},
|
||||
"en_AU": {
|
||||
"nativeName": "English (Australia)",
|
||||
"path": "en/en_AU"
|
||||
},
|
||||
"en_CA": {
|
||||
"nativeName": "English (Canada)",
|
||||
"path": "en/en_CA"
|
||||
},
|
||||
"en_GB": {
|
||||
"nativeName": "English (British)",
|
||||
"path": "en/en_GB"
|
||||
},
|
||||
"en_US": {
|
||||
"nativeName": "English (American)",
|
||||
"path": "en/en_US"
|
||||
},
|
||||
"en_ZA": {
|
||||
"nativeName": "English (Suid-Afrika)",
|
||||
"path": "en/en_ZA"
|
||||
},
|
||||
"eo": {
|
||||
"nativeName": "esperanto",
|
||||
"path": "eo/eo"
|
||||
},
|
||||
"es_AR": {
|
||||
"nativeName": "español (Argentina)",
|
||||
"path": "es/es_AR"
|
||||
},
|
||||
"es_BO": {
|
||||
"nativeName": "español (Bolivia)",
|
||||
"path": "es/es_BO"
|
||||
},
|
||||
"es_CL": {
|
||||
"nativeName": "español (Chile)",
|
||||
"path": "es/es_CL"
|
||||
},
|
||||
"es_CO": {
|
||||
"nativeName": "español (Colombia)",
|
||||
"path": "es/es_CO"
|
||||
},
|
||||
"es_CR": {
|
||||
"nativeName": "español (Costa Rica)",
|
||||
"path": "es/es_CR"
|
||||
},
|
||||
"es_CU": {
|
||||
"nativeName": "español (Cuba)",
|
||||
"path": "es/es_CU"
|
||||
},
|
||||
"es_DO": {
|
||||
"nativeName": "español (República Dominicana)",
|
||||
"path": "es/es_DO"
|
||||
},
|
||||
"es_EC": {
|
||||
"nativeName": "español (Ecuador)",
|
||||
"path": "es/es_EC"
|
||||
},
|
||||
"es_ES": {
|
||||
"nativeName": "español (España)",
|
||||
"path": "es/es_ES"
|
||||
},
|
||||
"es_GQ": {
|
||||
"nativeName": "español (Guinea Ecuatorial)",
|
||||
"path": "es/es_GQ"
|
||||
},
|
||||
"es_GT": {
|
||||
"nativeName": "español (Guatemala)",
|
||||
"path": "es/es_GT"
|
||||
},
|
||||
"es_HN": {
|
||||
"nativeName": "español (Honduras)",
|
||||
"path": "es/es_HN"
|
||||
},
|
||||
"es_MX": {
|
||||
"nativeName": "español (México)",
|
||||
"path": "es/es_MX"
|
||||
},
|
||||
"es_NI": {
|
||||
"nativeName": "español (Nicaragua)",
|
||||
"path": "es/es_NI"
|
||||
},
|
||||
"es_PA": {
|
||||
"nativeName": "español (Panamá)",
|
||||
"path": "es/es_PA"
|
||||
},
|
||||
"es_PE": {
|
||||
"nativeName": "español (Perú)",
|
||||
"path": "es/es_PE"
|
||||
},
|
||||
"es_PH": {
|
||||
"nativeName": "español (Pilipinas)",
|
||||
"path": "es/es_PH"
|
||||
},
|
||||
"es_PR": {
|
||||
"nativeName": "español (Puerto Rico)",
|
||||
"path": "es/es_PR"
|
||||
},
|
||||
"es_PY": {
|
||||
"nativeName": "español (Paraguai)",
|
||||
"path": "es/es_PY"
|
||||
},
|
||||
"es_SV": {
|
||||
"nativeName": "español (El Salvador)",
|
||||
"path": "es/es_SV"
|
||||
},
|
||||
"es_US": {
|
||||
"nativeName": "español (United States)",
|
||||
"path": "es/es_US"
|
||||
},
|
||||
"es_UY": {
|
||||
"nativeName": "español (Uruguay)",
|
||||
"path": "es/es_UY"
|
||||
},
|
||||
"es_VE": {
|
||||
"nativeName": "español (Venezuela)",
|
||||
"path": "es/es_VE"
|
||||
},
|
||||
"et_EE": {
|
||||
"nativeName": "eesti",
|
||||
"path": "et_EE/et_EE"
|
||||
},
|
||||
"fa-IR": {
|
||||
"nativeName": "فارسی",
|
||||
"path": "fa_IR/fa-IR"
|
||||
},
|
||||
"fr": {
|
||||
"nativeName": "français",
|
||||
"path": "fr_FR/fr"
|
||||
},
|
||||
"gd_GB": {
|
||||
"nativeName": "Gàidhlig",
|
||||
"path": "gd_GB/gd_GB"
|
||||
},
|
||||
"gl_ES": {
|
||||
"nativeName": "galego",
|
||||
"path": "gl/gl_ES"
|
||||
},
|
||||
"gu_IN": {
|
||||
"nativeName": "ગુજરાતી",
|
||||
"path": "gu_IN/gu_IN"
|
||||
},
|
||||
"he_IL": {
|
||||
"nativeName": "עברית",
|
||||
"path": "he_IL/he_IL"
|
||||
},
|
||||
"hi_IN": {
|
||||
"nativeName": "हिन्दी",
|
||||
"path": "hi_IN/hi_IN"
|
||||
},
|
||||
"hr_HR": {
|
||||
"nativeName": "hrvatski",
|
||||
"path": "hr_HR/hr_HR"
|
||||
},
|
||||
"hu_HU": {
|
||||
"nativeName": "magyar",
|
||||
"path": "hu_HU/hu_HU"
|
||||
},
|
||||
"id_ID": {
|
||||
"nativeName": "Indonesian",
|
||||
"path": "id/id_ID"
|
||||
},
|
||||
"is": {
|
||||
"nativeName": "íslenska",
|
||||
"path": "is/is"
|
||||
},
|
||||
"it_IT": {
|
||||
"nativeName": "italiano",
|
||||
"path": "it_IT/it_IT"
|
||||
},
|
||||
"kmr_Latn": {
|
||||
"nativeName": "Northern Kurdish",
|
||||
"path": "kmr_Latn/kmr_Latn"
|
||||
},
|
||||
"kn_IN": {
|
||||
"nativeName": "ಕನ್ನಡ",
|
||||
"path": "kn_IN/kn_IN"
|
||||
},
|
||||
"ko_KR": {
|
||||
"nativeName": "한국어",
|
||||
"path": "ko_KR/ko_KR"
|
||||
},
|
||||
"lo_LA": {
|
||||
"nativeName": "ລາວ",
|
||||
"path": "lo_LA/lo_LA"
|
||||
},
|
||||
"lt": {
|
||||
"nativeName": "lietuvių",
|
||||
"path": "lt_LT/lt"
|
||||
},
|
||||
"lv_LV": {
|
||||
"nativeName": "latviešu",
|
||||
"path": "lv_LV/lv_LV"
|
||||
},
|
||||
"mn_MN": {
|
||||
"nativeName": "монгол",
|
||||
"path": "mn_MN/mn_MN"
|
||||
},
|
||||
"mr_IN": {
|
||||
"nativeName": "मराठी",
|
||||
"path": "mr_IN/mr_IN"
|
||||
},
|
||||
"nb_NO": {
|
||||
"nativeName": "norsk bokmål",
|
||||
"path": "no/nb_NO"
|
||||
},
|
||||
"ne_NP": {
|
||||
"nativeName": "नेपाली",
|
||||
"path": "ne_NP/ne_NP"
|
||||
},
|
||||
"nl_NL": {
|
||||
"nativeName": "Nederlands",
|
||||
"path": "nl_NL/nl_NL"
|
||||
},
|
||||
"nn_NO": {
|
||||
"nativeName": "norsk nynorsk",
|
||||
"path": "no/nn_NO"
|
||||
},
|
||||
"oc_FR": {
|
||||
"nativeName": "occitan",
|
||||
"path": "oc_FR/oc_FR"
|
||||
},
|
||||
"or_IN": {
|
||||
"nativeName": "ଓଡ଼ିଆ",
|
||||
"path": "or_IN/or_IN"
|
||||
},
|
||||
"pa_IN": {
|
||||
"nativeName": "ਪੰਜਾਬੀ",
|
||||
"path": "pa_IN/pa_IN"
|
||||
},
|
||||
"pl_PL": {
|
||||
"nativeName": "polski",
|
||||
"path": "pl_PL/pl_PL"
|
||||
},
|
||||
"pt_BR": {
|
||||
"nativeName": "português (Brasil)",
|
||||
"path": "pt_BR/pt_BR"
|
||||
},
|
||||
"pt_PT": {
|
||||
"nativeName": "português europeu (Portugal)",
|
||||
"path": "pt_PT/pt_PT"
|
||||
},
|
||||
"ro_RO": {
|
||||
"nativeName": "română",
|
||||
"path": "ro/ro_RO"
|
||||
},
|
||||
"ru_RU": {
|
||||
"nativeName": "русский",
|
||||
"path": "ru_RU/ru_RU"
|
||||
},
|
||||
"sa_IN": {
|
||||
"nativeName": "संस्कृत भाषा",
|
||||
"path": "sa_IN/sa_IN"
|
||||
},
|
||||
"si_LK": {
|
||||
"nativeName": "සිංහල",
|
||||
"path": "si_LK/si_LK"
|
||||
},
|
||||
"sk_SK": {
|
||||
"nativeName": "slovenčina",
|
||||
"path": "sk_SK/sk_SK"
|
||||
},
|
||||
"sl_SI": {
|
||||
"nativeName": "slovenščina",
|
||||
"path": "sl_SI/sl_SI"
|
||||
},
|
||||
"sq_AL": {
|
||||
"nativeName": "shqip",
|
||||
"path": "sq_AL/sq_AL"
|
||||
},
|
||||
"sr": {
|
||||
"nativeName": "српски",
|
||||
"path": "sr/sr"
|
||||
},
|
||||
"sr-Latn": {
|
||||
"nativeName": "srpski",
|
||||
"path": "sr/sr-Latn"
|
||||
},
|
||||
"sv_FI": {
|
||||
"nativeName": "svenska (Finland)",
|
||||
"path": "sv_SE/sv_FI"
|
||||
},
|
||||
"sv_SE": {
|
||||
"nativeName": "svenska (Sverige)",
|
||||
"path": "sv_SE/sv_SE"
|
||||
},
|
||||
"sw_TZ": {
|
||||
"nativeName": "Kiswahili",
|
||||
"path": "sw_TZ/sw_TZ"
|
||||
},
|
||||
"ta_IN": {
|
||||
"nativeName": "தமிழ்",
|
||||
"path": "ta_IN/ta_IN"
|
||||
},
|
||||
"te_IN": {
|
||||
"nativeName": "తెలుగు",
|
||||
"path": "te_IN/te_IN"
|
||||
},
|
||||
"th_TH": {
|
||||
"nativeName": "ไทย",
|
||||
"path": "th_TH/th_TH"
|
||||
},
|
||||
"tr_TR": {
|
||||
"nativeName": "Türkçe",
|
||||
"path": "tr_TR/tr_TR"
|
||||
},
|
||||
"uk_UA": {
|
||||
"nativeName": "українська",
|
||||
"path": "uk_UA/uk_UA"
|
||||
},
|
||||
"vi_VN": {
|
||||
"nativeName": "Tiếng Việt",
|
||||
"path": "vi/vi_VN"
|
||||
}
|
||||
}
|
||||
@ -17,7 +17,6 @@
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtWebEngine
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Enums 1.1
|
||||
@ -253,9 +252,15 @@ QtObject {
|
||||
isCallFullscreen = fullScreenItems
|
||||
.filter(o => o.item.objectName === "callViewLoader")
|
||||
.length
|
||||
isWebFullscreen = fullScreenItems
|
||||
.filter(o => o.item instanceof WebEngineView)
|
||||
.length
|
||||
isWebFullscreen = WITH_WEBENGINE ? fullScreenItems
|
||||
.filter(o => o.item && (
|
||||
o.item.objectName === JamiQmlUtils.webEngineNames.mediaPreview ||
|
||||
o.item.objectName === JamiQmlUtils.webEngineNames.videoPreview ||
|
||||
o.item.objectName === JamiQmlUtils.webEngineNames.map ||
|
||||
o.item.objectName === JamiQmlUtils.webEngineNames.general ||
|
||||
o.item.objectName === JamiQmlUtils.webEngineNames.emojiPicker
|
||||
))
|
||||
.length : 0
|
||||
}
|
||||
|
||||
// Listen for a hangup combined with a fullscreen call state and
|
||||
|
||||
@ -37,18 +37,24 @@ ApplicationWindow {
|
||||
property bool isRTL: UtilsAdapter.isRTL
|
||||
LayoutMirroring.enabled: isRTL
|
||||
LayoutMirroring.childrenInherit: isRTL
|
||||
property var raiseWhenCalled: AppSettingsManager.getValue(Settings.RaiseWhenCalled)
|
||||
|
||||
onActiveFocusItemChanged: {
|
||||
focusOverlay.margin = -5;
|
||||
if (activeFocusItem && ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason))) {
|
||||
if (activeFocusItem.focusOnChild) {
|
||||
focusOverlay.parent = activeFocusItem.parent;
|
||||
} else if (activeFocusItem.dontShowFocusState) {
|
||||
focusOverlay.parent = null;
|
||||
if (activeFocusItem) {
|
||||
const goodReasonToChangeFocus = activeFocusItem instanceof ItemDelegate || ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason));
|
||||
if (goodReasonToChangeFocus) {
|
||||
if (activeFocusItem.focusOnChild) {
|
||||
focusOverlay.parent = activeFocusItem.parent;
|
||||
} else if (activeFocusItem.dontShowFocusState) {
|
||||
focusOverlay.parent = null;
|
||||
} else {
|
||||
if (activeFocusItem.showFocusMargin)
|
||||
focusOverlay.margin = 0;
|
||||
focusOverlay.parent = activeFocusItem;
|
||||
}
|
||||
} else {
|
||||
if (activeFocusItem.showFocusMargin)
|
||||
focusOverlay.margin = 0;
|
||||
focusOverlay.parent = activeFocusItem;
|
||||
focusOverlay.parent = null;
|
||||
}
|
||||
} else {
|
||||
focusOverlay.parent = null;
|
||||
@ -291,6 +297,26 @@ ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: UtilsAdapter
|
||||
function onRaiseWhenCalledChanged() {
|
||||
raiseWhenCalled = AppSettingsManager.getValue(Settings.RaiseWhenCalled);
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CallAdapter
|
||||
|
||||
function onCallStatusChanged(index, accountId, convUid) {
|
||||
//If we are starting a call with raiseWhenCalled activated
|
||||
if (raiseWhenCalled && index === Call.Status.INCOMING_RINGING) {
|
||||
appWindow.raise();
|
||||
appWindow.requestActivate();
|
||||
layoutManager.restoreApp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: MainApplication
|
||||
|
||||
|
||||
@ -34,8 +34,12 @@ AppSettingsManager::AppSettingsManager(QObject* parent)
|
||||
{
|
||||
for (int i = 0; i < static_cast<int>(Settings::Key::COUNT__); ++i) {
|
||||
auto key = static_cast<Settings::Key>(i);
|
||||
if (!settings_->contains(Settings::toString(key)))
|
||||
setValue(key, Settings::defaultValue(key));
|
||||
auto strKey= Settings::toString(key);
|
||||
// If the setting is written in the settings file and is equal to the default value,
|
||||
// remove it from the settings file.
|
||||
// This allow us to change default values without risking to remove user settings
|
||||
if ((settings_->contains(strKey)) && (settings_->value(strKey) == Settings::defaultValue(key)))
|
||||
settings_->remove(strKey);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -63,6 +63,8 @@ extern const QString defaultDownloadPath;
|
||||
X(WindowState, QWindow::AutomaticVisibility) \
|
||||
X(EnableExperimentalSwarm, false) \
|
||||
X(LANG, "SYSTEM") \
|
||||
X(SpellLang, {}) \
|
||||
X(EnableSpellCheck, true) \
|
||||
X(PluginStoreEndpoint, "https://plugins.jami.net") \
|
||||
X(PositionShareDuration, 15) \
|
||||
X(PositionShareLimit, true) \
|
||||
@ -74,7 +76,8 @@ extern const QString defaultDownloadPath;
|
||||
X(PttKeys, 32) \
|
||||
X(UseFramelessWindow, USE_FRAMELESS_WINDOW_DEFAULT) \
|
||||
X(EnableCrashReporting, true) \
|
||||
X(EnableAutomaticCrashReporting, false)
|
||||
X(EnableAutomaticCrashReporting, false) \
|
||||
X(RaiseWhenCalled, false)
|
||||
#if APPSTORE
|
||||
#define KEYS COMMON_KEYS
|
||||
#else
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
#include "appversionmanager.h"
|
||||
|
||||
#include "lrcinstance.h"
|
||||
#include "version.h"
|
||||
#include "version_info.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QTimer>
|
||||
@ -73,7 +73,7 @@ struct AppVersionManager::Impl : public QObject
|
||||
Q_EMIT parent_.updateCheckReplyReceived(false);
|
||||
return;
|
||||
}
|
||||
auto currentVersion = QString(VERSION_STRING).toULongLong();
|
||||
auto currentVersion = BUILD_VERSION_STRING.toULongLong();
|
||||
auto latestVersion = latestVersionString.toULongLong();
|
||||
const QString channelStr = isBeta ? "beta" : "stable";
|
||||
const auto newVersionFound = latestVersion > currentVersion;
|
||||
|
||||
@ -249,7 +249,7 @@ CallAdapter::onCallEnded(const QString& callId)
|
||||
}
|
||||
|
||||
void
|
||||
CallAdapter::onCallStatusChanged(const QString& callId, int code)
|
||||
CallAdapter::onCallStatusChanged(const QString& accountId, const QString& callId, int code)
|
||||
{
|
||||
Q_UNUSED(code)
|
||||
|
||||
@ -468,11 +468,14 @@ CallAdapter::onShowIncomingCallView(const QString& accountId, const QString& con
|
||||
showNotification(accountId, convInfo.uid);
|
||||
return;
|
||||
}
|
||||
if (!accountProperties.denySecondCall) {
|
||||
lrcInstance_->selectConversation(convInfo.uid, accountId);
|
||||
}
|
||||
} else {
|
||||
// finally, in this case, the conversation isn't selected yet
|
||||
// and there are no other special conditions, so just select the conversation
|
||||
lrcInstance_->selectConversation(convInfo.uid, accountId);
|
||||
}
|
||||
|
||||
// finally, in this case, the conversation isn't selected yet
|
||||
// and there are no other special conditions, so just select the conversation
|
||||
lrcInstance_->selectConversation(convInfo.uid, accountId);
|
||||
}
|
||||
|
||||
void
|
||||
@ -563,7 +566,7 @@ CallAdapter::connectCallModel(const QString& accountId)
|
||||
connect(accInfo.callModel.get(),
|
||||
&CallModel::callStatusChanged,
|
||||
this,
|
||||
QOverload<const QString&, int>::of(&CallAdapter::onCallStatusChanged),
|
||||
QOverload<const QString&, const QString&, int>::of(&CallAdapter::onCallStatusChanged),
|
||||
Qt::UniqueConnection);
|
||||
|
||||
connect(accInfo.callModel.get(),
|
||||
|
||||
@ -118,7 +118,7 @@ public Q_SLOTS:
|
||||
void onShowCallView(const QString& accountId, const QString& convUid);
|
||||
void onAccountChanged();
|
||||
void onCallStatusChanged(const QString& accountId, const QString& callId);
|
||||
void onCallStatusChanged(const QString& callId, int code);
|
||||
void onCallStatusChanged(const QString& accountId, const QString& callId, int code);
|
||||
void onCallAddedToConference(const QString& callId, const QString& conversationId, const QString& confId);
|
||||
void onCallStarted(const QString& callId);
|
||||
void onCallEnded(const QString& callId);
|
||||
|
||||
@ -135,7 +135,7 @@ PendingConferenceesListModel::connectSignals()
|
||||
callsStatusChanged_ = connect(currentCallModel,
|
||||
&CallModel::callStatusChanged,
|
||||
this,
|
||||
[this](const QString&, int) {
|
||||
[this](const QString&, const QString&, int) {
|
||||
Q_EMIT dataChanged(index(0, 0),
|
||||
index(rowCount() - 1),
|
||||
{Role::CallStatus});
|
||||
@ -401,6 +401,16 @@ CallOverlayModel::eventFilter(QObject* object, QEvent* event)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tab or BackTab key events should trigger a signal that we can use to
|
||||
// prevent the overlay from fading and to allow the user to navigate
|
||||
// through the controls.
|
||||
if (event->type() == QEvent::KeyPress && (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Tab)
|
||||
|| (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Backtab)) {
|
||||
Q_EMIT focusKeyPressed();
|
||||
// Don't absorb the event so that the focus can be changed
|
||||
// to the next or previous control.
|
||||
return false;
|
||||
}
|
||||
#ifndef HAVE_GLOBAL_PTT
|
||||
else if (event->type() == QEvent::KeyPress && listener_->getPttState()) {
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
|
||||
|
||||
@ -140,6 +140,7 @@ public:
|
||||
|
||||
Q_SIGNALS:
|
||||
void mouseMoved(QQuickItem* item);
|
||||
void focusKeyPressed();
|
||||
void pttKeyPressed();
|
||||
void pttKeyReleased();
|
||||
|
||||
|
||||
@ -78,8 +78,10 @@ Popup {
|
||||
contentItem: ColumnLayout {
|
||||
id: contentLayout
|
||||
|
||||
JamiPushButton {
|
||||
JamiPushButton { QWKSetParentHitTestVisible {}
|
||||
id: closeButton
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: JamiStrings.close
|
||||
|
||||
visible: closeButtonVisible
|
||||
|
||||
@ -117,7 +119,7 @@ Popup {
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredHeight: Math.min(contentHeight, root.height)
|
||||
Layout.preferredWidth: contentItem.childrenRect.width
|
||||
Layout.preferredWidth: contentItem.childrenRect.width + ScrollBar.vertical.width
|
||||
Layout.leftMargin: popupMargins
|
||||
Layout.rightMargin: popupMargins
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
@ -23,12 +23,12 @@ import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
SBSMessageBase {
|
||||
id: root
|
||||
id: rootDelegate
|
||||
|
||||
property var confId: ConfId
|
||||
property var currentCallId: CurrentCall.id
|
||||
component JoinCallButton: MaterialButton {
|
||||
visible: root.isActive && root.currentCallId !== root.confId
|
||||
visible: rootDelegate.isActive && rootDelegate.currentCallId !== rootDelegate.confId
|
||||
toolTipText: JamiStrings.joinCall
|
||||
color: JamiTheme.blackColor
|
||||
background.opacity: hovered ? 0.2 : 0.1
|
||||
@ -40,6 +40,20 @@ SBSMessageBase {
|
||||
textRightPadding: 9
|
||||
}
|
||||
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: {
|
||||
let name = isOutgoing ? JamiStrings.inReplyToYou : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
|
||||
return name + ": " + callLabel.text + " " + formattedDay;
|
||||
}
|
||||
Accessible.description: {
|
||||
let status = "";
|
||||
if (bubble.isEdited)
|
||||
status += JamiStrings.edited + " ";
|
||||
return status + (readers.length > 0 ? JamiStrings.readBy + " " + readers.map(function (uri) {
|
||||
return UtilsAdapter.getBestNameForUri(CurrentAccount.id, uri);
|
||||
}).join(", ") : "");
|
||||
}
|
||||
|
||||
property bool isRemoteImage
|
||||
|
||||
isOutgoing: Author === CurrentAccount.uri
|
||||
@ -48,17 +62,17 @@ SBSMessageBase {
|
||||
formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
|
||||
|
||||
bubble.border.color: CurrentConversation.color
|
||||
bubble.border.width: root.isActive ? 1.5 : 0
|
||||
bubble.border.width: rootDelegate.isActive ? 1.5 : 0
|
||||
bubble.color: JamiTheme.messageInBgColor
|
||||
bubble.opacity: 1
|
||||
|
||||
Connections {
|
||||
target: CurrentConversation
|
||||
enabled: root.isActive
|
||||
enabled: rootDelegate.isActive
|
||||
|
||||
function onActiveCallsChanged() {
|
||||
root.isActive = LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1;
|
||||
if (root.isActive) {
|
||||
rootDelegate.isActive = LRCInstance.indexOfActiveCall(rootDelegate.confId, ActionUri, DeviceId) !== -1;
|
||||
if (rootDelegate.isActive) {
|
||||
bubble.mask.border.color = CurrentConversation.color;
|
||||
bubble.mask.border.width = 1.5;
|
||||
bubble.mask.z = -2;
|
||||
@ -66,8 +80,8 @@ SBSMessageBase {
|
||||
}
|
||||
}
|
||||
|
||||
property bool isActive: LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1
|
||||
visible: isActive || root.confId === "" || Duration > 0
|
||||
property bool isActive: LRCInstance.indexOfActiveCall(rootDelegate.confId, ActionUri, DeviceId) !== -1
|
||||
visible: isActive || rootDelegate.confId === "" || Duration > 0
|
||||
|
||||
property var baseColor: JamiTheme.messageInBgColor
|
||||
|
||||
@ -76,7 +90,7 @@ SBSMessageBase {
|
||||
id: msg
|
||||
anchors.right: isOutgoing ? parent.right : undefined
|
||||
spacing: 10
|
||||
visible: root.visible
|
||||
visible: rootDelegate.visible
|
||||
|
||||
Image {
|
||||
id: statusIcon
|
||||
@ -84,10 +98,10 @@ SBSMessageBase {
|
||||
width: 10
|
||||
height: 10
|
||||
verticalAlignment: Qt.AlignVCenter
|
||||
visible: !root.isActive
|
||||
visible: !rootDelegate.isActive
|
||||
|
||||
source: {
|
||||
if (root.isOutgoing) {
|
||||
if (rootDelegate.isOutgoing) {
|
||||
if (Duration > 0)
|
||||
return "qrc:/icons/outgoing-call.svg";
|
||||
else
|
||||
@ -104,12 +118,11 @@ SBSMessageBase {
|
||||
effect: ColorOverlay {
|
||||
color: {
|
||||
if (Duration > 0)
|
||||
return UtilsAdapter.luma(root.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
|
||||
return JamiTheme.redColor
|
||||
return UtilsAdapter.luma(rootDelegate.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
|
||||
return JamiTheme.redColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Text {
|
||||
@ -120,11 +133,11 @@ SBSMessageBase {
|
||||
bottomPadding: 8
|
||||
|
||||
Layout.fillWidth: true
|
||||
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 */
|
||||
Layout.rightMargin: rootDelegate.isActive && rootDelegate.currentCallId !== rootDelegate.confId ? 0 : rootDelegate.timeWidth + 16
|
||||
Layout.leftMargin: rootDelegate.isActive ? 10 : -5 /* spacing is 10 and we want 5px with icon */
|
||||
|
||||
text: {
|
||||
if (root.isActive)
|
||||
if (rootDelegate.isActive)
|
||||
return JamiStrings.startedACall;
|
||||
return Body;
|
||||
}
|
||||
@ -136,7 +149,7 @@ SBSMessageBase {
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.MarkdownText
|
||||
|
||||
color: UtilsAdapter.luma(root.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
|
||||
color: UtilsAdapter.luma(rootDelegate.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
|
||||
}
|
||||
|
||||
JoinCallButton {
|
||||
@ -146,7 +159,7 @@ SBSMessageBase {
|
||||
Layout.bottomMargin: 4
|
||||
|
||||
text: JamiStrings.joinWithAudio
|
||||
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId, true)
|
||||
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, rootDelegate.confId, true)
|
||||
}
|
||||
|
||||
JoinCallButton {
|
||||
@ -156,20 +169,20 @@ SBSMessageBase {
|
||||
Layout.topMargin: 4
|
||||
Layout.bottomMargin: 4
|
||||
|
||||
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId)
|
||||
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, rootDelegate.confId)
|
||||
Layout.rightMargin: 4
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
opacity: 0
|
||||
Behavior on opacity {
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
}
|
||||
}
|
||||
Component.onCompleted: {
|
||||
bubble.timestampItem.visible = !root.isActive || root.currentCallId === root.confId;
|
||||
bubble.timestampItem.visible = !rootDelegate.isActive || rootDelegate.currentCallId === rootDelegate.confId;
|
||||
opacity = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,8 +21,8 @@ import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
Column {
|
||||
id: root
|
||||
Control {
|
||||
id: rootDelegate
|
||||
|
||||
property bool showTime: false
|
||||
property bool showDay: false
|
||||
@ -36,21 +36,41 @@ Column {
|
||||
height: timestampItem.height + textLabel.height
|
||||
spacing: 0
|
||||
|
||||
Item {
|
||||
Accessible.name: {
|
||||
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
|
||||
return name + ": " + Body + " " + formattedTime + " " + formattedDay;
|
||||
}
|
||||
Accessible.description: {
|
||||
let status = "";
|
||||
if (IsLastSent)
|
||||
status += JamiStrings.sent + " ";
|
||||
return status;
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
id: focusIndicator
|
||||
visible: rootDelegate.activeFocus
|
||||
border.color: JamiTheme.tintedBlue
|
||||
border.width: 2
|
||||
radius: 10
|
||||
color: "transparent"
|
||||
z: 1
|
||||
}
|
||||
|
||||
contentItem: Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: timestampItem.height + textLabel.height
|
||||
|
||||
TimestampInfo {
|
||||
id: timestampItem
|
||||
|
||||
showDay: root.showDay
|
||||
showTime: root.showTime
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedDay
|
||||
showDay: rootDelegate.showDay
|
||||
showTime: rootDelegate.showTime
|
||||
formattedTime: rootDelegate.formattedTime
|
||||
formattedDay: rootDelegate.formattedDay
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
|
||||
}
|
||||
|
||||
Label {
|
||||
@ -67,7 +87,7 @@ Column {
|
||||
}
|
||||
}
|
||||
opacity: 0
|
||||
Behavior on opacity {
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
}
|
||||
|
||||
@ -24,20 +24,32 @@ import net.jami.Constants 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
|
||||
Loader {
|
||||
id: root
|
||||
id: rootDelegate
|
||||
|
||||
property var mediaInfo
|
||||
property bool showTime
|
||||
property bool showDay
|
||||
property int timestamp: Timestamp
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(root.timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(root.timestamp)
|
||||
property string formattedTime: MessagesAdapter.getFormattedTime(rootDelegate.timestamp)
|
||||
property string formattedDay: MessagesAdapter.getFormattedDay(rootDelegate.timestamp)
|
||||
|
||||
property int seq: MsgSeq.single
|
||||
property string author: Author
|
||||
property string body: Body
|
||||
property var tid: TID
|
||||
property int transferStatus: TransferStatus
|
||||
|
||||
Accessible.name: {
|
||||
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
|
||||
return JamiStrings.dataTransfer + name + ": " + JamiStrings.status + TransferStatus + Body + " " + formattedTime + " " + formattedDay;
|
||||
}
|
||||
Accessible.description: {
|
||||
let status = "";
|
||||
if (IsLastSent)
|
||||
status += JamiStrings.sent + " ";
|
||||
return status;
|
||||
}
|
||||
|
||||
onTidChanged: {
|
||||
if (tid === "") {
|
||||
sourceComponent = deletedMsgComp;
|
||||
@ -48,7 +60,7 @@ Loader {
|
||||
sourceComponent = deletedMsgComp;
|
||||
return;
|
||||
} else if (transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED) {
|
||||
mediaInfo = MessagesAdapter.getMediaInfo(root.body);
|
||||
mediaInfo = MessagesAdapter.getMediaInfo(rootDelegate.body);
|
||||
if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE) {
|
||||
sourceComponent = localMediaMsgComp;
|
||||
return;
|
||||
@ -74,13 +86,13 @@ Loader {
|
||||
id: deletedItem
|
||||
|
||||
isOutgoing: Author === CurrentAccount.uri
|
||||
showTime: root.showTime
|
||||
seq: root.seq
|
||||
showTime: rootDelegate.showTime
|
||||
seq: rootDelegate.seq
|
||||
author: Author
|
||||
readers: Readers
|
||||
timestamp: root.timestamp
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedTime
|
||||
timestamp: rootDelegate.timestamp
|
||||
formattedTime: rootDelegate.formattedTime
|
||||
formattedDay: rootDelegate.formattedTime
|
||||
extraHeight: 0
|
||||
textContentWidth: textEditId.width
|
||||
textContentHeight: textEditId.height
|
||||
@ -122,34 +134,34 @@ Loader {
|
||||
id: dataTransferItem
|
||||
|
||||
transferId: Id
|
||||
property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
|
||||
property bool canOpen: root.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
|
||||
property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth - buttonsLoader.width - 24 - 6 - 24
|
||||
property var transferStats: MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus)
|
||||
property bool canOpen: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
|
||||
property real maxMsgWidth: rootDelegate.width - senderMargin - 2 * hPadding - avatarBlockWidth - buttonsLoader.width - 24 - 6 - 24
|
||||
|
||||
// Timer to update the translation bar
|
||||
Loader {
|
||||
id: timerLoader
|
||||
active: root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
|
||||
active: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
|
||||
sourceComponent: Timer {
|
||||
interval: 1000 // Update every second
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
transferStats = MessagesAdapter.getTransferStats(transferId, root.transferStatus);
|
||||
transferStats = MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isOutgoing: Author === CurrentAccount.uri
|
||||
showTime: root.showTime
|
||||
seq: root.seq
|
||||
showTime: rootDelegate.showTime
|
||||
seq: rootDelegate.seq
|
||||
author: Author
|
||||
location: Body
|
||||
transferName: TransferName
|
||||
readers: Readers
|
||||
timestamp: root.timestamp
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedTime
|
||||
timestamp: rootDelegate.timestamp
|
||||
formattedTime: rootDelegate.formattedTime
|
||||
formattedDay: rootDelegate.formattedTime
|
||||
extraHeight: progressBar.visible ? 25 : 0
|
||||
|
||||
innerContent.children: [
|
||||
@ -178,7 +190,7 @@ Loader {
|
||||
Layout.margins: 8
|
||||
|
||||
sourceComponent: {
|
||||
switch (root.transferStatus) {
|
||||
switch (rootDelegate.transferStatus) {
|
||||
case Interaction.TransferStatus.TRANSFER_CREATED:
|
||||
case Interaction.TransferStatus.TRANSFER_FINISHED:
|
||||
iconSource = JamiResources.link_black_24dp_svg;
|
||||
@ -225,7 +237,7 @@ Loader {
|
||||
normalColor: JamiTheme.chatviewBgColor
|
||||
imageColor: JamiTheme.chatviewButtonColor
|
||||
onClicked: {
|
||||
if (root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
|
||||
if (rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
|
||||
MessagesAdapter.cancelFile(transferId);
|
||||
} else {
|
||||
buttonsLoader.iconSource = JamiResources.connecting_black_24dp_svg;
|
||||
@ -287,7 +299,7 @@ Loader {
|
||||
ProgressBar {
|
||||
id: progressBar
|
||||
|
||||
visible: root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
|
||||
visible: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
|
||||
height: visible * implicitHeight
|
||||
value: transferStats.progress / transferStats.totalSize
|
||||
width: transferItem.width
|
||||
@ -305,15 +317,15 @@ Loader {
|
||||
|
||||
isOutgoing: Author === CurrentAccount.uri
|
||||
transferId: Id
|
||||
property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
|
||||
showTime: root.showTime
|
||||
seq: root.seq
|
||||
property var transferStats: MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus)
|
||||
showTime: rootDelegate.showTime
|
||||
seq: rootDelegate.seq
|
||||
author: Author
|
||||
location: Body
|
||||
transferName: TransferName
|
||||
readers: Readers
|
||||
formattedTime: MessagesAdapter.getFormattedTime(root.timestamp)
|
||||
formattedDay: MessagesAdapter.getFormattedDay(root.timestamp)
|
||||
formattedTime: MessagesAdapter.getFormattedTime(rootDelegate.timestamp)
|
||||
formattedDay: MessagesAdapter.getFormattedDay(rootDelegate.timestamp)
|
||||
|
||||
property real contentWidth
|
||||
|
||||
|
||||
370
src/app/commoncomponents/DictionaryInstallView.qml
Normal file
370
src/app/commoncomponents/DictionaryInstallView.qml
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../mainview/components"
|
||||
import "../settingsview/components"
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
// Search bar for filtering dictionaries
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: 0
|
||||
property int checkBoxWidth: 24
|
||||
|
||||
Component.onCompleted: Qt.callLater(dictionarySearchBar.setTextAreaFocus)
|
||||
|
||||
RowLayout {
|
||||
id: headerLayout
|
||||
width: parent.width
|
||||
Layout.preferredHeight: childrenRect.height
|
||||
|
||||
// Header title
|
||||
Searchbar {
|
||||
id: dictionarySearchBar
|
||||
|
||||
focus: true
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 55
|
||||
|
||||
placeHolderText: JamiStrings.searchTextLanguages
|
||||
Accessible.name: JamiStrings.searchTextLanguages
|
||||
Accessible.role: Accessible.EditableText
|
||||
Accessible.description: JamiStrings.searchAvailableTextLanguages
|
||||
|
||||
onSearchBarTextChanged: function (text) {
|
||||
dictionaryProxyModel.combinedFilterPattern = text;
|
||||
dictionaryProxyModel.invalidate();
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: JamiStrings.showInstalledDictionaries
|
||||
color: JamiTheme.faddedLastInteractionFontColor
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
|
||||
Layout.rightMargin: 0
|
||||
Layout.preferredHeight: 16
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
}
|
||||
|
||||
// Checkbox to filter installed dictionaries
|
||||
CheckBox {
|
||||
id: showInstalledOnlyCheckbox
|
||||
Accessible.name: JamiStrings.showInstalledDictionaries
|
||||
Accessible.role: Accessible.CheckBox
|
||||
Accessible.description: JamiStrings.showInstalledDictionariesDescription
|
||||
checked: false
|
||||
indicator: Image {
|
||||
anchors.centerIn: parent
|
||||
layer {
|
||||
enabled: true
|
||||
effect: ColorOverlay {
|
||||
color: JamiTheme.tintedBlue
|
||||
}
|
||||
mipmap: false
|
||||
smooth: true
|
||||
}
|
||||
width: checkBoxWidth
|
||||
height: checkBoxWidth
|
||||
source: showInstalledOnlyCheckbox.checked ? JamiResources.check_box_24dp_svg : JamiResources.check_box_outline_blank_24dp_svg
|
||||
}
|
||||
|
||||
Layout.preferredWidth: 55
|
||||
Layout.preferredHeight: 55
|
||||
Layout.rightMargin: 0
|
||||
}
|
||||
}
|
||||
|
||||
// Connect to listen for download failure and pop a simple dialog to inform the user
|
||||
Connections {
|
||||
target: SpellCheckAdapter
|
||||
function onDownloadFailed(locale) {
|
||||
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
|
||||
"title": JamiStrings.error,
|
||||
"infoText": JamiStrings.spellCheckDownloadFailed.arg(locale),
|
||||
"buttonTitles": [JamiStrings.optionOk],
|
||||
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
|
||||
"buttonRoles": [DialogButtonBox.AcceptRole]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
JamiListView {
|
||||
id: spellCheckDictionaryListView
|
||||
|
||||
width: parent.width
|
||||
Layout.fillHeight: true
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
id: dictionaryProxyModel
|
||||
sourceModel: SpellCheckAdapter.getDictionaryListModel()
|
||||
|
||||
property string combinedFilterPattern
|
||||
|
||||
filters: AllOf {
|
||||
AnyOf {
|
||||
// Filter by dictionary name
|
||||
RegExpFilter {
|
||||
roleName: "Locale"
|
||||
pattern: dictionaryProxyModel.combinedFilterPattern
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
// Filter by native name
|
||||
RegExpFilter {
|
||||
roleName: "NativeName"
|
||||
pattern: dictionaryProxyModel.combinedFilterPattern
|
||||
caseSensitivity: Qt.CaseInsensitive
|
||||
}
|
||||
}
|
||||
ValueFilter {
|
||||
roleName: "Installed"
|
||||
value: true
|
||||
enabled: showInstalledOnlyCheckbox.checked
|
||||
}
|
||||
}
|
||||
|
||||
sorters: [
|
||||
// Sort by locale alphabetically
|
||||
RoleSorter {
|
||||
roleName: "Locale"
|
||||
sortOrder: Qt.AscendingOrder
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
readonly property int itemMargins: 20
|
||||
topMargin: itemMargins / 2
|
||||
bottomMargin: itemMargins / 2
|
||||
|
||||
spacing: 8
|
||||
clip: true
|
||||
|
||||
delegate: ItemDelegate {
|
||||
id: dictionaryDelegate
|
||||
width: spellCheckDictionaryListView.width
|
||||
height: Math.max(JamiTheme.preferredFieldHeight, contentLayout.implicitHeight + 32)
|
||||
|
||||
background: Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width - spellCheckDictionaryListView.itemMargins
|
||||
height: parent.height
|
||||
color: JamiTheme.backgroundColor
|
||||
radius: JamiTheme.primaryRadius
|
||||
border.color: "transparent"
|
||||
border.width: 1
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
id: contentLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 16
|
||||
|
||||
// Dictionary info
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.leftMargin: 16
|
||||
spacing: 2
|
||||
|
||||
Text {
|
||||
id: dictionaryName
|
||||
Layout.fillWidth: true
|
||||
text: model.NativeName || ""
|
||||
color: JamiTheme.textColor
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
|
||||
font.weight: Font.Medium
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
Text {
|
||||
id: dictionaryLocale
|
||||
Layout.fillWidth: true
|
||||
text: model.Locale || ""
|
||||
color: JamiTheme.faddedLastInteractionFontColor
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 2
|
||||
elide: Text.ElideRight
|
||||
visible: text !== ""
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Installation status and action
|
||||
Item {
|
||||
Layout.preferredWidth: 100
|
||||
Layout.preferredHeight: 32
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
Layout.rightMargin: 16
|
||||
|
||||
// Install button for available dictionaries
|
||||
MaterialButton {
|
||||
id: installButton
|
||||
anchors.centerIn: parent
|
||||
width: 100
|
||||
height: 32
|
||||
Accessible.name: dictionaryName.text + " " + JamiStrings.install
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
text: JamiStrings.install
|
||||
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 1
|
||||
font.weight: Font.Medium
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
KeyNavigation.tab: {
|
||||
try {
|
||||
if (model.index < dictionaryProxyModel.count - 1) {
|
||||
var nextItem = spellCheckDictionaryListView.itemAtIndex(model.index + 1);
|
||||
if (nextItem) {
|
||||
var nextButton = nextItem.findChild("installButton") || nextItem.findChild("uninstallButton");
|
||||
return nextButton || null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.debug("KeyNavigation error handled:", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
spellCheckDictionaryListView.positionViewAtIndex(model.index, ListView.Contain);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (model.Locale) {
|
||||
SpellCheckAdapter.installDictionary(model.Locale);
|
||||
}
|
||||
}
|
||||
|
||||
visible: !model.Downloading && !model.Installed && model.Locale !== undefined && model.Locale !== ""
|
||||
}
|
||||
|
||||
// Uninstall button for installed dictionaries (not system dictionaries)
|
||||
MaterialButton {
|
||||
id: uninstallButton
|
||||
anchors.centerIn: parent
|
||||
width: 100
|
||||
height: 32
|
||||
|
||||
Accessible.name: dictionaryName.text + " " + JamiStrings.uninstall
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
text: JamiStrings.uninstall
|
||||
color: "#ff6666"
|
||||
hoveredColor: "#ff9999"
|
||||
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 1
|
||||
font.weight: Font.Medium
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
KeyNavigation.tab: {
|
||||
try {
|
||||
if (model.index < dictionaryProxyModel.count - 1) {
|
||||
var nextItem = spellCheckDictionaryListView.itemAtIndex(model.index + 1);
|
||||
if (nextItem) {
|
||||
var nextButton = nextItem.findChild("installButton") || nextItem.findChild("uninstallButton");
|
||||
return nextButton || null;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.debug("KeyNavigation error handled:", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
spellCheckDictionaryListView.positionViewAtIndex(model.index, ListView.Contain);
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (model.Locale) {
|
||||
SpellCheckAdapter.uninstallDictionary(model.Locale);
|
||||
}
|
||||
}
|
||||
|
||||
visible: !model.Downloading && model.Installed && !model.IsSystem && model.Locale !== undefined && model.Locale !== ""
|
||||
}
|
||||
|
||||
// System dictionary indicator
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
text: JamiStrings.systemDictionary
|
||||
color: JamiTheme.faddedLastInteractionFontColor
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 2
|
||||
visible: model.IsSystem
|
||||
}
|
||||
|
||||
// Downloading status indicator
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
visible: model.Downloading
|
||||
running: model.Downloading
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
// Use a custom animation for better UX
|
||||
Behavior on running {
|
||||
NumberAnimation {
|
||||
duration: 300
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Empty state for when no dictionaries are found
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: dictionaryProxyModel.count === 0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: 16
|
||||
width: parent.width * 0.8
|
||||
|
||||
// Big books emoji
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
text: "📚"
|
||||
font.pixelSize: 48
|
||||
opacity: 0.3
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.fillWidth: true
|
||||
text: dictionarySearchBar.textContent.length > 0 ? JamiStrings.noDictionariesFoundFor.arg(dictionarySearchBar.textContent) : JamiStrings.noDictionariesAvailable
|
||||
color: JamiTheme.faddedLastInteractionFontColor
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/app/commoncomponents/DictionaryManagerDialog.qml
Normal file
36
src/app/commoncomponents/DictionaryManagerDialog.qml
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2025 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.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../commoncomponents/contextmenu"
|
||||
|
||||
BaseModalDialog {
|
||||
id: root
|
||||
objectName: "dictionaryManagerDialog"
|
||||
|
||||
title: JamiStrings.dictionaryManager
|
||||
|
||||
popupContent: DictionaryInstallView {
|
||||
Accessible.name: JamiStrings.dictionaryManager
|
||||
Accessible.role: Accessible.PopupMenu
|
||||
width: 400
|
||||
height: 500
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,7 @@ import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
Column {
|
||||
id: root
|
||||
id: rootDelegate
|
||||
|
||||
property bool showTime: false
|
||||
property bool showDay: false
|
||||
@ -34,6 +34,18 @@ Column {
|
||||
spacing: 2
|
||||
topPadding: 12
|
||||
bottomPadding: 12
|
||||
|
||||
Accessible.name: {
|
||||
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
|
||||
return name + ": " + Body + " " + formattedTime + " " + formattedDay;
|
||||
}
|
||||
Accessible.description: {
|
||||
let status = "";
|
||||
if (IsLastSent)
|
||||
status += JamiStrings.sent + " ";
|
||||
return status;
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
width: parent.width
|
||||
@ -42,10 +54,10 @@ Column {
|
||||
TimestampInfo {
|
||||
id: timestampItem
|
||||
|
||||
showDay: root.showDay
|
||||
showTime: root.showTime
|
||||
formattedTime: root.formattedTime
|
||||
formattedDay: root.formattedDay
|
||||
showDay: rootDelegate.showDay
|
||||
showTime: rootDelegate.showTime
|
||||
formattedTime: rootDelegate.formattedTime
|
||||
formattedDay: rootDelegate.formattedDay
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
|
||||
@ -60,7 +72,7 @@ Column {
|
||||
}
|
||||
|
||||
opacity: 0
|
||||
Behavior on opacity {
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 100
|
||||
}
|
||||
|
||||
@ -28,6 +28,10 @@ Control {
|
||||
property string title: ""
|
||||
property string description: ""
|
||||
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: title
|
||||
Accessible.description: description
|
||||
|
||||
width: 190
|
||||
height: infos.implicitHeight
|
||||
|
||||
|
||||
@ -15,8 +15,13 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import QtQuick
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import net.jami.Models 1.1
|
||||
import "contextmenu"
|
||||
import "../mainview"
|
||||
import "../mainview/components"
|
||||
|
||||
ContextMenuAutoLoader {
|
||||
id: root
|
||||
@ -27,21 +32,19 @@ ContextMenuAutoLoader {
|
||||
property var selectionEnd
|
||||
property bool customizePaste: false
|
||||
property bool selectOnly: false
|
||||
property bool spellCheckEnabled: false
|
||||
property var suggestionList
|
||||
property var menuItemsLength
|
||||
property var language
|
||||
|
||||
signal contextMenuRequirePaste
|
||||
|
||||
property list<GeneralMenuItem> menuItems: [
|
||||
GeneralMenuItem {
|
||||
id: copy
|
||||
SpellLanguageContextMenu {
|
||||
id: spellLanguageContextMenu
|
||||
active: spellCheckEnabled
|
||||
}
|
||||
|
||||
canTrigger: true
|
||||
isActif: lineEditObj.selectedText.length
|
||||
itemName: JamiStrings.copy
|
||||
hasIcon: false
|
||||
onClicked: {
|
||||
lineEditObj.copy();
|
||||
}
|
||||
},
|
||||
property list<GeneralMenuItem> menuItems: [
|
||||
GeneralMenuItem {
|
||||
id: cut
|
||||
|
||||
@ -49,9 +52,16 @@ ContextMenuAutoLoader {
|
||||
isActif: lineEditObj.selectedText.length && !selectOnly
|
||||
itemName: JamiStrings.cut
|
||||
hasIcon: false
|
||||
onClicked: {
|
||||
lineEditObj.cut();
|
||||
}
|
||||
onClicked: lineEditObj.cut()
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: copy
|
||||
|
||||
canTrigger: true
|
||||
isActif: lineEditObj.selectedText.length
|
||||
itemName: JamiStrings.copy
|
||||
hasIcon: false
|
||||
onClicked: lineEditObj.copy()
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: paste
|
||||
@ -65,9 +75,77 @@ ContextMenuAutoLoader {
|
||||
else
|
||||
lineEditObj.paste();
|
||||
}
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: textLanguage
|
||||
canTrigger: spellCheckEnabled && SpellCheckAdapter.installedDictionaryCount > 0
|
||||
itemName: JamiStrings.textLanguage
|
||||
hasIcon: false
|
||||
onClicked: {
|
||||
spellLanguageContextMenu.openMenu();
|
||||
}
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: manageLanguages
|
||||
itemName: JamiStrings.dictionaryManager
|
||||
canTrigger: spellCheckEnabled
|
||||
hasIcon: false
|
||||
onClicked: {
|
||||
viewCoordinator.presentDialog(appWindow, "commoncomponents/DictionaryManagerDialog.qml");
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
ListView {
|
||||
model: ListModel {
|
||||
id: suggestionListModel
|
||||
}
|
||||
|
||||
Instantiator {
|
||||
model: suggestionListModel
|
||||
delegate: GeneralMenuItem {
|
||||
id: suggestion
|
||||
|
||||
canTrigger: true
|
||||
isActif: true
|
||||
itemName: model.name
|
||||
bold: true
|
||||
hasIcon: false
|
||||
onClicked: {
|
||||
replaceWord(model.name);
|
||||
}
|
||||
}
|
||||
|
||||
onObjectAdded: {
|
||||
menuItems.push(object);
|
||||
}
|
||||
|
||||
onObjectRemoved: {
|
||||
menuItems.splice(menuItemsLength, suggestionList.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function removeItems() {
|
||||
suggestionListModel.clear();
|
||||
suggestionList.length = 0;
|
||||
}
|
||||
|
||||
function addMenuItem(wordList) {
|
||||
menuItemsLength = menuItems.length; // Keep initial number of items for easier removal
|
||||
suggestionList = wordList;
|
||||
for (var i = 0; i < suggestionList.length; ++i) {
|
||||
suggestionListModel.append({
|
||||
"name": suggestionList[i]
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function replaceWord(word) {
|
||||
lineEditObj.remove(selectionStart, selectionEnd);
|
||||
lineEditObj.insert(lineEditObj.cursorPosition, word);
|
||||
}
|
||||
|
||||
function openMenuAt(mouseEvent) {
|
||||
if (lineEditObj.selectedText.length === 0 && selectOnly)
|
||||
return;
|
||||
@ -85,6 +163,12 @@ ContextMenuAutoLoader {
|
||||
function onOpened() {
|
||||
lineEditObj.select(selectionStart, selectionEnd);
|
||||
}
|
||||
function onClosed() {
|
||||
if (!suggestionList || suggestionList.length === 0) {
|
||||
return;
|
||||
}
|
||||
removeItems();
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: menuItemsToLoad = menuItems
|
||||
|
||||
@ -20,14 +20,11 @@ import QtQuick.Layouts
|
||||
import QtQuick.Controls
|
||||
import Qt.labs.platform
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
|
||||
import "../mainview/components"
|
||||
|
||||
|
||||
BaseModalDialog {
|
||||
id: root
|
||||
|
||||
@ -36,26 +33,27 @@ BaseModalDialog {
|
||||
property real buttonSize: 36
|
||||
property real imageSize: 25
|
||||
|
||||
|
||||
signal focusOnPreviousItem
|
||||
signal focusOnNextItem
|
||||
signal imageValidated
|
||||
signal imageTemporaryValidated
|
||||
signal imageRemoved
|
||||
signal imageTemporaryRemoved
|
||||
|
||||
function startBooth() {
|
||||
recordBox.openRecorder(true)
|
||||
recordBox.openRecorder(true);
|
||||
}
|
||||
|
||||
function stopBooth(){
|
||||
recordBox.closeRecorder()
|
||||
function stopBooth() {
|
||||
recordBox.closeRecorder();
|
||||
}
|
||||
|
||||
function focusOnNextPhotoBoothItem () {
|
||||
takePhotoButton.forceActiveFocus()
|
||||
function focusOnNextPhotoBoothItem() {
|
||||
takePhotoButton.forceActiveFocus();
|
||||
}
|
||||
|
||||
function focusOnPreviousPhotoBoothItem () {
|
||||
importButton.forceActiveFocus()
|
||||
function focusOnPreviousPhotoBoothItem() {
|
||||
importButton.forceActiveFocus();
|
||||
}
|
||||
|
||||
title: JamiStrings.selectImage
|
||||
@ -69,171 +67,165 @@ BaseModalDialog {
|
||||
isPhoto: true
|
||||
visible: false
|
||||
|
||||
onValidatePhoto: function(photo) {
|
||||
if (!root.newItem)
|
||||
AccountAdapter.setCurrentAccountAvatarBase64(photo)
|
||||
else{
|
||||
onValidatePhoto: function (photo) {
|
||||
if (!root.newItem) {
|
||||
AccountAdapter.setCurrentAccountAvatarBase64(photo);
|
||||
imageTemporaryValidated();
|
||||
} else {
|
||||
UtilsAdapter.setTempCreationImageFromString(photo, imageId);
|
||||
imageValidated();
|
||||
}
|
||||
root.close()
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
popupContent: RowLayout {
|
||||
id: buttonsRowLayout
|
||||
id: buttonsRowLayout
|
||||
|
||||
spacing: 18
|
||||
spacing: 18
|
||||
|
||||
JamiPushButton {
|
||||
id: takePhotoButton
|
||||
JamiPushButton {
|
||||
id: takePhotoButton
|
||||
Accessible.name: objectName
|
||||
|
||||
objectName: "takePhotoButton"
|
||||
objectName: "takePhotoButton"
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
|
||||
enabled: VideoDevices.listSize !== 0
|
||||
hoverEnabled: enabled
|
||||
enabled: VideoDevices.listSize !== 0
|
||||
hoverEnabled: enabled
|
||||
|
||||
normalColor: "transparent"
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
toolTipText: JamiStrings.takePhoto
|
||||
source: JamiResources.add_a_photo_black_24dp_svg
|
||||
normalColor: "transparent"
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
toolTipText: JamiStrings.takePhoto
|
||||
source: JamiResources.add_a_photo_black_24dp_svg
|
||||
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter ||
|
||||
keyEvent.key === Qt.Key_Return) {
|
||||
clicked()
|
||||
keyEvent.accepted = true
|
||||
} else if (keyEvent.key === Qt.Key_Up) {
|
||||
root.focusOnPreviousItem()
|
||||
keyEvent.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.tab: {
|
||||
if (clearButton.visible)
|
||||
return clearButton
|
||||
return importButton
|
||||
}
|
||||
KeyNavigation.down: KeyNavigation.tab
|
||||
|
||||
onClicked: {
|
||||
recordBox.parent = buttonsRowLayout
|
||||
startBooth()
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
|
||||
clicked();
|
||||
keyEvent.accepted = true;
|
||||
} else if (keyEvent.key === Qt.Key_Up) {
|
||||
root.focusOnPreviousItem();
|
||||
keyEvent.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
JamiPushButton {
|
||||
id: importButton
|
||||
KeyNavigation.tab: {
|
||||
if (clearButton.visible)
|
||||
return clearButton;
|
||||
return importButton;
|
||||
}
|
||||
KeyNavigation.down: KeyNavigation.tab
|
||||
|
||||
objectName: "photoboothViewImportButton"
|
||||
onClicked: {
|
||||
recordBox.parent = buttonsRowLayout;
|
||||
startBooth();
|
||||
}
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: parent.visible
|
||||
JamiPushButton {
|
||||
id: importButton
|
||||
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
objectName: "photoboothViewImportButton"
|
||||
|
||||
normalColor: "transparent"
|
||||
source: JamiResources.add_photo_alternate_black_24dp_svg
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
toolTipText: JamiStrings.importFromFile
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
visible: parent.visible
|
||||
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter ||
|
||||
keyEvent.key === Qt.Key_Return) {
|
||||
clicked()
|
||||
keyEvent.accepted = true
|
||||
} else if (keyEvent.key === Qt.Key_Down ||
|
||||
keyEvent.key === Qt.Key_Tab) {
|
||||
clearButton.forceActiveFocus()
|
||||
keyEvent.accepted = true
|
||||
}
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
|
||||
Accessible.name: objectName
|
||||
|
||||
normalColor: "transparent"
|
||||
source: JamiResources.add_photo_alternate_black_24dp_svg
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
toolTipText: JamiStrings.importFromFile
|
||||
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
|
||||
clicked();
|
||||
keyEvent.accepted = true;
|
||||
} else if (keyEvent.key === Qt.Key_Down || keyEvent.key === Qt.Key_Tab) {
|
||||
clearButton.forceActiveFocus();
|
||||
keyEvent.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
KeyNavigation.up: takePhotoButton
|
||||
KeyNavigation.up: takePhotoButton
|
||||
|
||||
onClicked: {
|
||||
stopBooth()
|
||||
var dlg = viewCoordinator.presentDialog(
|
||||
appWindow,
|
||||
"commoncomponents/JamiFileDialog.qml",
|
||||
{
|
||||
title: JamiStrings.selectProfilePicture,
|
||||
fileMode: JamiFileDialog.OpenFile,
|
||||
folder: StandardPaths.writableLocation(
|
||||
StandardPaths.PicturesLocation),
|
||||
nameFilters: [JamiStrings.imageFiles,
|
||||
JamiStrings.allFiles]
|
||||
})
|
||||
dlg.fileAccepted.connect(function(file) {
|
||||
var filePath = UtilsAdapter.getAbsPath(file)
|
||||
onClicked: {
|
||||
stopBooth();
|
||||
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
|
||||
title: JamiStrings.selectProfilePicture,
|
||||
fileMode: JamiFileDialog.OpenFile,
|
||||
folder: StandardPaths.writableLocation(StandardPaths.PicturesLocation),
|
||||
nameFilters: [JamiStrings.imageFiles, JamiStrings.allFiles]
|
||||
});
|
||||
dlg.fileAccepted.connect(function (file) {
|
||||
var filePath = UtilsAdapter.getAbsPath(file);
|
||||
if (!root.newItem) {
|
||||
AccountAdapter.setCurrentAccountAvatarFile(filePath)
|
||||
AccountAdapter.setCurrentAccountAvatarFile(filePath);
|
||||
imageTemporaryValidated();
|
||||
} else {
|
||||
UtilsAdapter.setTempCreationImageFromFile(filePath, root.imageId);
|
||||
imageValidated();
|
||||
}
|
||||
root.close()
|
||||
})
|
||||
root.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
JamiPushButton {
|
||||
id: clearButton
|
||||
|
||||
objectName: "photoboothViewClearButton"
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
|
||||
normalColor: "transparent"
|
||||
source: JamiResources.remove_circle_outline_black_24dp_svg
|
||||
toolTipText: JamiStrings.removeImage
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
|
||||
visible: {
|
||||
if (!newItem && LRCInstance.currentAccountAvatarSet)
|
||||
return true;
|
||||
if (newItem && UtilsAdapter.tempCreationImage(imageId).length !== 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
KeyNavigation.up: importButton
|
||||
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
|
||||
clicked();
|
||||
importButton.forceActiveFocus();
|
||||
keyEvent.accepted = true;
|
||||
} else if (keyEvent.key === Qt.Key_Down || keyEvent.key === Qt.Key_Tab) {
|
||||
btnCancel.forceActiveFocus();
|
||||
keyEvent.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
JamiPushButton {
|
||||
id: clearButton
|
||||
|
||||
objectName: "photoboothViewClearButton"
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
height: buttonSize
|
||||
width: buttonSize
|
||||
|
||||
normalColor: "transparent"
|
||||
source: JamiResources.remove_circle_outline_black_24dp_svg
|
||||
toolTipText: JamiStrings.removeImage
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
|
||||
visible: {
|
||||
if (!newItem && LRCInstance.currentAccountAvatarSet)
|
||||
return true
|
||||
if (newItem && UtilsAdapter.tempCreationImage(imageId).length !== 0)
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
KeyNavigation.up: importButton
|
||||
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
if (keyEvent.key === Qt.Key_Enter ||
|
||||
keyEvent.key === Qt.Key_Return) {
|
||||
clicked()
|
||||
importButton.forceActiveFocus()
|
||||
keyEvent.accepted = true
|
||||
} else if (keyEvent.key === Qt.Key_Down ||
|
||||
keyEvent.key === Qt.Key_Tab) {
|
||||
btnCancel.forceActiveFocus()
|
||||
keyEvent.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
if (!root.newItem)
|
||||
AccountAdapter.setCurrentAccountAvatarBase64()
|
||||
else {
|
||||
UtilsAdapter.setTempCreationImageFromString("", imageId);
|
||||
imageRemoved();
|
||||
}
|
||||
visible = false
|
||||
stopBooth()
|
||||
root.close()
|
||||
onClicked: {
|
||||
if (!root.newItem) {
|
||||
AccountAdapter.setCurrentAccountAvatarBase64();
|
||||
imageTemporaryRemoved();
|
||||
} else {
|
||||
UtilsAdapter.setTempCreationImageFromString("", imageId);
|
||||
imageRemoved();
|
||||
}
|
||||
visible = false;
|
||||
stopBooth();
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -37,12 +37,16 @@ Row {
|
||||
|
||||
SystemButton {
|
||||
id: minButton
|
||||
Accessible.name: JamiStrings.minimize
|
||||
Accessible.role: Accessible.Button
|
||||
source: JamiResources.window_bar_minimize_svg
|
||||
onClicked: appWindow.showMinimized()
|
||||
}
|
||||
|
||||
SystemButton {
|
||||
id: maxButton
|
||||
Accessible.name: JamiStrings.maximize
|
||||
Accessible.role: Accessible.Button
|
||||
source: appWindow.visibility === Window.Maximized ?
|
||||
JamiResources.window_bar_restore_svg :
|
||||
JamiResources.window_bar_maximize_svg
|
||||
@ -53,6 +57,8 @@ Row {
|
||||
|
||||
SystemButton {
|
||||
id: closeButton
|
||||
Accessible.name: JamiStrings.closeApplication
|
||||
Accessible.role: Accessible.Button
|
||||
source: JamiResources.window_bar_close_svg
|
||||
baseColor: "#e81123"
|
||||
onClicked: appWindow.close()
|
||||
|
||||
@ -24,6 +24,7 @@ import net.jami.Constants 1.1
|
||||
|
||||
Control {
|
||||
id: root
|
||||
Accessible.role: Accessible.StaticText
|
||||
|
||||
property alias avatarBlockWidth: avatarBlock.width
|
||||
property alias innerContent: innerContent
|
||||
@ -64,6 +65,7 @@ Control {
|
||||
property bool bigMsg
|
||||
property bool timeUnderBubble: false
|
||||
property var type: Type
|
||||
property var shouldBeVisible: msgRowlayout.msgHovered || root.activeFocus || reply.activeFocus || more.activeFocus || share.activeFocus
|
||||
|
||||
// If the ListView attached properties are not available,
|
||||
// then the root delegate is likely a Loader.
|
||||
@ -81,6 +83,16 @@ Control {
|
||||
rightPadding: hPadding
|
||||
leftPadding: hPadding
|
||||
|
||||
background: Rectangle {
|
||||
id: focusIndicator
|
||||
visible: rootDelegate.activeFocus
|
||||
radius: 4
|
||||
border.color: JamiTheme.tintedBlue
|
||||
border.width: 2
|
||||
color: "transparent"
|
||||
z: 1
|
||||
}
|
||||
|
||||
contentItem: ColumnLayout {
|
||||
id: mainColumnLayout
|
||||
|
||||
@ -142,6 +154,7 @@ Control {
|
||||
RowLayout {
|
||||
id: replyToLayout
|
||||
|
||||
spacing: replyItem.isSelf ? 2 : 4
|
||||
Layout.alignment: isOutgoing ? Qt.AlignRight : Qt.AlignLeft
|
||||
property var replyUserName: UtilsAdapter.getBestNameForUri(CurrentAccount.id, ReplyToAuthor)
|
||||
|
||||
@ -185,7 +198,7 @@ Control {
|
||||
text: textMetricsUsername2.elidedText
|
||||
TextMetrics {
|
||||
id: textMetricsUsername2
|
||||
text: replyItem.isSelf ? JamiStrings.inReplyToMe : replyToLayout.replyUserName
|
||||
text: replyItem.isSelf ? JamiStrings.inReplyToYou : replyToLayout.replyUserName
|
||||
elideWidth: 200
|
||||
elide: Qt.ElideMiddle
|
||||
}
|
||||
@ -300,7 +313,7 @@ Control {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: isOutgoing ? optionButtonItem.right : undefined
|
||||
anchors.left: !isOutgoing ? optionButtonItem.left : undefined
|
||||
visible: msgRowlayout.msgHovered
|
||||
visible: shouldBeVisible
|
||||
source: JamiResources.more_vert_24dp_svg
|
||||
width: optionButtonItem.width / 4
|
||||
height: optionButtonItem.height
|
||||
@ -310,7 +323,7 @@ Control {
|
||||
|
||||
function setBindings() {
|
||||
more.isOpen = false;
|
||||
visible = Qt.binding(() => msgRowlayout.msgHovered);
|
||||
visible = Qt.binding(() => shouldBeVisible);
|
||||
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
|
||||
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
|
||||
}
|
||||
@ -355,7 +368,7 @@ Control {
|
||||
anchors.rightMargin: 5
|
||||
anchors.right: isOutgoing ? more.left : undefined
|
||||
anchors.left: !isOutgoing ? more.right : undefined
|
||||
visible: msgRowlayout.msgHovered
|
||||
visible: shouldBeVisible
|
||||
|
||||
onClicked: {
|
||||
MessagesAdapter.editId = "";
|
||||
@ -379,13 +392,14 @@ Control {
|
||||
anchors.rightMargin: 5
|
||||
anchors.right: isOutgoing ? reply.left : undefined
|
||||
anchors.left: !isOutgoing ? reply.right : undefined
|
||||
visible: msgRowlayout.msgHovered
|
||||
|
||||
visible: shouldBeVisible
|
||||
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(() => msgRowlayout.msgHovered);
|
||||
visible = Qt.binding(() => shouldBeVisible);
|
||||
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
|
||||
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
|
||||
}
|
||||
|
||||
@ -23,7 +23,7 @@ import QtQuick.Layouts
|
||||
Rectangle {
|
||||
property alias name: label.text
|
||||
property bool stretchParent: false
|
||||
property string tag: parent.toString()
|
||||
property string tag: parent.toString() + " (w:" + width + ", h: " + height + ")"
|
||||
signal moveX(real dx)
|
||||
signal moveY(real dy)
|
||||
property real ox: 0
|
||||
|
||||
@ -50,11 +50,14 @@ ComboBox {
|
||||
|
||||
contentItem: Text {
|
||||
text: {
|
||||
if (index < 0)
|
||||
if (index < 0 || !model)
|
||||
return '';
|
||||
var currentItem = root.delegateModel.items.get(index);
|
||||
const value = currentItem.model[root.textRole];
|
||||
return value === undefined ? '' : value.toString();
|
||||
|
||||
if (root.textRole && model[root.textRole] !== undefined) {
|
||||
return model[root.textRole].toString();
|
||||
}
|
||||
|
||||
return model.display !== undefined ? model.display.toString() : '';
|
||||
}
|
||||
|
||||
color: hovered ? JamiTheme.comboboxTextColorHovered : JamiTheme.textColor
|
||||
@ -80,7 +83,7 @@ ComboBox {
|
||||
|
||||
source: popup.visible ? JamiResources.expand_less_24dp_svg : JamiResources.expand_more_24dp_svg
|
||||
|
||||
color: JamiTheme.comboboxIconColor
|
||||
color: root.enabled ? JamiTheme.comboboxIconColor : "grey"
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
@ -92,7 +95,7 @@ ComboBox {
|
||||
anchors.rightMargin: root.indicator.width * 2
|
||||
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
|
||||
text: root.displayText
|
||||
color: JamiTheme.comboboxTextColor
|
||||
color: root.enabled ? JamiTheme.comboboxTextColor : "grey"
|
||||
font.weight: Font.Medium
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
@ -104,7 +107,11 @@ ComboBox {
|
||||
color: JamiTheme.transparentColor
|
||||
implicitWidth: 120
|
||||
implicitHeight: contentItem.implicitHeight + JamiTheme.buttontextHeightMargin
|
||||
border.color: popup.visible ? JamiTheme.comboboxBorderColorActive : JamiTheme.comboboxBorderColor
|
||||
border.color: root.enabled ?
|
||||
(popup.visible ?
|
||||
JamiTheme.comboboxBorderColorActive :
|
||||
JamiTheme.comboboxBorderColor) :
|
||||
"grey"
|
||||
border.width: root.visualFocus ? 2 : 1
|
||||
radius: 5
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import "contextmenu"
|
||||
|
||||
BaseContextMenu {
|
||||
id: root
|
||||
|
||||
property var modelList
|
||||
signal audioRecordMessageButtonClicked
|
||||
signal videoRecordMessageButtonClicked
|
||||
@ -31,35 +32,63 @@ BaseContextMenu {
|
||||
GeneralMenuItem {
|
||||
id: audioMessage
|
||||
|
||||
Accessible.role: Accessible.MenuItem
|
||||
Accessible.name: itemName
|
||||
focusPolicy: Qt.StrongFocus
|
||||
Keys.onReturnPressed: clicked()
|
||||
|
||||
canTrigger: true
|
||||
iconSource: JamiResources.message_audio_black_24dp_svg
|
||||
itemName: JamiStrings.leaveAudioMessage
|
||||
onClicked: {
|
||||
root.audioRecordMessageButtonClicked();
|
||||
root.close()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: videoMessage
|
||||
KeyNavigation.backtab: shareLocation
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: videoMessage
|
||||
|
||||
Accessible.role: Accessible.MenuItem
|
||||
Accessible.name: itemName
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
Keys.onReturnPressed: clicked()
|
||||
|
||||
canTrigger: true
|
||||
iconSource: JamiResources.message_video_black_24dp_svg
|
||||
itemName: JamiStrings.leaveVideoMessage
|
||||
|
||||
isActif: VideoDevices.listSize !== 0
|
||||
|
||||
onClicked: {
|
||||
root.videoRecordMessageButtonClicked();
|
||||
root.close()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: shareLocation
|
||||
KeyNavigation.backtab: audioMessage
|
||||
},
|
||||
GeneralMenuItem {
|
||||
id: shareLocation
|
||||
|
||||
Accessible.role: Accessible.MenuItem
|
||||
Accessible.name: itemName
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
Keys.onReturnPressed: clicked()
|
||||
|
||||
canTrigger: true
|
||||
iconSource: JamiResources.localisation_sharing_send_pin_svg
|
||||
itemName: JamiStrings.shareLocation
|
||||
onClicked: {
|
||||
root.showMapClicked();
|
||||
root.close()
|
||||
}
|
||||
|
||||
KeyNavigation.tab: audioMessage
|
||||
KeyNavigation.backtab: videoMessage
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
78
src/app/commoncomponents/SpellLanguageContextMenu.qml
Normal file
78
src/app/commoncomponents/SpellLanguageContextMenu.qml
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2020-2025 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 net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Models 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import "contextmenu"
|
||||
import "../mainview"
|
||||
import "../mainview/components"
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
ContextMenuAutoLoader {
|
||||
id: root
|
||||
|
||||
signal languageChanged
|
||||
|
||||
function openMenuAt(mouseEvent) {
|
||||
x = mouseEvent.x;
|
||||
y = mouseEvent.y;
|
||||
root.openMenu();
|
||||
}
|
||||
|
||||
onOpenRequested: {
|
||||
// Create the menu items from the installed dictionaries
|
||||
menuItemsToLoad = generateMenuItems();
|
||||
}
|
||||
|
||||
function generateMenuItems() {
|
||||
var menuItems = [];
|
||||
// Create new menu items
|
||||
var dictionaries = SpellCheckAdapter.getInstalledDictionaries();
|
||||
var keys = Object.keys(dictionaries);
|
||||
for (var i = 0; i < keys.length; ++i) {
|
||||
const locale = keys[i];
|
||||
const nativeName = dictionaries[keys[i]];
|
||||
var menuItem = Qt.createComponent("qrc:/commoncomponents/contextmenu/GeneralMenuItem.qml", Component.PreferSynchronous);
|
||||
if (menuItem.status !== Component.Ready) {
|
||||
console.error("Error loading component:", menuItem.errorString());
|
||||
continue;
|
||||
}
|
||||
let menuItemObject = menuItem.createObject(root, {
|
||||
"parent": root,
|
||||
"canTrigger": true,
|
||||
"isActif": true,
|
||||
"itemName": nativeName,
|
||||
"hasIcon": false,
|
||||
"content": locale,
|
||||
"bold": UtilsAdapter.getAppValue(Settings.SpellLang) === locale
|
||||
});
|
||||
if (menuItemObject === null) {
|
||||
console.error("Error creating menu item:", menuItem.errorString());
|
||||
continue;
|
||||
}
|
||||
menuItemObject.clicked.connect(function () {
|
||||
const locale = menuItemObject.content;
|
||||
SpellCheckAdapter.setDictionary(locale);
|
||||
});
|
||||
// Log the object pointer
|
||||
menuItems.push(menuItemObject);
|
||||
}
|
||||
return menuItems;
|
||||
}
|
||||
}
|
||||
@ -24,7 +24,21 @@ import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
|
||||
SBSMessageBase {
|
||||
id: root
|
||||
id: rootDelegate
|
||||
|
||||
Accessible.role: Accessible.StaticText
|
||||
Accessible.name: {
|
||||
let name = isOutgoing ? JamiStrings.inReplyToYou : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
|
||||
return name + ": " + Body + " " + formattedTime;
|
||||
}
|
||||
Accessible.description: {
|
||||
let status = "";
|
||||
if (bubble.isEdited)
|
||||
status += JamiStrings.edited + " ";
|
||||
return status + (readers.length > 0 ? JamiStrings.readBy + " " + readers.map(function (uri) {
|
||||
return UtilsAdapter.getBestNameForUri(CurrentAccount.id, uri);
|
||||
}).join(", ") : "");
|
||||
}
|
||||
|
||||
property bool isRemoteImage
|
||||
property bool isEmojiOnly: IsEmojiOnly
|
||||
@ -34,11 +48,11 @@ SBSMessageBase {
|
||||
Connections {
|
||||
target: bubble
|
||||
function onColorChanged(color) {
|
||||
root.colorUrl = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark;
|
||||
root.colorText = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
|
||||
rootDelegate.colorUrl = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark;
|
||||
rootDelegate.colorText = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
|
||||
// Update parsed body with correct colors
|
||||
if (Body !== "")
|
||||
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), root.colorUrl, bubble.color);
|
||||
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), rootDelegate.colorUrl, bubble.color);
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +67,7 @@ SBSMessageBase {
|
||||
textContentWidth: textEditId.width
|
||||
textContentHeight: textEditId.height
|
||||
|
||||
bigMsg: textContentWidth >= (2 / 3) * root.maxMsgWidth || extraContent.active
|
||||
bigMsg: textContentWidth >= (2 / 3) * rootDelegate.maxMsgWidth || extraContent.active
|
||||
|
||||
innerContent.children: [
|
||||
TextEdit {
|
||||
@ -63,10 +77,10 @@ SBSMessageBase {
|
||||
topPadding: bubble.isDeleted ? 6 : 10
|
||||
bottomPadding: bubble.isDeleted ? 6 : 10
|
||||
anchors.right: isOutgoing ? parent.right : undefined
|
||||
anchors.rightMargin: isOutgoing && !isEmojiOnly && !bigMsg ? root.timeWidth + root.editedWidth : 0
|
||||
anchors.rightMargin: isOutgoing && !isEmojiOnly && !bigMsg ? rootDelegate.timeWidth + rootDelegate.editedWidth : 0
|
||||
text: {
|
||||
if (Body !== "" && ParsedBody.length === 0) {
|
||||
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), root.colorUrl, bubble.color);
|
||||
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), rootDelegate.colorUrl, bubble.color);
|
||||
return "";
|
||||
}
|
||||
if (ParsedBody !== "")
|
||||
@ -82,11 +96,11 @@ SBSMessageBase {
|
||||
|
||||
width: {
|
||||
if (extraContent.active)
|
||||
Math.max(extraContent.width, Math.min((2 / 3) * root.maxMsgWidth, implicitWidth - avatarBlockWidth, extraContent.minSize) - senderMargin);
|
||||
Math.max(extraContent.width, Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth - avatarBlockWidth, extraContent.minSize) - senderMargin);
|
||||
else if (isEmojiOnly)
|
||||
Math.min((2 / 3) * root.maxMsgWidth, implicitWidth, innerContent.width - senderMargin - (innerContent.width - senderMargin) % (JamiTheme.chatviewEmojiSize + 2));
|
||||
Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth, innerContent.width - senderMargin - (innerContent.width - senderMargin) % (JamiTheme.chatviewEmojiSize + 2));
|
||||
else
|
||||
Math.min((2 / 3) * root.maxMsgWidth, implicitWidth + 5, innerContent.width - senderMargin + 5);
|
||||
Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth + 5, innerContent.width - senderMargin + 5);
|
||||
}
|
||||
|
||||
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
|
||||
@ -96,7 +110,7 @@ SBSMessageBase {
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: Text.RichText
|
||||
clip: true
|
||||
onLinkHovered: root.hoveredLink = hoveredLink
|
||||
onLinkHovered: rootDelegate.hoveredLink = hoveredLink
|
||||
onLinkActivated: Qt.openUrlExternally(new URL(hoveredLink))
|
||||
readOnly: true
|
||||
color: (ParsedBody !== "") ? getBaseColor() : (UtilsAdapter.luma(bubble.color) ? "white" : "dark")
|
||||
@ -150,7 +164,7 @@ SBSMessageBase {
|
||||
HoverHandler {
|
||||
target: previewContent
|
||||
onHoveredChanged: {
|
||||
root.hoveredLink = hovered ? LinkPreviewInfo.url : "";
|
||||
rootDelegate.hoveredLink = hovered ? LinkPreviewInfo.url : "";
|
||||
}
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
||||
@ -204,7 +218,7 @@ SBSMessageBase {
|
||||
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: TextEdit.RichText
|
||||
color: root.colorText
|
||||
color: rootDelegate.colorText
|
||||
visible: LinkPreviewInfo.title.length > 0
|
||||
text: LinkPreviewInfo.title
|
||||
lineHeight: 1.3
|
||||
@ -217,9 +231,9 @@ SBSMessageBase {
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: TextEdit.RichText
|
||||
visible: LinkPreviewInfo.description.length > 0
|
||||
font.underline: root.hoveredLink
|
||||
font.underline: rootDelegate.hoveredLink
|
||||
text: LinkPreviewInfo.description
|
||||
color: root.colorUrl
|
||||
color: rootDelegate.colorUrl
|
||||
lineHeight: 1.3
|
||||
}
|
||||
Label {
|
||||
@ -229,7 +243,7 @@ SBSMessageBase {
|
||||
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
|
||||
renderType: Text.NativeRendering
|
||||
textFormat: TextEdit.RichText
|
||||
color: root.colorText
|
||||
color: rootDelegate.colorText
|
||||
text: LinkPreviewInfo.domain
|
||||
lineHeight: 1.3
|
||||
}
|
||||
|
||||
@ -44,11 +44,15 @@ Menu {
|
||||
|
||||
function loadMenuItems(menuItems) {
|
||||
root.addItem(menuTopBorder);
|
||||
|
||||
// Establish the preferred width of the menu by taking the maximum width of the items
|
||||
for (var j = 0; j < menuItems.length; ++j) {
|
||||
var currentItemWidth = menuItems[j].itemPreferredWidth;
|
||||
if (currentItemWidth !== JamiTheme.menuItemsPreferredWidth && currentItemWidth > menuPreferredWidth && menuItems[j].canTrigger)
|
||||
menuPreferredWidth = currentItemWidth;
|
||||
}
|
||||
|
||||
// Add the items to the menu
|
||||
for (var i = 0; i < menuItems.length; ++i) {
|
||||
if (menuItems[i].canTrigger) {
|
||||
menuItems[i].parentMenu = root;
|
||||
|
||||
@ -27,11 +27,14 @@ Loader {
|
||||
property int contextMenuItemPreferredHeight: 0
|
||||
property int contextMenuSeparatorPreferredHeight: 0
|
||||
|
||||
signal openRequested
|
||||
|
||||
active: false
|
||||
|
||||
visible: false
|
||||
|
||||
function openMenu() {
|
||||
openRequested();
|
||||
root.active = true;
|
||||
root.sourceComponent = menuComponent;
|
||||
}
|
||||
|
||||
@ -28,6 +28,8 @@ MenuItem {
|
||||
id: menuItem
|
||||
|
||||
property string itemName: ""
|
||||
property bool bold: false
|
||||
property string content: ""
|
||||
property alias iconSource: contextMenuItemImage.source
|
||||
property string iconColor: ""
|
||||
property bool canTrigger: true
|
||||
@ -98,6 +100,7 @@ MenuItem {
|
||||
anchors.left: parent.left
|
||||
height: parent.height
|
||||
text: itemName
|
||||
font.bold: bold
|
||||
color: dangerous ? JamiTheme.redColor : isActif ? JamiTheme.textColor : JamiTheme.chatViewFooterImgColor
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "version.h"
|
||||
#include "version_info.h"
|
||||
|
||||
#include <QVariantMap>
|
||||
@ -108,7 +107,7 @@ protected:
|
||||
{"platform", QSysInfo::prettyProductName() + "_" + QSysInfo::currentCpuArchitecture()},
|
||||
{"client_sha", APP_VERSION_STRING},
|
||||
{"jamicore_sha", CORE_VERSION_STRING},
|
||||
{"build_id", QString(VERSION_STRING)},
|
||||
{"build_id", BUILD_VERSION_STRING},
|
||||
#if defined(Q_OS_WIN) && defined(BETA)
|
||||
{"build_variant", "beta"},
|
||||
#endif
|
||||
|
||||
@ -147,6 +147,7 @@ CurrentAccount::updateData()
|
||||
set_isRendezVous(accConfig.isRendezVous, true);
|
||||
set_dhtPort(accConfig.dhtPort, true);
|
||||
set_autoAnswer(accConfig.autoAnswer, true);
|
||||
set_denySecondCall(accConfig.denySecondCall, true);
|
||||
set_proxyEnabled(accConfig.proxyEnabled, true);
|
||||
set_upnpEnabled(accConfig.upnpEnabled, true);
|
||||
set_publishedSameAsLocal(accConfig.publishedSameAsLocal, true);
|
||||
|
||||
@ -121,6 +121,7 @@ class CurrentAccount final : public QObject
|
||||
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, denySecondCall)
|
||||
QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, proxyEnabled)
|
||||
QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, upnpEnabled)
|
||||
QML_ACCOUNT_CONFIG_SETTINGS_PROPERTY(bool, publishedSameAsLocal)
|
||||
|
||||
@ -356,7 +356,7 @@ CurrentCall::onCurrentAccountIdChanged()
|
||||
}
|
||||
|
||||
void
|
||||
CurrentCall::onCallStatusChanged(const QString& callId, int code)
|
||||
CurrentCall::onCallStatusChanged(const QString& accountId, const QString& callId, int code)
|
||||
{
|
||||
Q_UNUSED(code)
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ private:
|
||||
private Q_SLOTS:
|
||||
void onCurrentConvIdChanged();
|
||||
void onCurrentAccountIdChanged();
|
||||
void onCallStatusChanged(const QString& callId, int code);
|
||||
void onCallStatusChanged(const QString& accountId, const QString& callId, int code);
|
||||
void onCallInfosChanged(const QString& accountId, const QString& callId);
|
||||
void onCurrentCallChanged(const QString& callId);
|
||||
void onParticipantsChanged(const QString& callId);
|
||||
|
||||
@ -371,7 +371,7 @@ CurrentConversation::updateActiveCalls(const QString&, const QString& convId)
|
||||
}
|
||||
|
||||
void
|
||||
CurrentConversation::onCallStatusChanged(const QString& callId, int)
|
||||
CurrentConversation::onCallStatusChanged(const QString& accountId, const QString& callId, int)
|
||||
{
|
||||
if (callId != callId_) {
|
||||
return;
|
||||
|
||||
@ -90,7 +90,7 @@ private Q_SLOTS:
|
||||
void updateErrors(const QString& convId);
|
||||
void updateConversationPreferences(const QString& convId);
|
||||
void updateActiveCalls(const QString&, const QString& convId);
|
||||
void onCallStatusChanged(const QString& callId, int code);
|
||||
void onCallStatusChanged(const QString& accountId, const QString& callId, int code);
|
||||
void onShowIncomingCallView(const QString& accountId, const QString& convUid);
|
||||
|
||||
Q_SIGNALS:
|
||||
|
||||
@ -15,32 +15,32 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "imagedownloader.h"
|
||||
#include "filedownloader.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QLockFile>
|
||||
|
||||
ImageDownloader::ImageDownloader(ConnectivityMonitor* cm, QObject* parent)
|
||||
FileDownloader::FileDownloader(ConnectivityMonitor* cm, QObject* parent)
|
||||
: NetworkManager(cm, parent)
|
||||
{}
|
||||
|
||||
void
|
||||
ImageDownloader::downloadImage(const QUrl& url, const QString& localPath)
|
||||
FileDownloader::downloadFile(const QUrl& url, const QString& localPath)
|
||||
{
|
||||
Utils::oneShotConnect(this, &NetworkManager::errorOccurred, this, [this, localPath]() {
|
||||
onDownloadImageFinished({}, localPath);
|
||||
onDownloadFileFinished({}, localPath);
|
||||
});
|
||||
|
||||
sendGetRequest(url, [this, localPath](const QByteArray& imageData) {
|
||||
onDownloadImageFinished(imageData, localPath);
|
||||
sendGetRequest(url, [this, localPath](const QByteArray& fileData) {
|
||||
onDownloadFileFinished(fileData, localPath);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
ImageDownloader::onDownloadImageFinished(const QByteArray& data, const QString& localPath)
|
||||
FileDownloader::onDownloadFileFinished(const QByteArray& data, const QString& localPath)
|
||||
{
|
||||
if (data.isEmpty()) {
|
||||
Q_EMIT downloadImageFailed(localPath);
|
||||
Q_EMIT downloadFileFailed(localPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ ImageDownloader::onDownloadImageFinished(const QByteArray& data, const QString&
|
||||
const QDir dir;
|
||||
if (!dir.mkpath(dirPath)) {
|
||||
qWarning() << Q_FUNC_INFO << "Failed to create directory" << dirPath;
|
||||
Q_EMIT downloadImageFailed(localPath);
|
||||
Q_EMIT downloadFileFailed(localPath);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -58,10 +58,10 @@ ImageDownloader::onDownloadImageFinished(const QByteArray& data, const QString&
|
||||
if (lf.lock() && file.open(QIODevice::WriteOnly)) {
|
||||
file.write(data);
|
||||
file.close();
|
||||
Q_EMIT downloadImageSuccessful(localPath);
|
||||
Q_EMIT downloadFileSuccessful(localPath);
|
||||
return;
|
||||
}
|
||||
|
||||
qWarning() << Q_FUNC_INFO << "Failed to write image to" << localPath;
|
||||
Q_EMIT downloadImageFailed(localPath);
|
||||
qWarning() << Q_FUNC_INFO << "Failed to write file to" << localPath;
|
||||
Q_EMIT downloadFileFailed(localPath);
|
||||
}
|
||||
@ -24,7 +24,7 @@
|
||||
#include <QQmlEngine> // QML registration
|
||||
#include <QApplication> // QML registration
|
||||
|
||||
class ImageDownloader : public NetworkManager
|
||||
class FileDownloader : public NetworkManager
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_SINGLETON
|
||||
@ -32,23 +32,23 @@ class ImageDownloader : public NetworkManager
|
||||
QML_PROPERTY(QString, cachePath)
|
||||
|
||||
public:
|
||||
static ImageDownloader* create(QQmlEngine*, QJSEngine*)
|
||||
static FileDownloader* create(QQmlEngine*, QJSEngine*)
|
||||
{
|
||||
return new ImageDownloader(
|
||||
return new FileDownloader(
|
||||
qApp->property("ConnectivityMonitor").value<ConnectivityMonitor*>());
|
||||
}
|
||||
|
||||
explicit ImageDownloader(ConnectivityMonitor* cm, QObject* parent = nullptr);
|
||||
~ImageDownloader() = default;
|
||||
explicit FileDownloader(ConnectivityMonitor* cm, QObject* parent = nullptr);
|
||||
~FileDownloader() = default;
|
||||
|
||||
// Download an image and call onDownloadImageFinished when done
|
||||
Q_INVOKABLE void downloadImage(const QUrl& url, const QString& localPath);
|
||||
// Download an image and call onDownloadFileFinished when done
|
||||
Q_INVOKABLE void downloadFile(const QUrl& url, const QString& localPath);
|
||||
|
||||
Q_SIGNALS:
|
||||
void downloadImageSuccessful(const QString& localPath);
|
||||
void downloadImageFailed(const QString& localPath);
|
||||
void downloadFileSuccessful(const QString& localPath);
|
||||
void downloadFileFailed(const QString& localPath);
|
||||
|
||||
private Q_SLOTS:
|
||||
// Saves the image to the localPath and emits the appropriate signal
|
||||
void onDownloadImageFinished(const QByteArray& reply, const QString& localPath);
|
||||
void onDownloadFileFinished(const QByteArray& reply, const QString& localPath);
|
||||
};
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
#include "mainapplication.h"
|
||||
#include "instancemanager.h"
|
||||
#include "version.h"
|
||||
#include "version_info.h"
|
||||
#if defined(Q_OS_MACOS)
|
||||
#include <os/macos/macutils.h>
|
||||
#endif
|
||||
@ -66,7 +66,7 @@ main(int argc, char* argv[])
|
||||
QApplication::setApplicationName(QStringLiteral("Jami"));
|
||||
QApplication::setOrganizationDomain(QStringLiteral("jami.net"));
|
||||
QApplication::setQuitOnLastWindowClosed(false);
|
||||
QCoreApplication::setApplicationVersion(QString(VERSION_STRING));
|
||||
QCoreApplication::setApplicationVersion(BUILD_VERSION_STRING);
|
||||
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true);
|
||||
QApplication::setHighDpiScaleFactorRoundingPolicy(
|
||||
Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||
|
||||
@ -159,6 +159,7 @@ MainApplication::MainApplication(int& argc, char** argv)
|
||||
"qml.debug=false\n"
|
||||
"default.debug=false\n"
|
||||
"client.debug=false\n"
|
||||
"spellcheck.debug=false\n"
|
||||
"\n");
|
||||
// These can be set in the environment as well.
|
||||
// e.g. QT_LOGGING_RULES="*.debug=false;qml.debug=true"
|
||||
@ -347,8 +348,8 @@ MainApplication::parseArguments()
|
||||
parser_.addOption(muteDaemonOption);
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
// In debug mode, add an option to test a specific QML component via its name.
|
||||
// e.g. ./jami --test AccountComboBox
|
||||
// In debug mode, add an option to test a specific QML component via its name.
|
||||
// e.g. ./jami --test AccountComboBox
|
||||
parser_.addOption(QCommandLineOption("test", "Test a QML component via its name.", "uri"));
|
||||
// We may need to force the test window dimensions in the case that the component to test
|
||||
// does not specify its own dimensions and is dependent on parent/sibling dimensions.
|
||||
@ -463,7 +464,7 @@ MainApplication::initQmlLayer()
|
||||
void
|
||||
MainApplication::initSystray()
|
||||
{
|
||||
systemTray_->setIcon(QIcon(":/images/jami.svg"));
|
||||
systemTray_->setIcon(QIcon(":/images/net.jami.Jami.svg"));
|
||||
|
||||
QMenu* menu {nullptr};
|
||||
// If there was a previous menu, reuse it, otherwise create a new one.
|
||||
|
||||
@ -85,7 +85,6 @@ Popup {
|
||||
anchors.rightMargin: 15
|
||||
spacing: 10
|
||||
|
||||
|
||||
Avatar {
|
||||
id: avatar
|
||||
objectName: "accountComboBoxPopupAvatar"
|
||||
@ -164,8 +163,13 @@ Popup {
|
||||
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
hoveredColor: JamiTheme.hoverColor
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: toolTipText
|
||||
Accessible.description: JamiStrings.qrCodeExplanation
|
||||
|
||||
onClicked: {
|
||||
viewCoordinator.presentDialog(appWindow, "mainview/components/WelcomePageQrDialog.qml");
|
||||
listView.currentIndex = -1;
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
@ -184,34 +188,40 @@ Popup {
|
||||
|
||||
toolTipText: !inSettings ? JamiStrings.openSettings : JamiStrings.closeSettings
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: toolTipText
|
||||
KeyNavigation.backtab: shareButton
|
||||
|
||||
onClicked: {
|
||||
!inSettings ? viewCoordinator.present("SettingsView") : viewCoordinator.dismiss("SettingsView");
|
||||
root.close();
|
||||
}
|
||||
|
||||
KeyNavigation.tab: addAccountItem
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
height: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: 15
|
||||
Layout.rightMargin: 15
|
||||
color: JamiTheme.smartListHoveredColor
|
||||
}
|
||||
|
||||
|
||||
JamiListView {
|
||||
ListView {
|
||||
id: listView
|
||||
objectName: "accountList"
|
||||
Accessible.name: JamiStrings.accountList
|
||||
Accessible.role: Accessible.List
|
||||
Accessible.description: JamiStrings.accountListDescription
|
||||
|
||||
layer.mipmap: false
|
||||
clip: true
|
||||
maximumFlickVelocity: 1024
|
||||
|
||||
// HACK: remove after migration to Qt 6.7+
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
|
||||
Layout.fillHeight: true
|
||||
Layout.preferredWidth: parent.width
|
||||
|
||||
activeFocusOnTab: true
|
||||
focus: true
|
||||
currentIndex: -1 // Set to -1 to avoid initial highlighting
|
||||
|
||||
model: SortFilterProxyModel {
|
||||
sourceModel: AccountListModel
|
||||
filters: ValueFilter {
|
||||
@ -221,10 +231,35 @@ Popup {
|
||||
}
|
||||
}
|
||||
|
||||
highlight: Rectangle {
|
||||
color: "transparent"
|
||||
border.color: JamiTheme.primaryBackgroundColor
|
||||
border.width: 2
|
||||
radius: 5
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.hoverColor
|
||||
radius: 5
|
||||
opacity: 0.3
|
||||
}
|
||||
}
|
||||
|
||||
delegate: AccountItemDelegate {
|
||||
height: JamiTheme.accountListItemHeight
|
||||
width: root.width
|
||||
|
||||
Accessible.role: Accessible.ListItem
|
||||
Accessible.name: Alias || Username
|
||||
Accessible.description: JamiStrings.switchToAccount
|
||||
|
||||
// Update the background to show focus state
|
||||
background: Rectangle {
|
||||
color: parent.activeFocus || parent.hovered ? JamiTheme.hoverColor : "transparent"
|
||||
opacity: parent.activeFocus ? 0.3 : 1
|
||||
radius: 5
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
root.close();
|
||||
// This is a workaround for the synchronicity issue
|
||||
@ -235,7 +270,7 @@ Popup {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
height: 1
|
||||
Layout.fillWidth: true
|
||||
@ -248,19 +283,24 @@ Popup {
|
||||
id: addAccountItem
|
||||
|
||||
Layout.preferredHeight: 45
|
||||
Layout.preferredWidth: parent.width -10
|
||||
Layout.preferredWidth: parent.width - 10
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
Layout.leftMargin: 5
|
||||
|
||||
Accessible.name: JamiStrings.addAccount
|
||||
focusPolicy: Qt.StrongFocus
|
||||
Accessible.name: addAccountText.text
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
KeyNavigation.tab: manageAccountItem
|
||||
KeyNavigation.up: listView
|
||||
KeyNavigation.down: manageAccountItem
|
||||
|
||||
background: Rectangle {
|
||||
color: addAccountItem.hovered ? JamiTheme.hoverColor : JamiTheme.accountComboBoxBackgroundColor
|
||||
radius: 5
|
||||
}
|
||||
|
||||
RowLayout{
|
||||
RowLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -274,6 +314,7 @@ Popup {
|
||||
}
|
||||
|
||||
Text {
|
||||
id: addAccountText
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
text: JamiStrings.addAccount
|
||||
textFormat: TextEdit.PlainText
|
||||
@ -285,18 +326,21 @@ Popup {
|
||||
root.close();
|
||||
viewCoordinator.present("WizardView");
|
||||
}
|
||||
|
||||
KeyNavigation.tab: manageAccountItem
|
||||
}
|
||||
|
||||
ItemDelegate {
|
||||
id: manageAccountItem
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: JamiStrings.manageAccount
|
||||
Accessible.name: manageAccountText.text
|
||||
|
||||
KeyNavigation.backtab: addAccountItem
|
||||
KeyNavigation.tab: shareButton
|
||||
KeyNavigation.up: addAccountItem
|
||||
|
||||
Layout.preferredHeight: 45
|
||||
Layout.preferredWidth: parent.width-10
|
||||
Layout.preferredWidth: parent.width - 10
|
||||
Layout.leftMargin: 5
|
||||
Layout.bottomMargin: 5
|
||||
|
||||
@ -305,7 +349,7 @@ Popup {
|
||||
radius: 5
|
||||
}
|
||||
|
||||
RowLayout{
|
||||
RowLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 18
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -319,8 +363,8 @@ Popup {
|
||||
color: manageAccountItem.hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
|
||||
}
|
||||
Text {
|
||||
id: manageAccountText
|
||||
text: JamiStrings.manageAccount
|
||||
|
||||
textFormat: TextEdit.PlainText
|
||||
color: JamiTheme.textColor
|
||||
font.pointSize: JamiTheme.textFontSize
|
||||
@ -328,7 +372,7 @@ Popup {
|
||||
}
|
||||
onClicked: {
|
||||
root.close();
|
||||
viewCoordinator.present("SettingsView")
|
||||
viewCoordinator.present("SettingsView");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,17 +28,24 @@ ItemDelegate {
|
||||
height: JamiTheme.accountListItemHeight
|
||||
|
||||
background: Rectangle {
|
||||
width: root.width - 10
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors {
|
||||
left: parent ? parent.left : undefined
|
||||
right: parent ? parent.right : undefined
|
||||
leftMargin: 5
|
||||
rightMargin: 5
|
||||
}
|
||||
radius: 5
|
||||
|
||||
Rectangle{
|
||||
Rectangle {
|
||||
id: separationLine
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors {
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
top: parent.top
|
||||
leftMargin: 10
|
||||
rightMargin: 10
|
||||
}
|
||||
height: 1
|
||||
width: parent.width - 20
|
||||
color: JamiTheme.hoverColor
|
||||
visible: index !== 0
|
||||
}
|
||||
|
||||
@ -25,6 +25,13 @@ import "../../commoncomponents"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string tipTitle: title.text
|
||||
property string tipDescription: opened ? description.text : JamiStrings.whyBackupAccount
|
||||
|
||||
Accessible.name: tipTitle
|
||||
Accessible.description: tipDescription
|
||||
|
||||
width: parent.width
|
||||
height: backupLayout.height
|
||||
|
||||
|
||||
@ -64,8 +64,8 @@ Item {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ImageDownloader
|
||||
function onDownloadImageSuccessful(localPath) {
|
||||
target: FileDownloader
|
||||
function onDownloadFileSuccessful(localPath) {
|
||||
if (localPath === cachedImage.localPath) {
|
||||
image.source = UtilsAdapter.urlFromLocalPath(localPath);
|
||||
}
|
||||
@ -90,7 +90,7 @@ Item {
|
||||
}
|
||||
if (downloadUrl && downloadUrl !== "" && localPath !== "") {
|
||||
if (!UtilsAdapter.fileExists(localPath)) {
|
||||
ImageDownloader.downloadImage(downloadUrl, localPath);
|
||||
FileDownloader.downloadFile(downloadUrl, localPath);
|
||||
} else {
|
||||
image.source = UtilsAdapter.urlFromLocalPath(localPath);
|
||||
if (image.isGif) {
|
||||
|
||||
@ -55,15 +55,30 @@ Control {
|
||||
signal fullScreenClicked
|
||||
signal swarmDetailsClicked
|
||||
|
||||
// For Keyboard naviguation
|
||||
property bool isInternalNavigation: false
|
||||
|
||||
function exitBarNavigation() {
|
||||
isInternalNavigation = false;
|
||||
// Let the parent control take over focus handling
|
||||
parent.forceActiveFocus();
|
||||
}
|
||||
|
||||
Component {
|
||||
id: buttonDelegate
|
||||
|
||||
CallButtonDelegate {
|
||||
id: delegateItem
|
||||
width: root.height
|
||||
height: width
|
||||
barWidth: root.width
|
||||
onSubMenuVisibleChanged: subMenuOpen = subMenuVisible
|
||||
onHoveredChanged: root.barHovered = hovered
|
||||
|
||||
focusPolicy: Qt.StrongFocus
|
||||
focus: false
|
||||
|
||||
Keys.onEscapePressed: root.exitBarNavigation()
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,6 +98,7 @@ Control {
|
||||
id: audioInputMenuAction
|
||||
text: JamiStrings.selectAudioInputDevice
|
||||
Component.onCompleted: enabled = audioInputDeviceListModel.rowCount()
|
||||
property int popupMode: CallActionBar.ActionPopupMode.MediaDevice
|
||||
property var listModel: AudioDeviceModel {
|
||||
id: audioInputDeviceListModel
|
||||
lrcInstance: LRCInstance
|
||||
@ -98,6 +114,7 @@ Control {
|
||||
id: audioOutputMenuAction
|
||||
text: JamiStrings.selectAudioOutputDevice
|
||||
Component.onCompleted: enabled = audioOutputDeviceListModel.rowCount()
|
||||
property int popupMode: CallActionBar.ActionPopupMode.MediaDevice
|
||||
property var listModel: AudioDeviceModel {
|
||||
id: audioOutputDeviceListModel
|
||||
lrcInstance: LRCInstance
|
||||
@ -257,6 +274,7 @@ Control {
|
||||
id: videoInputMenuAction
|
||||
enabled: VideoDevices.listSize !== 0
|
||||
text: JamiStrings.selectVideoDevice
|
||||
property int popupMode: CallActionBar.ActionPopupMode.MediaDevice
|
||||
property var listModel: VideoDevices.deviceSourceModel
|
||||
function accept(index) {
|
||||
VideoDevices.setDefaultDevice(index);
|
||||
@ -567,6 +585,34 @@ Control {
|
||||
ComboBox {
|
||||
id: overflowButton
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: JamiStrings.more
|
||||
Accessible.description: JamiStrings.moreOptions
|
||||
|
||||
KeyNavigation.tab: {
|
||||
if (popup.opened) {
|
||||
return popup.contentItem.itemAtIndex(0);
|
||||
}
|
||||
// Exit bar navigation if we've reached the end
|
||||
root.exitBarNavigation();
|
||||
return null;
|
||||
}
|
||||
|
||||
KeyNavigation.backtab: {
|
||||
if (overflowItemListView.count > 0) {
|
||||
return overflowItemListView.itemAtIndex(overflowItemListView.count - 1);
|
||||
}
|
||||
return itemListView.itemAtIndex(itemListView.count - 1);
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: {
|
||||
if (popup.opened) {
|
||||
popup.close();
|
||||
} else {
|
||||
root.exitBarNavigation();
|
||||
}
|
||||
}
|
||||
|
||||
visible: CallOverlayModel.overflowIndex < overflowItemCount - 2
|
||||
width: root.height
|
||||
height: width
|
||||
|
||||
@ -42,8 +42,18 @@ ItemDelegate {
|
||||
text: ""
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: text
|
||||
Accessible.description: text
|
||||
Accessible.name: ItemAction.text
|
||||
Accessible.description: {
|
||||
if (!ItemAction?.text)
|
||||
return "";
|
||||
if (ItemAction.checkable) {
|
||||
return JamiStrings.pressToToggle.arg(ItemAction.text).arg(ItemAction.checked ? JamiStrings.active : JamiStrings.inactive);
|
||||
}
|
||||
return JamiStrings.pressToAction.arg(ItemAction.text);
|
||||
}
|
||||
Accessible.pressed: pressed
|
||||
Accessible.checkable: ItemAction ? ItemAction.checkable : false
|
||||
Accessible.checked: ItemAction ? ItemAction.checked : false
|
||||
|
||||
z: index
|
||||
|
||||
@ -77,7 +87,7 @@ ItemDelegate {
|
||||
return HalfPill.None;
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: JamiTheme.shortFadeDuration
|
||||
}
|
||||
@ -94,7 +104,7 @@ ItemDelegate {
|
||||
radius: isLast ? 5 : width / 2
|
||||
type: isLast ? HalfPill.Right : HalfPill.None
|
||||
|
||||
Behavior on color {
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: JamiTheme.shortFadeDuration
|
||||
}
|
||||
@ -113,7 +123,7 @@ ItemDelegate {
|
||||
source: ItemAction ? ItemAction.icon.source : ""
|
||||
color: ItemAction ? (ItemAction.enabled ? ItemAction.icon.color : Qt.lighter(ItemAction.icon.color)) : null
|
||||
|
||||
SequentialAnimation on opacity {
|
||||
SequentialAnimation on opacity {
|
||||
loops: Animation.Infinite
|
||||
running: ItemAction !== undefined && ItemAction.blinksWhenChecked !== undefined && ItemAction.blinksWhenChecked && checked
|
||||
onStopped: icon.opacity = 1
|
||||
@ -171,9 +181,23 @@ ItemDelegate {
|
||||
Connections {
|
||||
target: menuAction !== undefined ? menuAction : null
|
||||
function onTriggered() {
|
||||
if (menuAction.popupMode !== CallActionBar.ActionPopupMode.ListElement) {
|
||||
var index = menuAction.listModel.currentIndex;
|
||||
itemListView.currentIndex = index !== undefined ? index : 0;
|
||||
var index;
|
||||
switch (menuAction.popupMode) {
|
||||
case CallActionBar.ActionPopupMode.MediaDevice:
|
||||
index = menuAction.listModel.getCurrentIndex();
|
||||
break;
|
||||
case CallActionBar.ActionPopupMode.LayoutOption:
|
||||
index = menuAction.listModel.currentIndex;
|
||||
break;
|
||||
case CallActionBar.ActionPopupMode.ListElement:
|
||||
index = menuAction.listModel.currentIndex;
|
||||
break;
|
||||
default:
|
||||
console.warn("Unknown popup mode: " + menuAction.popupMode);
|
||||
return;
|
||||
}
|
||||
if (index !== undefined) {
|
||||
itemListView.currentIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -188,7 +212,7 @@ ItemDelegate {
|
||||
radius: 4
|
||||
}
|
||||
|
||||
onActivated: index => menuAction.accept(index);
|
||||
onActivated: index => menuAction.accept(index)
|
||||
model: visible ? menuAction.listModel : null
|
||||
delegate: ItemDelegate {
|
||||
id: menuItem
|
||||
@ -313,7 +337,6 @@ ItemDelegate {
|
||||
// it fits within the overlay, with an extra leftward margin of 24 pixels.
|
||||
return diff > 0 ? xValue - diff - 24 : xValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
implicitWidth: contentItem.implicitWidth
|
||||
|
||||
@ -116,23 +116,23 @@ Rectangle {
|
||||
|
||||
spacing: 0
|
||||
|
||||
LineEditContextMenu {
|
||||
id: displayNameContextMenu
|
||||
lineEditObj: title
|
||||
selectOnly: true
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: function (mouse) {
|
||||
displayNameContextMenu.openMenuAt(mouse);
|
||||
}
|
||||
}
|
||||
|
||||
ElidedTextLabel {
|
||||
id: title
|
||||
|
||||
LineEditContextMenu {
|
||||
id: displayNameContextMenu
|
||||
lineEditObj: title
|
||||
selectOnly: true
|
||||
}
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
cursorShape: Qt.IBeamCursor
|
||||
onClicked: function (mouse) {
|
||||
displayNameContextMenu.openMenuAt(mouse);
|
||||
}
|
||||
}
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
|
||||
font.pointSize: JamiTheme.textFontSize + 2
|
||||
|
||||
@ -26,6 +26,12 @@ ColumnLayout {
|
||||
id: column
|
||||
width: parent.width
|
||||
|
||||
property string tipTitle: JamiStrings.customize
|
||||
property string tipDescription: JamiStrings.customizeText
|
||||
|
||||
Accessible.name: tipTitle
|
||||
Accessible.description: tipDescription
|
||||
|
||||
property var iconSize: 26
|
||||
property var margin: 5
|
||||
property var prefWidth: 170
|
||||
|
||||
@ -24,6 +24,13 @@ import "../../commoncomponents"
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string tipTitle: title.text
|
||||
property string tipDescription: content.text
|
||||
|
||||
Accessible.name: tipTitle
|
||||
Accessible.description: tipDescription
|
||||
|
||||
focus: true
|
||||
width: parent.width
|
||||
height: backupLayout.height
|
||||
|
||||
@ -43,6 +43,9 @@ TabButton {
|
||||
hoverEnabled: true
|
||||
onClicked: selected()
|
||||
|
||||
Accessible.name: root.labelText
|
||||
Accessible.role: Accessible.Button
|
||||
|
||||
Rectangle {
|
||||
id: contentRect
|
||||
|
||||
|
||||
@ -26,6 +26,12 @@ ColumnLayout {
|
||||
id: column
|
||||
width: parent.width
|
||||
|
||||
property alias tipTitle: title.text
|
||||
property alias tipDescription: description.text
|
||||
|
||||
Accessible.name: tipTitle
|
||||
Accessible.description: tipDescription
|
||||
|
||||
property real maxHeight: 250
|
||||
|
||||
property var iconSize: 26
|
||||
|
||||
@ -25,4 +25,6 @@ PushButton {
|
||||
|
||||
normalColor: JamiTheme.chatviewBgColor
|
||||
imageColor: hovered ? JamiTheme.chatviewButtonColor : JamiTheme.chatViewFooterImgColor
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.description: toolTipText
|
||||
}
|
||||
|
||||
@ -228,6 +228,11 @@ Window {
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
|
||||
// make a list view of keyboardShortcutsModelList[selectionBar.currentIndex]
|
||||
JamiListView {
|
||||
id: keyboardShortcutsListView
|
||||
@ -262,6 +267,7 @@ Window {
|
||||
Layout.topMargin: 8
|
||||
Layout.leftMargin: 20
|
||||
text: description
|
||||
color: JamiTheme.textColor
|
||||
background: Rectangle {
|
||||
width: parent.width + 16
|
||||
height: parent.height + 16
|
||||
@ -269,6 +275,7 @@ Window {
|
||||
border.width: 2
|
||||
radius: 5
|
||||
anchors.centerIn: parent
|
||||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
}
|
||||
Label {
|
||||
@ -277,6 +284,7 @@ Window {
|
||||
Layout.topMargin: 8
|
||||
Layout.rightMargin: 20
|
||||
text: shortcut
|
||||
color: JamiTheme.textColor
|
||||
background: Rectangle {
|
||||
width: parent.width + 16
|
||||
height: parent.height + 16
|
||||
@ -284,6 +292,7 @@ Window {
|
||||
border.width: 2
|
||||
radius: 5
|
||||
anchors.centerIn: parent
|
||||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -300,6 +309,10 @@ Window {
|
||||
|
||||
focus: true
|
||||
|
||||
background: Rectangle {
|
||||
color: JamiTheme.backgroundColor
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: [JamiStrings.generalSettingsTitle, JamiStrings.conversationKeyboardShortcuts, JamiStrings.callKeyboardShortcuts, JamiStrings.markdownKeyboardShortcuts, JamiStrings.settings]
|
||||
|
||||
@ -339,9 +352,16 @@ Window {
|
||||
footer: Item {
|
||||
height: JamiTheme.keyboardShortcutTabBarSize
|
||||
PageIndicator {
|
||||
id: pageIndicator
|
||||
anchors.centerIn: parent
|
||||
count: selectionBar.count
|
||||
currentIndex: selectionBar.currentIndex
|
||||
delegate: Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: index === pageIndicator.currentIndex ? JamiTheme.textColor : JamiTheme.textColorHoveredHighContrast
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,17 @@ Item {
|
||||
|
||||
property string timeText: "00:00"
|
||||
property string remoteRecordingLabel
|
||||
property bool isKeyboardSelectionActive: {
|
||||
if (!appWindow || !appWindow.activeFocusItem)
|
||||
return false;
|
||||
let parent = appWindow.activeFocusItem.parent;
|
||||
while (parent && parent !== appWindow && parent !== root && parent !== null) {
|
||||
if (parent.objectName === "callActionBar")
|
||||
return true;
|
||||
parent = parent.parent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CurrentCall
|
||||
@ -42,7 +53,11 @@ Item {
|
||||
|
||||
property alias callActionBar: __callActionBar
|
||||
|
||||
property bool frozen: callActionBar.overflowOpen || callActionBar.barHovered || callActionBar.subMenuOpen || participantCallInStatusView.visible
|
||||
property bool frozen: callActionBar.overflowOpen ||
|
||||
callActionBar.barHovered ||
|
||||
callActionBar.subMenuOpen ||
|
||||
participantCallInStatusView.visible ||
|
||||
isKeyboardSelectionActive
|
||||
|
||||
property string muteAlertMessage: ""
|
||||
property bool muteAlertActive: false
|
||||
@ -59,15 +74,27 @@ Item {
|
||||
Component.onDestruction: CallOverlayModel.setEventFilterActive(appWindow, this, false)
|
||||
onVisibleChanged: CallOverlayModel.setEventFilterActive(appWindow, this, visible)
|
||||
|
||||
function kickOverlay() {
|
||||
root.opacity = 1;
|
||||
fadeOutTimer.restart();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CallOverlayModel
|
||||
|
||||
function onMouseMoved(item) {
|
||||
if (item === root) {
|
||||
root.opacity = 1;
|
||||
fadeOutTimer.restart();
|
||||
kickOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
// This is part of a mechanism used to show the overlay when a focus key is pressed
|
||||
// and keep it open in the case that the user is navigating with the keyboard over
|
||||
// the call action bar.
|
||||
function onFocusKeyPressed() {
|
||||
// Always show the overlay when a focus key (Tab/BackTab) is pressed
|
||||
kickOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
Shortcut {
|
||||
@ -76,8 +103,7 @@ Item {
|
||||
context: Qt.ApplicationShortcut
|
||||
onActivated: {
|
||||
CallAdapter.muteAudioToggle();
|
||||
root.opacity = 1;
|
||||
fadeOutTimer.restart();
|
||||
kickOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,8 +113,7 @@ Item {
|
||||
context: Qt.ApplicationShortcut
|
||||
onActivated: {
|
||||
CallAdapter.muteCameraToggle();
|
||||
root.opacity = 1;
|
||||
fadeOutTimer.restart();
|
||||
kickOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,19 +17,17 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
import net.jami.Models 1.1
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import "../../commoncomponents"
|
||||
|
||||
JamiFlickable {
|
||||
id: root
|
||||
|
||||
property int underlineHeight: JamiTheme.messageUnderlineHeight
|
||||
property alias text: textArea.text
|
||||
property var textAreaObj: textArea
|
||||
property alias placeholderText: textArea.placeholderText
|
||||
@ -39,9 +37,11 @@ JamiFlickable {
|
||||
property bool showPreview: false
|
||||
property bool isShowTypo: UtilsAdapter.getAppValue(Settings.Key.ShowMardownOption)
|
||||
property int textWidth: textArea.contentWidth
|
||||
property var language: AppSettingsManager.getValue(Settings.SpellLang)
|
||||
|
||||
// Used to cache the editable text when showing the preview message
|
||||
// and also to debounce the textChanged signal's effect on the composing status.
|
||||
property var underlineList: []
|
||||
property string cachedText
|
||||
property string debounceText
|
||||
|
||||
@ -72,6 +72,7 @@ JamiFlickable {
|
||||
|
||||
lineEditObj: textArea
|
||||
customizePaste: true
|
||||
spellCheckEnabled: root.spellCheckEnabled
|
||||
|
||||
onContextMenuRequirePaste: {
|
||||
// Intercept paste event to use C++ QMimeData
|
||||
@ -112,12 +113,50 @@ JamiFlickable {
|
||||
}
|
||||
}
|
||||
|
||||
property bool spellCheckEnabled: AppSettingsManager.getValue(Settings.EnableSpellCheck) && AppSettingsManager.getValue(Settings.SpellLang) !== ""
|
||||
|
||||
// Spell check is active under the following conditions:
|
||||
// 1. Spell check is enabled in settings
|
||||
// 2. The selected spell language is not ""
|
||||
// 3. We are not in preview mode
|
||||
readonly property bool spellCheckActive: spellCheckEnabled && !showPreview
|
||||
|
||||
onSpellCheckActiveChanged: textArea.updateSpellCorrection()
|
||||
|
||||
TextArea.flickable: TextArea {
|
||||
id: textArea
|
||||
|
||||
Connections {
|
||||
target: SpellCheckAdapter
|
||||
|
||||
function onDictionaryChanged() {
|
||||
textArea.updateSpellCorrection();
|
||||
}
|
||||
}
|
||||
|
||||
// Listen to settings changes to apply it to the text area
|
||||
Connections {
|
||||
target: UtilsAdapter
|
||||
|
||||
function onChangeLanguage() {
|
||||
textArea.updateSpellCorrection();
|
||||
}
|
||||
|
||||
function onChangeFontSize() {
|
||||
textArea.updateSpellCorrection();
|
||||
}
|
||||
|
||||
function onEnableSpellCheckChanged() {
|
||||
textArea.updateSpellCorrection();
|
||||
}
|
||||
}
|
||||
|
||||
readOnly: showPreview
|
||||
leftPadding: JamiTheme.scrollBarHandleSize
|
||||
rightPadding: JamiTheme.scrollBarHandleSize
|
||||
topPadding: 0
|
||||
bottomPadding: underlineHeight
|
||||
|
||||
persistentSelection: true
|
||||
verticalAlignment: TextEdit.AlignVCenter
|
||||
font.pointSize: JamiTheme.textFontSize + 2
|
||||
@ -135,12 +174,39 @@ JamiFlickable {
|
||||
color: "transparent"
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: textMetrics
|
||||
elide: Text.ElideMiddle
|
||||
font.family: textArea.font.family
|
||||
font.pointSize: JamiTheme.textFontSize + 2
|
||||
}
|
||||
|
||||
Text {
|
||||
id: highlight
|
||||
color: "black"
|
||||
font.bold: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
onReleased: function (event) {
|
||||
if (event.button === Qt.RightButton)
|
||||
if (event.button === Qt.RightButton) {
|
||||
if (spellCheckActive && SpellCheckAdapter.hasLoadedDictionary) {
|
||||
var position = textArea.positionAt(event.x, event.y);
|
||||
textArea.moveCursorSelection(position, TextInput.SelectWords);
|
||||
textArea.selectWord();
|
||||
if (!SpellCheckAdapter.spell(textArea.selectedText)) {
|
||||
var wordList = SpellCheckAdapter.spellSuggestionsRequest(textArea.selectedText);
|
||||
if (wordList.length !== 0) {
|
||||
textAreaContextMenu.addMenuItem(wordList);
|
||||
}
|
||||
}
|
||||
}
|
||||
textAreaContextMenu.openMenuAt(event);
|
||||
}
|
||||
}
|
||||
|
||||
onTextChanged: {
|
||||
updateSpellCorrection();
|
||||
if (text !== debounceText && !showPreview) {
|
||||
debounceText = text;
|
||||
MessagesAdapter.userIsComposing(text ? true : false);
|
||||
@ -152,6 +218,8 @@ JamiFlickable {
|
||||
// eg. Enter -> Send messages
|
||||
// Shift + Enter -> Next Line
|
||||
Keys.onPressed: function (keyEvent) {
|
||||
// Update underline on each input to take into account deleted text and sent ones
|
||||
updateSpellCorrection();
|
||||
if (keyEvent.matches(StandardKey.Paste)) {
|
||||
MessagesAdapter.onPaste();
|
||||
keyEvent.accepted = true;
|
||||
@ -180,5 +248,41 @@ JamiFlickable {
|
||||
keyEvent.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function updateSpellCorrection() {
|
||||
clearUnderlines();
|
||||
// We iterate over the whole text to find words to check and underline them if needed
|
||||
if (spellCheckActive && SpellCheckAdapter.hasLoadedDictionary) {
|
||||
var text = textArea.text;
|
||||
var words = SpellCheckAdapter.findWords(text);
|
||||
if (!words)
|
||||
return;
|
||||
for (var i = 0; i < words.length; i++) {
|
||||
var wordInfo = words[i];
|
||||
if (wordInfo && wordInfo.word && !SpellCheckAdapter.spell(wordInfo.word)) {
|
||||
textMetrics.text = wordInfo.word;
|
||||
var xPos = textArea.positionToRectangle(wordInfo.position).x;
|
||||
var yPos = textArea.positionToRectangle(wordInfo.position).y + textArea.positionToRectangle(wordInfo.position).height;
|
||||
var underlineObject = Qt.createQmlObject('import QtQuick; Rectangle {height: 2; color: "red";}', textArea);
|
||||
underlineObject.x = xPos;
|
||||
underlineObject.y = yPos;
|
||||
underlineObject.width = textMetrics.width;
|
||||
underlineList.push(underlineObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearUnderlines() {
|
||||
// Destroy all of the underline boxes
|
||||
while (underlineList.length > 0) {
|
||||
// Get the previous item
|
||||
var underlineObject = underlineList[underlineList.length - 1];
|
||||
// Remove the last item
|
||||
underlineList.pop();
|
||||
// Destroy the removed item
|
||||
underlineObject.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,6 +479,9 @@ Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
enabled: !showPreview
|
||||
hoverEnabled: !showPreview
|
||||
Accessible.name: JamiStrings.showMoreMessagingOptions
|
||||
Accessible.role: Accessible.ComboBox
|
||||
Accessible.description: JamiStrings.showMoreMessagingOptionsDescription
|
||||
|
||||
// Used to choose the correct color for the button.
|
||||
readonly property bool highlight: down || hovered
|
||||
|
||||
@ -24,8 +24,26 @@ import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import "../../commoncomponents"
|
||||
|
||||
JamiListView {
|
||||
ListView {
|
||||
id: root
|
||||
property alias verticalScrollBar: verticalScrollBar
|
||||
layer.mipmap: false
|
||||
clip: true
|
||||
|
||||
ScrollBar.vertical: JamiScrollBar {
|
||||
id: verticalScrollBar
|
||||
|
||||
attachedFlickableMoving: root.moving
|
||||
}
|
||||
|
||||
keyNavigationEnabled: true
|
||||
keyNavigationWraps: false
|
||||
|
||||
focus: true
|
||||
activeFocusOnTab: true
|
||||
|
||||
Accessible.role: Accessible.List
|
||||
Accessible.name: JamiStrings.conversationMessages
|
||||
|
||||
function getDistanceToBottom() {
|
||||
const scrollDiff = ScrollBar.vertical.position - (1.0 - ScrollBar.vertical.size);
|
||||
@ -139,7 +157,10 @@ JamiListView {
|
||||
}
|
||||
|
||||
// fade-in mechanism
|
||||
Component.onCompleted: fadeAnimation.start()
|
||||
Component.onCompleted: {
|
||||
positionViewAtBeginning();
|
||||
fadeAnimation.start();
|
||||
}
|
||||
Rectangle {
|
||||
id: overlay
|
||||
anchors.fill: parent
|
||||
@ -194,13 +215,19 @@ JamiListView {
|
||||
boundsBehavior: Flickable.StopAtBounds
|
||||
currentIndex: -1
|
||||
|
||||
Connections {
|
||||
target: CurrentConversation
|
||||
function onIdChanged() {
|
||||
currentIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
model: MessagesAdapter.messageListModel
|
||||
delegate: DelegateChooser {
|
||||
id: delegateChooser
|
||||
role: "Type"
|
||||
|
||||
DelegateChoice {
|
||||
id: delegateChoice
|
||||
roleValue: Interaction.Type.TEXT
|
||||
|
||||
TextMessageDelegate {
|
||||
|
||||
@ -220,7 +220,6 @@ Popup {
|
||||
id: cancelBtn
|
||||
objectName: "cancelBtn"
|
||||
z: 1
|
||||
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignTop
|
||||
Layout.preferredHeight: 20
|
||||
Layout.preferredWidth: 20
|
||||
@ -323,6 +322,9 @@ Popup {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
preferredSize: btnSize
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: toolTipText
|
||||
|
||||
source: JamiResources.stop_rectangle_24dp_svg
|
||||
|
||||
imageColor: JamiTheme.whiteColor
|
||||
|
||||
@ -34,7 +34,13 @@ Rectangle {
|
||||
|
||||
function clearText() {
|
||||
textArea.clear();
|
||||
textArea.forceActiveFocus();
|
||||
setTextAreaFocus();
|
||||
}
|
||||
|
||||
function setTextAreaFocus() {
|
||||
if (visible){
|
||||
textArea.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
radius: JamiTheme.primaryRadius
|
||||
@ -42,7 +48,7 @@ Rectangle {
|
||||
|
||||
onFocusChanged: {
|
||||
if (focus) {
|
||||
textArea.forceActiveFocus();
|
||||
setTextAreaFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -36,6 +36,36 @@ FocusScope {
|
||||
property color textColor: JamiTheme.textColor
|
||||
property color iconColor: JamiTheme.tintedBlue
|
||||
|
||||
Accessible.role: Accessible.Paragraph
|
||||
Accessible.name: {
|
||||
switch (type) {
|
||||
case "donation":
|
||||
return JamiStrings.donation
|
||||
case "backup":
|
||||
return JamiStrings.backupAccountBtn
|
||||
case "customize":
|
||||
return JamiStrings.customize
|
||||
case "tip":
|
||||
return title
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
Accessible.description: {
|
||||
switch (type) {
|
||||
case "donation":
|
||||
return JamiStrings.donationTipBoxText
|
||||
case "backup":
|
||||
return JamiStrings.whyBackupAccount
|
||||
case "customize":
|
||||
return JamiStrings.customizeText
|
||||
case "tip":
|
||||
return description
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
property string customizeTip: "CustomizeTipBox {}"
|
||||
|
||||
property string backupTip: "BackupTipBox {" + " onIgnore: {" + " root.ignoreClicked()" + " }" + "}"
|
||||
@ -75,6 +105,9 @@ FocusScope {
|
||||
active: type === "donation"
|
||||
focus: true
|
||||
sourceComponent: DonationTipBox {
|
||||
Accessible.name: JamiStrings.donation
|
||||
Accessible.description: JamiStrings.donationTipBoxText
|
||||
Accessible.role: Accessible.Link
|
||||
maxHeight: root.maximumHeight
|
||||
textColor: root.textColor
|
||||
iconColor: root.iconColor
|
||||
@ -86,6 +119,9 @@ FocusScope {
|
||||
id: loader_backupTip
|
||||
active: type === "backup"
|
||||
sourceComponent: BackupTipBox {
|
||||
Accessible.name: JamiStrings.backupAccountBtn
|
||||
Accessible.description: JamiStrings.whyBackupAccount
|
||||
Accessible.role: Accessible.Link
|
||||
onIgnore: {
|
||||
root.ignoreClicked();
|
||||
}
|
||||
@ -95,20 +131,24 @@ FocusScope {
|
||||
}
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader_customizeTip
|
||||
active: type === "customize"
|
||||
sourceComponent: CustomizeTipBox {
|
||||
Accessible.role: Accessible.Link
|
||||
textColor: root.textColor
|
||||
iconColor: root.iconColor
|
||||
}
|
||||
width: parent.width
|
||||
focus: true
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader_infoTip
|
||||
active: type === "tip"
|
||||
sourceComponent: InformativeTipBox {
|
||||
Accessible.role: Accessible.Link
|
||||
maxHeight: root.maximumHeight
|
||||
textColor: root.textColor
|
||||
iconColor: root.iconColor
|
||||
@ -159,6 +199,8 @@ FocusScope {
|
||||
id: component_btnClose
|
||||
PushButton {
|
||||
id: btnClose
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: JamiStrings.dismissTip
|
||||
|
||||
width: 20
|
||||
height: 20
|
||||
|
||||
@ -18,7 +18,6 @@ import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Qt5Compat.GraphicalEffects
|
||||
|
||||
import net.jami.Adapters 1.1
|
||||
import net.jami.Constants 1.1
|
||||
import net.jami.Enums 1.1
|
||||
@ -39,6 +38,10 @@ ListSelectionView {
|
||||
onPresented: LRCInstance.deselectConversation()
|
||||
leftPaneItem: viewCoordinator.getView("SidePanel", true)
|
||||
|
||||
Accessible.role: Accessible.Pane
|
||||
Accessible.name: title
|
||||
Accessible.description: JamiStrings.description
|
||||
|
||||
property variant uiCustomization: CurrentAccount.uiCustomization
|
||||
|
||||
onUiCustomizationChanged: {
|
||||
@ -277,6 +280,9 @@ ListSelectionView {
|
||||
preferredWidth: textSize.width + 2 * JamiTheme.preferredMarginSize
|
||||
text: JamiStrings.aboutJami
|
||||
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: text
|
||||
|
||||
onClicked: viewCoordinator.presentDialog(appWindow, "mainview/components/AboutPopUp.qml")
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user