Compare commits

...

50 Commits

Author SHA1 Message Date
7a759dab7a Push-To-Talk : add global and local ptt
It works with a Pimpl which the right pttlistener.cpp depending
on the platform you are on (macOs, windows or X11). It is a
global PTT which listen to key events during calls. If the
global PTT is not supported, a local PTT is set.

https://git.jami.net/savoirfairelinux/jami-project/-/issues/1402

Change-Id: I8399800966c737bb8e8a656ecbb6af7ac7cdde8c
2023-10-30 09:31:26 -04:00
d2e87150b4 misc: fix build on fedora 39
Change-Id: I0b64db0a418e9992dcafa053c762e153a65515b8
2023-10-30 08:40:46 -04:00
ec60458dbe misc: fix sidepanel and donation date
Change-Id: I98294ccfb1ae68b45260f3e66bdce3e179ee55a9
2023-10-26 15:57:11 -04:00
8a9aea2f28 Patch menu: position of the popup
Change-Id: I9a07dccc7bb4a17c0ce3046906f922d5ace35f8a
2023-10-26 11:15:47 -04:00
ae86464658 Chat setting view: add darktheme color
GitLab: #1369

Change-Id: I863d13dc924e3e0d12dd92f9fb2b8d48bad051f4
2023-10-25 13:10:44 -04:00
5f0163df05 Menu: add some details on menu
GitLab: #1388
Change-Id: Ia38dbd15b176afcaf7c03b6612695ee5b6e89723
2023-10-25 11:34:53 -04:00
493addcbd8 Menu: refactor menu
GitLab: #1388

Change-Id: Ia168dce60ffdafa1ab4d08905c46f47f98625916
2023-10-24 15:20:03 -04:00
f144b27db8 misc: bump daemon
Change-Id: I3d6a777d5b482f0810144780c333a292ce0e3f5c
2023-10-24 14:52:38 -04:00
861c42e3d5 fix: don't remove the daemon cache dir
Change-Id: Icde3c4f5dbb54c2ae93712434f5d08def4e3c3bb
2023-10-24 13:20:29 -04:00
873c4c72b9 i18n: automatic bump
Change-Id: Id0905136d6091270819b9ae8b37d3e9be5d9c1dc
2023-10-23 16:47:01 -04:00
3e012c32d5 Welcome view: set default title to false and resize logo
GitLab: #1334

Change-Id: I71930584b3f5e0925ba8f5f42fff669ff9237dd1
2023-10-23 14:41:23 -04:00
6bff3c54f1 TroubleshootingSetting: Connection monitoring
Change-Id: Idf922df701cdf2efc2d167362dca021897d8e2e5
2023-10-23 13:39:13 -04:00
e55eaa5d8e packaging: add fedora 39, ubuntu 23.10
Change-Id: I2da6a821b25c3a5ae26ba8f59f3dc8b6656751b5
2023-10-20 09:16:08 -04:00
1a17735d55 misc: bump daemon
Change-Id: I20cbebf0bea67385b08fa879884ce2a7f8634d52
2023-10-19 15:52:03 -04:00
4e5f153230 Message button: set circled false
Change-Id: I58aee3397e46025a79321e2a54211f72d299077e
2023-10-19 15:23:12 -04:00
15351a5aae splitview: hide handles when in single-pane mode
Prevents breaking the UI.

Gitlab: #1370
Change-Id: I6bad222c2a05dc66402bc8f86e17f9a6d4d99c99
2023-10-18 13:01:58 -04:00
e89aa95673 Donation: show the tipbox only after the 1st November 2023
Change-Id: If2bb725a0be137a55a29cd7592726c4f2c718c8a
2023-10-17 14:29:49 -04:00
3609dae584 pushbutton: circled default to true
Change-Id: I85967917eae6d69f534aebeaae998454a9a6a4c0
2023-10-17 15:01:45 -03:00
8b21b0fda9 Share popup: fix font size
Change-Id: Ied676c0bcea675735274362ecc35de504c4c7fa9
2023-10-17 10:02:33 -04:00
811a93cc27 Chat settings: refactor chat settings
GitLab: #1369
Change-Id: I1bd9dfab7526a9cd0d84205817ab4eae951dba90
2023-10-17 08:31:05 -04:00
baeb90bced i18n: automatic bump
Change-Id: I5f6e1f01940f43a6e4d8ffd8c497a848ed981971
2023-10-16 16:42:38 -04:00
439fea530d PushButton: Remove transparent color who break the animation
PopUp: Add shadow on the SharePopup

Change-Id: I3829fb651116e2ce8da05e71ecb61a67356748c7
2023-10-16 12:57:16 -04:00
55415d6062 Donation campaign: add toggleswitch setting
GitLab: #1334
Change-Id: Ic0e2a4b08db7228e4a4bdab665f53adfa581e16c
2023-10-13 09:23:36 -04:00
9d3b5cd0c5 Donation campaign: add donate tipbox
GitLab: #1334
Change-Id: Ie32b6278fb28381524936baabf09ee3cbba04eb6
2023-10-11 11:25:05 -04:00
4e549d123e misc: use the cache dir instead of the data dir as the cache dir
Gitlab: #1378
Change-Id: I0249a87fba240eb65165fc79bdbc0ffb55f00af8
2023-10-11 09:51:54 -04:00
77193b26d9 eleutheria: update welcome page for release
GitLab: #1334
Change-Id: Ibe19091076f3b041517f32684a248700c0fce7ff
2023-10-10 15:13:02 -04:00
afb514ee02 i18n: automatic bump
Change-Id: I2a892bc8ee46e169865397d771d3e9d233468911
2023-10-09 16:43:02 -04:00
f1ccd5d05d downloader: use native separators when building target file path
Also reverts waiting on the msiexec process + error checking.

Change-Id: Icfd8c349087d1b9f84c95d855b68b7ef2e45b3ab
2023-10-05 19:12:07 -04:00
6a0963d37b misc: bump daemon
Change-Id: Ia78ee9a1946d79b68b0761642b37f90a77182a68
2023-10-05 17:13:29 -04:00
6fc30b51d6 windows: updates: make UI represent underlying update states
This commit fixes several issues:
- the update confirmation dialog getting stuck in the open state
- secondary attempts to download an update possibly causing a crash
- poor error information presented in the case of missing content
- unhandled errors during MSI package installation

Gitlab: #1367
Change-Id: Ia8855b8268ab13b8e1cbbb15de75d41f593f947a
2023-10-03 17:49:04 -04:00
2719f303d9 misc: bump daemon
Change-Id: I8a3fe51e2d868f25c482b1a57bea82bc976a457a
2023-10-03 16:30:22 -04:00
100756b02d viewmanager: allow creating more than 1 instance of a view
Previously, managed views were always stored in a dictionary using non-unique keys. This commit adds a method to the ViewManager component allowing for automatic unique key generation if the base key (QML component path) is the same. This is used for dialogs because we need to possibly open nested modal dialogs.

Gitlab: #1367
Change-Id: I94e0ef0e0ae79689445be0409dd902dc74554e43
2023-10-03 15:38:39 -04:00
b963a0bdf2 Avoid infinite loops in MainApplication::cleanup
Change-Id: I910ab554c463a3d91c48c297c6c1ed48202283f9
2023-10-03 15:18:47 -04:00
d765fc9297 PluginStoreEndPoint: add possibility to change the plugin store end point
Gitlab: #1341
Change-Id: Ib4516c6cf2361a4976230a6b056a4c072932a92b
2023-10-03 13:55:05 -04:00
f8f1301fa0 i18n: automatic bump
Change-Id: I35a6a56c9e7ddd8f83ef0a388ed7b7ec6d6f72d7
2023-10-02 16:42:38 -04:00
b9d24298f7 Donation campaign: add banner in smartlist
GitLab: #1334
Change-Id: I53b23eabab47389b9bea50f54afac28d41741b0b
2023-09-29 20:04:04 -04:00
6b9ce14ca9 messagerbar: add continue editing tooltip
Change-Id: Ifa69df02610e0d104b6a0bf338ded3128e2be9b7
GitLab: #1359
2023-09-29 05:06:41 -04:00
f88b8584af deploy-packages: add alma
Change-Id: I5ff774d6e2eceb3ce99d16eae34249ee451f9199
2023-09-29 02:18:36 -04:00
ad35d108f2 link-device: apply new design and add QR code
GitLab: #1253
Change-Id: Ib47a081e4e5d714e98fb397732ff9232b62afc36
2023-09-28 16:59:20 -04:00
63c3d0bf2e Build: build without dbus if enable_libwrap is not specified
Change-Id: I8819b193b83f7ee051d78d30990db40e3f295354
2023-09-28 11:37:54 -04:00
6f8f96edfd Correct some bug MessageBar
Change-Id: I198763539ba1b093ef9dfbc6f429ba15dcf93285
2023-09-26 17:03:27 -04:00
1bd7d75d29 Fingerprint : prevent overflow when zooming
GitLab: #1347
Change-Id: I2b1862b1df7b2bcc7c173a04b50c006d861241d2
2023-09-26 12:01:03 -04:00
ad29993e17 AboutJami button : text scale with text size
GitLab: #1348
Change-Id: I442b4ca074113ca4460757780b1bcc0b1675a35e
2023-09-26 11:15:10 -04:00
70ce0c091e i18n: automatic bump
Change-Id: I9b9ac457d4c71a343af793ad15bd6ce8c2ed4089
2023-09-25 16:43:03 -04:00
ea5b2d6589 misc: bump daemon
Change-Id: I9d10579e5bb231f4b457a0fd9f3c36c8bc491dbc
2023-09-22 15:04:16 -04:00
eaababc817 callactionbar: fix submenus layouts
Change-Id: I1d100b48db6ad95bf5e09642e9c12aad8ccf110a
2023-09-21 08:45:09 -04:00
aa96b723bc misc: bump daemon
Change-Id: I8ec5348b0a37c06e81ad3fc46c11822556391694
2023-09-20 21:16:46 -04:00
1616261bef misc: update plugin-store after plugin uninstall
Change-Id: Ibbb428e17f362f3645a530ad55fbd87d6719f98d
2023-09-20 14:58:32 -04:00
926ab72334 markdown: fix keyboard shortcuts
Change-Id: Ic02ab2df7a4a3870dbbe2f0e23160f13281ba2ac
GitLab: #1321
2023-09-20 14:54:54 -04:00
a6d16ba1f8 misc: pass HideSelf to true by default
Change-Id: I507ec00f9d94ae9cec5f63ca948bca1f9cdd82b3
2023-09-20 13:13:23 -04:00
228 changed files with 52380 additions and 31271 deletions

View File

@ -244,6 +244,8 @@ set(COMMON_SOURCES
${APP_SRC_DIR}/messageparser.cpp
${APP_SRC_DIR}/previewengine.cpp
${APP_SRC_DIR}/imagedownloader.cpp
${APP_SRC_DIR}/pluginversionmanager.cpp
${APP_SRC_DIR}/connectioninfolistmodel.cpp
${APP_SRC_DIR}/pluginversionmanager.cpp)
set(COMMON_HEADERS
@ -310,8 +312,9 @@ set(COMMON_HEADERS
${APP_SRC_DIR}/messageparser.h
${APP_SRC_DIR}/htmlparser.h
${APP_SRC_DIR}/imagedownloader.h
${APP_SRC_DIR}/pluginversionmanager.h)
${APP_SRC_DIR}/pluginversionmanager.h
${APP_SRC_DIR}/connectioninfolistmodel.h
${APP_SRC_DIR}/pttlistener.h)
# For libavutil/avframe.
set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib")
@ -493,6 +496,29 @@ else()
OPTIONAL_COMPONENTS LinguistTools)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
if (DEFINED ENV{XDG_SESSION_TYPE})
if ($ENV{XDG_SESSION_TYPE} STREQUAL "x11")
set(PTT_PLATFORM "x11")
list(APPEND COMMON_HEADER ${APP_SRC_DIR}/platform/X11/xcbkeyboard.H)
# TODO: add Wayland support
endif ()
endif ()
elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(PTT_PLATFORM "windows")
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set(PTT_PLATFORM "macos")
endif ()
if (NOT ${PTT_PLATFORM} STREQUAL "")
message(STATUS "Platform: ${PTT_PLATFORM}")
add_definitions(-DHAVE_GLOBAL_PTT)
list(APPEND COMMON_SOURCES ${APP_SRC_DIR}/platform/${PTT_PLATFORM}/pttlistener.cpp)
else ()
message(WARNING "Global push-to-talk not supported.")
list(APPEND COMMON_SOURCES ${APP_SRC_DIR}/platform/local/pttlistener.cpp)
endif ()
# common includes
include_directories(
${PROJECT_SOURCE_DIR}
@ -593,7 +619,6 @@ elseif (NOT APPLE)
${GLIB_LIBRARIES}
${GIO_LIBRARIES})
# Installation rules
install(
TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin)
@ -724,7 +749,7 @@ else()
list(APPEND CLIENT_LIBS
"-framework AVFoundation"
"-framework CoreAudio -framework CoreMedia -framework CoreVideo"
"-framework VideoToolbox -framework AudioUnit"
"-framework VideoToolbox -framework AudioUnit -framework Carbon"
"-framework Security"
compression
resolv

2
daemon

Submodule daemon updated: 86d147d080...a7e2c494d1

View File

@ -49,7 +49,7 @@ QT_MAJOR := 6
QT_MINOR := 4
QT_PATCH := 3
QT_TARBALL_CHECKSUM := 29a7eebdbba0ea57978dea6083709c93593a60f0f3133a3de08b9571ee8eaab4
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-2
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-3
DEBIAN_QT_DSC_FILENAME := libqt-jami_$(DEBIAN_QT_VERSION).dsc
QT_JAMI_PREFIX := /usr/lib/libqt-jami
@ -167,8 +167,10 @@ DISTRIBUTIONS := \
ubuntu_20.04 \
ubuntu_22.04 \
ubuntu_23.04 \
ubuntu_23.10 \
fedora_37 \
fedora_38 \
fedora_39 \
opensuse-leap_15.4 \
snap

View File

@ -0,0 +1,104 @@
FROM fedora:39
RUN dnf clean all
RUN dnf update -y
RUN dnf install -y dnf-command\(builddep\) rpmdevtools && \
dnf install -y mock
RUN dnf groupinstall -y "X Software Development"
RUN dnf install -y \
git \
rpm-build \
tar \
make \
autoconf \
automake \
nasm \
speexdsp-devel \
pulseaudio-libs-devel \
libcanberra-devel \
libcurl-devel \
libtool \
mesa-libgbm-devel \
mesa-dri-drivers \
dbus-devel \
expat-devel \
pcre-devel \
yaml-cpp-devel \
libXext-devel \
libXfixes-devel \
yasm \
speex-devel \
gsm-devel \
chrpath \
check \
astyle \
uuid-c++-devel \
gettext-devel \
gcc-c++ \
which \
alsa-lib-devel \
systemd-devel \
libuuid-devel \
uuid-devel \
gnutls-devel \
nettle-devel \
opus-devel \
patch \
jsoncpp-devel \
libnatpmp-devel \
webkitgtk4-devel \
cryptopp-devel \
libva-devel \
libvdpau-devel \
msgpack-devel \
NetworkManager-libnm-devel \
openssl-devel \
clutter-devel \
clutter-gtk-devel \
libappindicator-gtk3-devel \
libnotify-devel \
libupnp-devel \
qrencode-devel \
libargon2-devel \
libsndfile-devel \
libdrm \
gperf \
bison \
clang \
clang-devel \
llvm-devel \
nodejs \
flex \
gstreamer1 gstreamer1-devel \
gstreamer1-plugins-base-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
nss-devel \
libxcb* \
libxkb* \
libX11-devel \
vulkan-devel \
libXrender-devel \
xcb-util-* \
xz \
xkeyboard-config \
libnotify \
wget \
libstdc++-static \
sqlite-devel \
perl-generators \
perl-English \
libxshmfence-devel \
ninja-build \
clang \
cmake \
fmt-devel \
python3.10 \
cups-devel
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
CMD ["/opt/build-package-rpm.sh"]

View File

@ -0,0 +1,22 @@
FROM ubuntu:23.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
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
CMD ["/opt/build-package-debian.sh"]

View File

@ -0,0 +1,81 @@
From ecae5d93b0a89e2b8c16a2227b2d176f58579d04 Mon Sep 17 00:00:00 2001
From: Rémi Denis-Courmont <remi@remlab.net>
Date: Sun, 16 Jul 2023 18:18:02 +0300
Subject: [PATCH] Fix ffmpeg assembly with newer binutil
avcodec/x86/mathops: clip constants used with shift instructions within inline assembly
Fixes assembling with binutil as >= 2.41
FFmpeg commit effadce6c756247ea8bae32dc13bb3e6f464f0eb.
Deals with: "Error: operand type mismatch for `shr'"
Fixes: QTBUG-116649
Change-Id: I094e8c23fed4a61fba3f1e3a9c73c016d129d830
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/495990
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
(cherry picked from commit 29354c7c7def7bdc66bcd25d401677fd9421f657)
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/509219
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
---
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h b/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
index 6298f5e..ca7e2df 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
+++ b/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
@@ -35,12 +35,20 @@
static av_always_inline av_const int MULL(int a, int b, unsigned shift)
{
int rt, dummy;
+ if (__builtin_constant_p(shift))
__asm__ (
"imull %3 \n\t"
"shrdl %4, %%edx, %%eax \n\t"
:"=a"(rt), "=d"(dummy)
- :"a"(a), "rm"(b), "ci"((uint8_t)shift)
+ :"a"(a), "rm"(b), "i"(shift & 0x1F)
);
+ else
+ __asm__ (
+ "imull %3 \n\t"
+ "shrdl %4, %%edx, %%eax \n\t"
+ :"=a"(rt), "=d"(dummy)
+ :"a"(a), "rm"(b), "c"((uint8_t)shift)
+ );
return rt;
}
@@ -113,19 +121,31 @@
// avoid +32 for shift optimization (gcc should do that ...)
#define NEG_SSR32 NEG_SSR32
static inline int32_t NEG_SSR32( int32_t a, int8_t s){
+ if (__builtin_constant_p(s))
__asm__ ("sarl %1, %0\n\t"
: "+r" (a)
- : "ic" ((uint8_t)(-s))
+ : "i" (-s & 0x1F)
);
+ else
+ __asm__ ("sarl %1, %0\n\t"
+ : "+r" (a)
+ : "c" ((uint8_t)(-s))
+ );
return a;
}
#define NEG_USR32 NEG_USR32
static inline uint32_t NEG_USR32(uint32_t a, int8_t s){
+ if (__builtin_constant_p(s))
__asm__ ("shrl %1, %0\n\t"
: "+r" (a)
- : "ic" ((uint8_t)(-s))
+ : "i" (-s & 0x1F)
);
+ else
+ __asm__ ("shrl %1, %0\n\t"
+ : "+r" (a)
+ : "c" ((uint8_t)(-s))
+ );
return a;
}

View File

@ -0,0 +1,16 @@
qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
index 3488120..120e47a 100644
--- a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
+++ b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
@@ -472,7 +472,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
}
catch (const DeadlyImportError& e)
{
- if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
+ if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
}
throw;

View File

@ -0,0 +1,433 @@
qtbase/src/corelib/debug_script.py | 2 +-
qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py | 2 +-
qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py | 2 +-
qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py | 2 +-
.../3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py | 2 +-
qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py | 2 +-
qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py | 2 +-
31 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/qtbase/src/corelib/debug_script.py b/qtbase/src/corelib/debug_script.py
index f6207c6104..663c8e0ac1 100644
--- a/qtbase/src/corelib/debug_script.py
+++ b/qtbase/src/corelib/debug_script.py
@@ -3,7 +3,7 @@
import os
import sys
-import imp
+import importlib
from distutils.version import LooseVersion
diff --git a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
index 681039d34b..a1fe56fa05 100644
--- a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
+++ b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
@@ -16,7 +16,7 @@ import subprocess
import sys
import tempfile
import time
-import imp
+import importlib
# from TestCasePackagerConfig import *
diff --git a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
index 92d4e6139b..7a18e12ced 100644
--- a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
+++ b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
@@ -7,7 +7,7 @@ import unittest
import os
import yaml
-import imp
+import importlib
# add parent dir to search path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py b/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
index c7412927c8..ad2caff318 100755
--- a/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
+++ b/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
@@ -5,7 +5,7 @@
import os
import sys
-import imp
+import importlib
import tempfile
import unittest
import PRESUBMIT
diff --git a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
index 5daee773ba..2d6b124162 100755
--- a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
+++ b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
@@ -9,7 +9,7 @@
"""
from __future__ import print_function
import abc
-import imp
+import importlib
import optparse
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
index bf626f5479..3fae129aaa 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
@@ -3,7 +3,7 @@
# found in the LICENSE file.
import errno
-import imp
+import importlib
import os.path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
index ff5753a291..04fc34f742 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import shutil
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
index 32c884a8c0..e761faa54c 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
index 95a916db08..4331e2fbfa 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
index 62798631db..28e9dbf705 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
index cba249b0f3..5a4051827a 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
index 4a2fefc712..11a9879cb7 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
index cc17ae0253..bcc944f06b 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
index bd72830e54..f2fdc9ae28 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py b/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
index 1feb303a48..8428de61bb 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
@@ -6,7 +6,7 @@
angle_presubmit_utils_unittest.py: Top-level unittest script for ANGLE presubmit checks.
"""
-import imp
+import importlib
import os
import unittest
from angle_presubmit_utils import *
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py b/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
index ed4f38c67b..cac734cefa 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
@@ -7,7 +7,7 @@ See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into gcl.
"""
-import imp
+import importlib
import inspect
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py b/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
index 0244c9787e..f535afe99c 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
@@ -32,7 +32,7 @@ if PY3:
memoryview_type = memoryview
struct_bool_decl = "?"
else:
- import imp
+ import importlib
string_types = (unicode,)
if PY26 or PY27:
binary_types = (str,bytearray)
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py b/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
index 8430390eea..29212205bc 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
@@ -732,7 +732,7 @@ class Environment(object):
)
py_compile = False
else:
- import imp
+ import importlib
import marshal
py_header = imp.get_magic() + u"\xff\xff\xff\xff".encode("iso-8859-15")
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py b/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
index 06bb8d99f5..05089dc982 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
@@ -115,7 +115,7 @@ if py3k:
return module
else:
- import imp
+ import importlib
def load_module(module_id, path):
fp = open(path, "rb")
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
index a7dc683365..68b6804c78 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for call_trees module."""
-import imp
+import importlib
from tensorflow.python.autograph.converters import call_trees
from tensorflow.python.autograph.converters import functions
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
index 81a7fde808..1370f900fd 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for converter module."""
-import imp
+import importlib
from tensorflow.python.autograph.core import converter
from tensorflow.python.autograph.core import converter_testing
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
index b93cbb627b..452ec71f5b 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
@@ -15,7 +15,7 @@
"""Base class for tests in this module."""
import contextlib
-import imp
+import importlib
import inspect
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
index 9a62d7c0d2..7ec4fa6dca 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
@@ -19,7 +19,7 @@ import collections
import contextlib
import functools
import gc
-import imp
+import importlib
import inspect
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
index 852af3efe7..6456c50446 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for conversion module."""
-import imp
+import importlib
import sys
import types
import weakref
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
index a50a64534a..ba0f31afa2 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
@@ -17,7 +17,7 @@
import abc
import collections
import functools
-import imp
+import importlib
import textwrap
import six
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
index 29f38d853a..7ca88fa371 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for templates module."""
-import imp
+import importlib
from absl.testing import parameterized
import gast
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
index e46460574b..a40fea6568 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
@@ -14,7 +14,7 @@
# =============================================================================
"""Tests for create_python_api."""
-import imp
+import importlib
import sys
from tensorflow.python.platform import test
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
index 73d1742714..ea77dd7647 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
@@ -1,5 +1,5 @@
import importlib
-import imp
+import importlib
from .browsers import product_list
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
index 6a744472b5..9175cb5d34 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
@@ -1,6 +1,6 @@
import copy
import functools
-import imp
+import importlib
import io
import os
from collections import OrderedDict, defaultdict
diff --git a/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py b/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
index 6912b6f3c0..7d851f7f76 100755
--- a/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
+++ b/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
@@ -16,7 +16,7 @@
from __future__ import print_function
-import imp
+import importlib
import optparse
import os
import pipes
diff --git a/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py b/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
index 1c2aba80af..55260d697e 100644
--- a/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
+++ b/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
@@ -10,7 +10,7 @@ from __future__ import print_function
import os
import re
-import imp
+import importlib
from _monkeyYaml import load as yamlLoad

View File

@ -1,2 +1,5 @@
0001-fix-gcc13.patch
0002-OpenFile-portal-do-not-use-O_PATH-fds.patch
0002-OpenFile-portal-do-not-use-O_PATH-fds.patch
0003-fix-mathops.patch
0004-fix-binary-tokenizer.patch
0005-importlib.patch

View File

@ -101,6 +101,8 @@ if [ -f /etc/os-release ]; then
ENDTAG="ubuntu_22.04"
elif [ "${UBUNTU_CODENAME}" = "lunar" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_23.04" ]; then
ENDTAG="ubuntu_23.04"
elif [ "${UBUNTU_CODENAME}" = "mantic" ] || [ "${ID}_${VERSION_ID}" = "ubuntu_23.10" ]; then
ENDTAG="ubuntu_23.10"
elif [ "${ID}" = "debian" ] && \
[ "$(command -v lsb_release)" ] && \
[ "$(lsb_release -rs)" = "testing" ]; then

View File

@ -28,6 +28,9 @@ URL: https://jami.net/
Source: jami-libqt-%{version}.tar.xz
Patch0: 0001-fix-gcc13.patch
Patch1: 0002-OpenFile-portal-do-not-use-O_PATH-fds.patch
Patch2: 0003-fix-mathops.patch
Patch3: 0004-fix-binary-tokenizer.patch
Patch4: 0005-importlib.patch
%global gst 0.10
%if 0%{?fedora} || 0%{?rhel} > 7
@ -42,6 +45,7 @@ BuildRequires: bison
BuildRequires: gperf
BuildRequires: flex
BuildRequires: vulkan-devel
BuildRequires: python-six
%if %{defined suse_version}
BuildRequires: ffmpeg-devel
BuildRequires: ffmpeg
@ -64,6 +68,9 @@ This package contains Qt libraries for Jami.
%setup -n qt-everywhere-src-%{version}
%patch0 -p1
%patch1 -p1
%patch2 -p1
%patch3 -p1
%patch4 -p1
%build
echo "Building Qt using %{job_count} parallel jobs"
@ -84,6 +91,15 @@ cat qtbase/src/corelib/global/qendian.h
sed -i 's,#include <string.h>,#include <string.h>\n#include <limits>,g' qtbase/src/corelib/global/qfloat16.h
sed -i 's,#include <QtCore/qbytearray.h>,#include <QtCore/qbytearray.h>\n#include <limits>,g' qtbase/src/corelib/text/qbytearraymatcher.h
cat qtwebengine/configure.cmake
#https://bugreports.qt.io/browse/QTBUG-117979
if test -f "/usr/bin/python3.10"; then
/usr/bin/python3.10 -m venv env
source env/bin/activate
python -m pip install html5lib
python -m pip install six
fi
# recent gcc version do not like lto from qt
CXXFLAGS="${CXXFLAGS} -fno-lto" CFLAGS="${CFLAGS} -fno-lto" LDFLAGS="$(CFLAGS) ${LDFLAGS}" ./configure \
-opensource \

View File

@ -0,0 +1,81 @@
From ecae5d93b0a89e2b8c16a2227b2d176f58579d04 Mon Sep 17 00:00:00 2001
From: Rémi Denis-Courmont <remi@remlab.net>
Date: Sun, 16 Jul 2023 18:18:02 +0300
Subject: [PATCH] Fix ffmpeg assembly with newer binutil
avcodec/x86/mathops: clip constants used with shift instructions within inline assembly
Fixes assembling with binutil as >= 2.41
FFmpeg commit effadce6c756247ea8bae32dc13bb3e6f464f0eb.
Deals with: "Error: operand type mismatch for `shr'"
Fixes: QTBUG-116649
Change-Id: I094e8c23fed4a61fba3f1e3a9c73c016d129d830
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/495990
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
(cherry picked from commit 29354c7c7def7bdc66bcd25d401677fd9421f657)
Reviewed-on: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/509219
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
---
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h b/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
index 6298f5e..ca7e2df 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
+++ b/qtwebengine/src/3rdparty/chromium/third_party/ffmpeg/libavcodec/x86/mathops.h
@@ -35,12 +35,20 @@
static av_always_inline av_const int MULL(int a, int b, unsigned shift)
{
int rt, dummy;
+ if (__builtin_constant_p(shift))
__asm__ (
"imull %3 \n\t"
"shrdl %4, %%edx, %%eax \n\t"
:"=a"(rt), "=d"(dummy)
- :"a"(a), "rm"(b), "ci"((uint8_t)shift)
+ :"a"(a), "rm"(b), "i"(shift & 0x1F)
);
+ else
+ __asm__ (
+ "imull %3 \n\t"
+ "shrdl %4, %%edx, %%eax \n\t"
+ :"=a"(rt), "=d"(dummy)
+ :"a"(a), "rm"(b), "c"((uint8_t)shift)
+ );
return rt;
}
@@ -113,19 +121,31 @@
// avoid +32 for shift optimization (gcc should do that ...)
#define NEG_SSR32 NEG_SSR32
static inline int32_t NEG_SSR32( int32_t a, int8_t s){
+ if (__builtin_constant_p(s))
__asm__ ("sarl %1, %0\n\t"
: "+r" (a)
- : "ic" ((uint8_t)(-s))
+ : "i" (-s & 0x1F)
);
+ else
+ __asm__ ("sarl %1, %0\n\t"
+ : "+r" (a)
+ : "c" ((uint8_t)(-s))
+ );
return a;
}
#define NEG_USR32 NEG_USR32
static inline uint32_t NEG_USR32(uint32_t a, int8_t s){
+ if (__builtin_constant_p(s))
__asm__ ("shrl %1, %0\n\t"
: "+r" (a)
- : "ic" ((uint8_t)(-s))
+ : "i" (-s & 0x1F)
);
+ else
+ __asm__ ("shrl %1, %0\n\t"
+ : "+r" (a)
+ : "c" ((uint8_t)(-s))
+ );
return a;
}

View File

@ -0,0 +1,16 @@
qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
index 3488120..120e47a 100644
--- a/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
+++ b/qt3d/src/3rdparty/assimp/src/code/AssetLib/FBX/FBXBinaryTokenizer.cpp
@@ -472,7 +472,7 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length)
}
catch (const DeadlyImportError& e)
{
- if (!is64bits && (length > std::numeric_limits<std::uint32_t>::max())) {
+ if (!is64bits && (length > std::numeric_limits<uint32_t>::max())) {
throw DeadlyImportError("The FBX file is invalid. This may be because the content is too big for this older version (", ai_to_string(version), ") of the FBX format. (", e.what(), ")");
}
throw;

View File

@ -0,0 +1,433 @@
qtbase/src/corelib/debug_script.py | 2 +-
qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py | 2 +-
qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py | 2 +-
qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py | 2 +-
.../src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py | 2 +-
.../3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py | 2 +-
qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py | 2 +-
qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py | 2 +-
qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py | 2 +-
31 files changed, 31 insertions(+), 31 deletions(-)
diff --git a/qtbase/src/corelib/debug_script.py b/qtbase/src/corelib/debug_script.py
index f6207c6104..663c8e0ac1 100644
--- a/qtbase/src/corelib/debug_script.py
+++ b/qtbase/src/corelib/debug_script.py
@@ -3,7 +3,7 @@
import os
import sys
-import imp
+import importlib
from distutils.version import LooseVersion
diff --git a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
index 681039d34b..a1fe56fa05 100644
--- a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
+++ b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/parseTestRecord.py
@@ -16,7 +16,7 @@ import subprocess
import sys
import tempfile
import time
-import imp
+import importlib
# from TestCasePackagerConfig import *
diff --git a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
index 92d4e6139b..7a18e12ced 100644
--- a/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
+++ b/qtdeclarative/tests/auto/qml/ecmascripttests/test262/tools/packaging/test/test_monkeyYaml.py
@@ -7,7 +7,7 @@ import unittest
import os
import yaml
-import imp
+import importlib
# add parent dir to search path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py b/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
index c7412927c8..ad2caff318 100755
--- a/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
+++ b/qtwebengine/src/3rdparty/chromium/chrome/browser/resources/PRESUBMIT_test.py
@@ -5,7 +5,7 @@
import os
import sys
-import imp
+import importlib
import tempfile
import unittest
import PRESUBMIT
diff --git a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
index 5daee773ba..2d6b124162 100755
--- a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
+++ b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
@@ -9,7 +9,7 @@
"""
from __future__ import print_function
import abc
-import imp
+import importlib
import optparse
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
index bf626f5479..3fae129aaa 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
@@ -3,7 +3,7 @@
# found in the LICENSE file.
import errno
-import imp
+import importlib
import os.path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
index ff5753a291..04fc34f742 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import shutil
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
index 32c884a8c0..e761faa54c 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
index 95a916db08..4331e2fbfa 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
index 62798631db..28e9dbf705 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
index cba249b0f3..5a4051827a 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
index 4a2fefc712..11a9879cb7 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
index cc17ae0253..bcc944f06b 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
index bd72830e54..f2fdc9ae28 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import imp
+import importlib
import os.path
import sys
import unittest
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py b/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
index 1feb303a48..8428de61bb 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/angle/scripts/angle_presubmit_utils_unittest.py
@@ -6,7 +6,7 @@
angle_presubmit_utils_unittest.py: Top-level unittest script for ANGLE presubmit checks.
"""
-import imp
+import importlib
import os
import unittest
from angle_presubmit_utils import *
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py b/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
index ed4f38c67b..cac734cefa 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/PRESUBMIT.py
@@ -7,7 +7,7 @@ See https://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
for more details about the presubmit API built into gcl.
"""
-import imp
+import importlib
import inspect
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py b/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
index 0244c9787e..f535afe99c 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/flatbuffers/src/python/flatbuffers/compat.py
@@ -32,7 +32,7 @@ if PY3:
memoryview_type = memoryview
struct_bool_decl = "?"
else:
- import imp
+ import importlib
string_types = (unicode,)
if PY26 or PY27:
binary_types = (str,bytearray)
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py b/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
index 8430390eea..29212205bc 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/jinja2/environment.py
@@ -732,7 +732,7 @@ class Environment(object):
)
py_compile = False
else:
- import imp
+ import importlib
import marshal
py_header = imp.get_magic() + u"\xff\xff\xff\xff".encode("iso-8859-15")
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py b/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
index 06bb8d99f5..05089dc982 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/mako/mako/compat.py
@@ -115,7 +115,7 @@ if py3k:
return module
else:
- import imp
+ import importlib
def load_module(module_id, path):
fp = open(path, "rb")
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
index a7dc683365..68b6804c78 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/converters/call_trees_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for call_trees module."""
-import imp
+import importlib
from tensorflow.python.autograph.converters import call_trees
from tensorflow.python.autograph.converters import functions
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
index 81a7fde808..1370f900fd 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for converter module."""
-import imp
+import importlib
from tensorflow.python.autograph.core import converter
from tensorflow.python.autograph.core import converter_testing
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
index b93cbb627b..452ec71f5b 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/core/converter_testing.py
@@ -15,7 +15,7 @@
"""Base class for tests in this module."""
import contextlib
-import imp
+import importlib
import inspect
import sys
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
index 9a62d7c0d2..7ec4fa6dca 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/api_test.py
@@ -19,7 +19,7 @@ import collections
import contextlib
import functools
import gc
-import imp
+import importlib
import inspect
import os
import re
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
index 852af3efe7..6456c50446 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/impl/conversion_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for conversion module."""
-import imp
+import importlib
import sys
import types
import weakref
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
index a50a64534a..ba0f31afa2 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/inspect_utils_test.py
@@ -17,7 +17,7 @@
import abc
import collections
import functools
-import imp
+import importlib
import textwrap
import six
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
index 29f38d853a..7ca88fa371 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/autograph/pyct/templates_test.py
@@ -14,7 +14,7 @@
# ==============================================================================
"""Tests for templates module."""
-import imp
+import importlib
from absl.testing import parameterized
import gast
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
index e46460574b..a40fea6568 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/tflite/src/tensorflow/python/tools/api/generator/create_python_api_test.py
@@ -14,7 +14,7 @@
# =============================================================================
"""Tests for create_python_api."""
-import imp
+import importlib
import sys
from tensorflow.python.platform import test
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
index 73d1742714..ea77dd7647 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/products.py
@@ -1,5 +1,5 @@
import importlib
-import imp
+import importlib
from .browsers import product_list
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
index 6a744472b5..9175cb5d34 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/wpt_tools/wpt/tools/wptrunner/wptrunner/stability.py
@@ -1,6 +1,6 @@
import copy
import functools
-import imp
+import importlib
import io
import os
from collections import OrderedDict, defaultdict
diff --git a/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py b/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
index 6912b6f3c0..7d851f7f76 100755
--- a/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
+++ b/qtwebengine/src/3rdparty/chromium/tools/sublime/ninja_options_script.py
@@ -16,7 +16,7 @@
from __future__ import print_function
-import imp
+import importlib
import optparse
import os
import pipes
diff --git a/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py b/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
index 1c2aba80af..55260d697e 100644
--- a/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
+++ b/qtwebengine/src/3rdparty/chromium/v8/third_party/test262-harness/src/parseTestRecord.py
@@ -10,7 +10,7 @@ from __future__ import print_function
import os
import re
-import imp
+import importlib
from _monkeyYaml import load as yamlLoad

View File

@ -46,7 +46,7 @@ CMAKE_PREFIX_PATH="${QT_JAMI_PREFIX}/lib/cmake:${CMAKE_PREFIX_PATH}"
QT_MAJOR=6
QT_MINOR=4
QT_PATCH=3
QT_RELEASE_PATCH=2
QT_RELEASE_PATCH=3
QT_MAJOR_MINOR=${QT_MAJOR}.${QT_MINOR}
QT_MAJOR_MINOR_PATCH=${QT_MAJOR}.${QT_MINOR}.${QT_PATCH}
@ -105,18 +105,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_33" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc33.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_34" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc34.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_35" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc35.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_36" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc36.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_37" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc37.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_38" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc38.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_39" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc39.x86_64.rpm "${RPM_PATH}"
else
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-*.rpm "${RPM_PATH}"
fi

View File

@ -272,7 +272,7 @@ function package()
{
if [[ $DISTRIBUTION =~ debian|ubuntu|raspbian|guix-deb-pack ]]; then
package_deb
elif [[ $DISTRIBUTION =~ fedora|rhel|opensuse|guix-rpm-pack ]]; then
elif [[ $DISTRIBUTION =~ alma|fedora|rhel|opensuse|guix-rpm-pack ]]; then
package_rpm
elif [[ $DISTRIBUTION =~ snap ]]; then
package_snap

View File

@ -125,6 +125,8 @@ else
if [[ "$OSTYPE" != "darwin"* ]]; then
CONFIGURE_FLAGS+=" --disable-shared"
fi
else
CONFIGURE_FLAGS+="--without-dbus"
fi
BUILD_TYPE="Release"

View File

@ -36,5 +36,7 @@
<string>Jami requires to access your microphone to make calls and record audio</string>
<key>ITSAppUsesNonExemptEncryption</key>
<true/>
<key>NSAppleEventsUsageDescription</key>
<string>Jami requires to monitor global key events for push-to-talk functionality.</string>
</dict>
</plist>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<path id="noun-connection-5025318" d="M18,6.3c1.2,0,2.2-1,2.2-2.1C20.1,3,19.2,2,18,2c-1.2,0-2.2,1-2.2,2.1c0,0.5,0.2,1.1,0.6,1.5
l-3.3,3.8c-0.8-0.6-2-0.5-2.7,0.2L7.3,7.1c0.5-0.8,0.2-1.9-0.6-2.4C5.9,4.2,4.8,4.5,4.3,5.3C3.8,6.1,4,7.2,4.9,7.7
C5.6,8.1,6.4,8,7,7.5l3.1,2.5c-0.5,0.8-0.4,1.9,0.3,2.6l-2.9,2.9c-1.1-0.7-2.5-0.4-3.2,0.7c-0.7,1.1-0.4,2.5,0.7,3.2
c1.1,0.7,2.5,0.4,3.2-0.7c0.6-0.9,0.5-2.1-0.3-2.9l2.9-2.9c0.3,0.2,0.7,0.3,1.2,0.3c0,0,0.1,0,0.1,0l0.8,4.8
c-1.1,0.3-1.7,1.4-1.4,2.5c0.3,1.1,1.4,1.7,2.5,1.4c1.1-0.3,1.7-1.4,1.4-2.5c-0.3-0.9-1-1.4-1.9-1.4c0,0-0.1,0-0.1,0l-0.8-4.8
c0.4-0.1,0.7-0.3,0.9-0.6l3.6,2.7c-0.4,0.8-0.2,1.8,0.6,2.2c0.8,0.4,1.8,0.2,2.2-0.6c0.4-0.8,0.2-1.8-0.6-2.2
c-0.6-0.4-1.4-0.3-1.9,0.2l-3.6-2.7c0.2-0.3,0.3-0.7,0.3-1.1c0-0.5-0.2-1.1-0.6-1.5l3.3-3.8C17.1,6.2,17.5,6.3,18,6.3L18,6.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<g id="noun-waiting-3611673" transform="translate(-13.64 -30.48)">
<path id="Path_278" d="M25.9,34.5c0.5,0,0.8-0.4,0.8-0.8c0-0.5-0.4-0.8-0.8-0.8c-0.5,0-0.8,0.4-0.8,0.8c0,0.2,0.1,0.4,0.2,0.6
C25.4,34.4,25.6,34.5,25.9,34.5z"/>
<path id="Path_279" d="M32.7,36.9c0.4-0.4,0.4-1.1,0-1.5c-0.4-0.4-1.1-0.4-1.5,0c-0.4,0.4-0.4,1.1,0,1.5c0.2,0.2,0.5,0.3,0.8,0.3
C32.2,37.2,32.5,37.1,32.7,36.9z"/>
<path id="Path_280" d="M34.5,41c-0.7,0-1.2,0.5-1.2,1.2s0.5,1.2,1.2,1.2c0.7,0,1.2-0.5,1.2-1.2c0-0.3-0.1-0.6-0.3-0.8
C35.1,41.1,34.8,41,34.5,41z"/>
<path id="Path_281" d="M31.9,47c-0.7,0-1.3,0.6-1.3,1.3c0,0.7,0.6,1.3,1.3,1.3c0.7,0,1.3-0.6,1.3-1.3c0-0.3-0.1-0.7-0.4-0.9
C32.6,47.1,32.3,47,31.9,47z"/>
<path id="Path_282" d="M25.9,49.4c-0.8,0-1.4,0.6-1.4,1.4c0,0.8,0.6,1.4,1.4,1.4c0.8,0,1.4-0.6,1.4-1.4c0-0.4-0.1-0.7-0.4-1
C26.6,49.5,26.2,49.4,25.9,49.4z"/>
<path id="Path_283" d="M18.7,47.2L18.7,47.2c-0.6,0.6-0.6,1.6,0,2.2c0.6,0.6,1.6,0.6,2.2,0c0.6-0.6,0.6-1.6,0-2.2
c-0.3-0.3-0.7-0.5-1.1-0.5C19.4,46.7,19,46.9,18.7,47.2z"/>
<path id="Path_284" d="M18.9,42.2c0-0.9-0.7-1.7-1.6-1.7s-1.7,0.7-1.7,1.6c0,0.9,0.7,1.7,1.6,1.7c0.4,0,0.9-0.2,1.2-0.5
C18.8,43,18.9,42.6,18.9,42.2z"/>
<path id="Path_285" d="M21.1,34.9c-0.7-0.3-1.5-0.1-1.9,0.6c-0.3,0.7-0.1,1.5,0.6,1.9c0.7,0.3,1.5,0.1,1.9-0.6
c0.1-0.2,0.2-0.5,0.1-0.7C21.8,35.5,21.5,35.1,21.1,34.9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="43" height="52.655" viewBox="0 0 43 52.655">
<defs>
<clipPath id="clip-path">
<rect id="Rectangle_268" data-name="Rectangle 268" width="38" height="24" transform="translate(-0.407 0.083)" fill="#fff" stroke="#707070" stroke-width="1"/>
</clipPath>
</defs>
<g id="Icon_Donate" transform="translate(-22 -189.345)">
<rect id="Rectangle_267" data-name="Rectangle 267" width="43" height="10" rx="5" transform="translate(22 232)" fill="#9eb3c3"/>
<path id="Path_459" data-name="Path 459" d="M9.674,17.083,8.562,16.07C4.609,12.486,2,10.122,2,7.221A4.18,4.18,0,0,1,6.221,3,4.6,4.6,0,0,1,9.674,4.6,4.6,4.6,0,0,1,13.128,3a4.18,4.18,0,0,1,4.221,4.221c0,2.9-2.609,5.265-6.562,8.856Z" transform="translate(22.407 199.828)" fill="#ff0045" opacity="0.3"/>
<path id="Path_460" data-name="Path 460" d="M6.953,12.088l-.718-.654C3.684,9.122,2,7.6,2,5.724A2.7,2.7,0,0,1,4.724,3,2.966,2.966,0,0,1,6.953,4.035,2.966,2.966,0,0,1,9.182,3a2.7,2.7,0,0,1,2.724,2.724c0,1.872-1.684,3.4-4.235,5.716Z" transform="translate(45.571 186.345)" fill="#ff0045" opacity="0.16"/>
<g id="Mask_Group_38" data-name="Mask Group 38" transform="translate(24.407 213.918)" clip-path="url(#clip-path)">
<path id="Path_270" data-name="Path 270" d="M12.649,22.542l-1.544-1.406C5.621,16.163,2,12.883,2,8.857A5.8,5.8,0,0,1,7.857,3a6.377,6.377,0,0,1,4.792,2.226A6.377,6.377,0,0,1,17.442,3,5.8,5.8,0,0,1,23.3,8.857c0,4.025-3.621,7.306-9.105,12.289Z" transform="translate(5.992 5.54)" fill="#ff0045"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" width="21.5" height="20.112" viewBox="0 0 21.5 20.112">
<g id="favorite_black_24dp" transform="translate(-1.25 -2.25)">
<path id="Path_270" data-name="Path 270" d="M12,21.35l-1.45-1.32C5.4,15.36,2,12.28,2,8.5A5.447,5.447,0,0,1,7.5,3,5.988,5.988,0,0,1,12,5.09,5.988,5.988,0,0,1,16.5,3,5.447,5.447,0,0,1,22,8.5c0,3.78-3.4,6.86-8.55,11.54Z" fill="none" stroke="#03b9e9" stroke-width="1.5"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 KiB

View File

@ -268,7 +268,7 @@ ApplicationWindow {
}
function presentUpdateInfoDialog(infoText) {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
return viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.updateDialogTitle,
"infoText": infoText,
"buttonTitles": [JamiStrings.optionOk],
@ -277,6 +277,36 @@ ApplicationWindow {
});
}
function presentUpdateConfirmInstallDialog(switchToBeta=false) {
return viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.updateDialogTitle,
"infoText": switchToBeta ? JamiStrings.confirmBeta : JamiStrings.updateFound,
"buttonTitles": [JamiStrings.optionUpgrade, JamiStrings.optionLater],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonCallBacks": [function () {
AppVersionManager.applyUpdates(switchToBeta);
}]
});
}
function translateErrorToString(error) {
switch (error) {
case NetworkManager.DISCONNECTED:
return JamiStrings.networkDisconnected;
case NetworkManager.CONTENT_NOT_FOUND:
return JamiStrings.contentNotFoundError;
case NetworkManager.ACCESS_DENIED:
return JamiStrings.accessError;
case NetworkManager.SSL_ERROR:
return JamiStrings.updateSSLError;
case NetworkManager.CANCELED:
return JamiStrings.updateDownloadCanceled;
case NetworkManager.NETWORK_ERROR:
default:
return JamiStrings.updateNetworkError;
}
}
Connections {
target: AppVersionManager
@ -288,41 +318,22 @@ ApplicationWindow {
function onUpdateCheckReplyReceived(ok, found) {
if (!ok) {
// Show an error dialog describing that we could not successfully check for an update.
presentUpdateInfoDialog(JamiStrings.updateCheckError);
return;
}
if (!found) {
// Show a dialog describing that no update was found.
presentUpdateInfoDialog(JamiStrings.updateNotFound);
} else {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.updateDialogTitle,
"infoText": JamiStrings.updateFound,
"buttonTitles": [JamiStrings.optionUpgrade, JamiStrings.optionLater],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonCallBacks": [function () {
AppVersionManager.applyUpdates();
}]
});
// Show a dialog describing that an update were found, and offering to install it.
presentUpdateConfirmInstallDialog()
}
}
function onUpdateErrorOccurred(error) {
presentUpdateInfoDialog((function () {
switch (error) {
case NetworkManager.ACCESS_DENIED:
return JamiStrings.genericError;
case NetworkManager.DISCONNECTED:
return JamiStrings.networkDisconnected;
case NetworkManager.NETWORK_ERROR:
return JamiStrings.updateNetworkError;
case NetworkManager.SSL_ERROR:
return JamiStrings.updateSSLError;
case NetworkManager.CANCELED:
return JamiStrings.updateDownloadCanceled;
default:
return {};
}
})());
function onNetworkErrorOccurred(error) {
var errorStr = translateErrorToString(error);
presentUpdateInfoDialog(errorStr);
}
}

View File

@ -74,7 +74,7 @@ QtObject {
// Create, present, and return a dialog object.
function presentDialog(parent, path, props = {}) {
// Open the dialog once the object is created
return viewManager.createView(path, parent, function (obj) {
return viewManager.createUniqueView(path, parent, function (obj) {
const doneCb = function () {
viewManager.destroyView(path);
};

View File

@ -36,36 +36,70 @@ QtObject {
}
}
// Create a view from a path only if it doesn't already exist. This is used
// by the view coordinator to create views that are not self-destructing
// (main views) and only exist once per instance of the app.
function createView(path, parent = null, cb = null, props = {}) {
if (views.hasOwnProperty(path)) {
// an instance of <path> already exists
const component = Qt.createComponent(Qt.resolvedUrl(path));
return createViewFromComponent(component, path, parent, cb, props);
}
// Create a new view. Useful when we want to create multiple views that are
// self-destructing (dialogs).
function createUniqueView(path, parent = null, cb = null, props = {}) {
const component = Qt.createComponent(Qt.resolvedUrl(path));
return createViewFromComponent(component, getViewName(path), parent, cb,
props);
}
// Create a new view from a component. If a view with the same path already
// exists, it is returned instead.
function createViewFromComponent(component, viewName, parent = null,
cb = null, props = {}) {
if (views.hasOwnProperty(viewName)) {
// an instance of the view already exists
if (cb !== null) {
cb(views[path])
cb(views[viewName])
}
return views[path]
return views[viewName]
}
const component = Qt.createComponent(Qt.resolvedUrl(path))
if (component.status === Component.Ready) {
const obj = component.createObject(parent, props)
if (obj === null) {
print("error creating object")
console.error("error creating object")
return null
}
views[path] = obj
views[viewName] = obj
// Set the view name to the object name if it has one.
const viewName = obj.objectName.toString() !== '' ? obj.objectName : path.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")
viewPaths[viewName] = path
const friendlyName = obj.objectName.toString() !== '' ?
obj.objectName :
viewName.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")
viewPaths[friendlyName] = viewName
if (cb !== null) {
cb(obj)
}
return views[path]
return views[viewName]
}
print("error creating component", path)
console.error("error creating component", component.url)
console.error(component.errorString())
Qt.exit(1)
return null
}
// Finds a unique view name for a given path by appending a number to the
// base name. For example, if a view named "MyView" already exists, the next
// view will be named "MyView_1".
function getViewName(path) {
const baseName = path.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")
let viewName = baseName
let suffix = 1
while (views.hasOwnProperty(viewName)) {
viewName = `${baseName}_${suffix}`
suffix++
}
return viewName
}
function destroyView(path) {
// The view may already have been destroyed.
if (!views.hasOwnProperty(path)) {

View File

@ -46,7 +46,7 @@ extern const QString defaultDownloadPath;
X(AppTheme, "System") \
X(BaseZoom, 1.0) \
X(ParticipantsSide, false) \
X(HideSelf, false) \
X(HideSelf, true) \
X(HideSpectators, false) \
X(AutoUpdate, true) \
X(PluginAutoUpdate, false) \
@ -57,13 +57,18 @@ extern const QString defaultDownloadPath;
X(WindowState, QWindow::AutomaticVisibility) \
X(EnableExperimentalSwarm, false) \
X(LANG, "SYSTEM") \
X(PluginStoreEndpoint, "https://plugins.jami.net") \
X(PositionShareDuration, 15) \
X(PositionShareLimit, true) \
X(FlipSelf, true) \
X(ShowMardownOption, false) \
X(ChatViewEnterIsNewLine, false) \
X(ShowSendOption, false)
X(ShowSendOption, false) \
X(DonationVisibleDate, "2023-11-01 05:00") \
X(IsDonationVisible, true) \
X(DonationEndDate, "2024-01-01 00:00") \
X(EnablePtt, false) \
X(pttKey, 36)
/*
* A class to expose settings keys in both c++ and QML.
* Note: this is using a non-constructable class instead of a

View File

@ -44,7 +44,6 @@ struct AppVersionManager::Impl : public QObject
, parent_(parent)
, lrcInstance_(instance)
, baseUrlString_(url.isEmpty() ? downloadUrl : url)
, tempPath_(QDir::tempPath())
, updateTimer_(new QTimer(this))
{
connect(updateTimer_, &QTimer::timeout, this, [this] {
@ -62,11 +61,11 @@ struct AppVersionManager::Impl : public QObject
connect(&parent_,
&NetworkManager::errorOccurred,
&parent_,
&AppVersionManager::updateErrorOccurred);
&AppVersionManager::networkErrorOccurred);
cleanUpdateFiles();
QUrl versionUrl {isBeta ? QUrl::fromUserInput(baseUrlString_ + betaVersionSubUrl)
: QUrl::fromUserInput(baseUrlString_ + versionSubUrl)};
const QUrl versionUrl {isBeta ? QUrl::fromUserInput(baseUrlString_ + betaVersionSubUrl)
: QUrl::fromUserInput(baseUrlString_ + versionSubUrl)};
parent_.sendGetRequest(versionUrl, [this, quiet](const QByteArray& latestVersionString) {
if (latestVersionString.isEmpty()) {
qWarning() << "Error checking version";
@ -76,14 +75,15 @@ struct AppVersionManager::Impl : public QObject
}
auto currentVersion = QString(VERSION_STRING).toULongLong();
auto latestVersion = latestVersionString.toULongLong();
qDebug() << "latest: " << latestVersion << " current: " << currentVersion;
if (latestVersion > currentVersion) {
qDebug() << "New version found";
const QString channelStr = isBeta ? "beta" : "stable";
const auto newVersionFound = latestVersion > currentVersion;
qInfo().noquote() << "--------- Version info ------------"
<< QString("\n - Current: %1 (%2)").arg(currentVersion).arg(channelStr);
if (newVersionFound) {
qDebug() << " - Latest: " << latestVersion;
Q_EMIT parent_.updateCheckReplyReceived(true, true);
} else {
qDebug() << "No new version found";
if (!quiet)
Q_EMIT parent_.updateCheckReplyReceived(true, false);
} else if (!quiet) {
Q_EMIT parent_.updateCheckReplyReceived(true, false);
}
});
};
@ -94,20 +94,21 @@ struct AppVersionManager::Impl : public QObject
connect(&parent_,
&NetworkManager::errorOccurred,
&parent_,
&AppVersionManager::updateErrorOccurred);
&AppVersionManager::networkErrorOccurred);
const QUrl downloadUrl {(beta || isBeta)
? QUrl::fromUserInput(baseUrlString_ + betaMsiSubUrl)
: QUrl::fromUserInput(baseUrlString_ + msiSubUrl)};
int uuid = parent_.downloadFile(
const auto lastDownloadReplyId = parent_.replyId_;
parent_.replyId_ = parent_.downloadFile(
downloadUrl,
*(parent_.replyId_),
[this, downloadUrl](bool success, const QString& errorMessage) {
lastDownloadReplyId,
[downloadUrl](bool success, const QString& errorMessage) {
Q_UNUSED(success)
Q_UNUSED(errorMessage)
const QProcess process;
auto basePath = tempPath_ + QDir::separator();
QProcess process;
auto basePath = QDir::tempPath() + QDir::separator();
auto msiPath = QDir::toNativeSeparators(basePath + downloadUrl.fileName());
auto logPath = QDir::toNativeSeparators(basePath + "jami_x64_install.log");
process.startDetached("msiexec",
@ -116,13 +117,12 @@ struct AppVersionManager::Impl : public QObject
<< "WIXNONUILAUNCH=1"
<< "/L*V" << logPath);
},
tempPath_);
parent_.replyId_.reset(&uuid);
QDir::tempPath());
};
void cancelUpdate()
{
parent_.cancelDownload(*(parent_.replyId_));
parent_.cancelDownload(parent_.replyId_);
};
void setAutoUpdateCheck(bool state)
@ -138,7 +138,7 @@ struct AppVersionManager::Impl : public QObject
void cleanUpdateFiles()
{
// Delete all logs and msi in the temporary directory before launching.
QString dir = QDir::tempPath();
const QString dir = QDir::tempPath();
QDir log_dir(dir, {"jami*.log"});
for (const QString& filename : log_dir.entryList()) {
log_dir.remove(filename);
@ -157,7 +157,6 @@ struct AppVersionManager::Impl : public QObject
LRCInstance* lrcInstance_ {nullptr};
QString baseUrlString_;
QString tempPath_;
QTimer* updateTimer_;
};
@ -166,13 +165,13 @@ AppVersionManager::AppVersionManager(const QString& url,
LRCInstance* instance,
QObject* parent)
: NetworkManager(cm, parent)
, replyId_(new int(0))
, replyId_(0)
, pimpl_(std::make_unique<Impl>(url, instance, *this))
{}
AppVersionManager::~AppVersionManager()
{
cancelDownload(*replyId_);
cancelDownload(replyId_);
}
void

View File

@ -47,10 +47,10 @@ Q_SIGNALS:
void appCloseRequested();
void updateCheckReplyReceived(bool ok, bool found = false);
void updateDownloadProgressChanged(qint64 bytesRead, qint64 totalBytes);
void updateErrorOccurred(const NetworkManager::GetError& error);
void networkErrorOccurred(const NetworkManager::GetError& error);
private:
QScopedPointer<int> replyId_;
int replyId_;
struct Impl;
friend struct Impl;
std::unique_ptr<Impl> pimpl_;

View File

@ -7,6 +7,7 @@
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Author: Capucine Berthet <capucine.berthet@savoirfairelinux.com>
*
* 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
@ -47,7 +48,7 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &CallAdapter::updateAdvancedInformation);
overlayModel_.reset(new CallOverlayModel(lrcInstance_, this));
overlayModel_.reset(new CallOverlayModel(lrcInstance_, listener_, this));
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, overlayModel_.get(), "CallOverlayModel");
accountId_ = lrcInstance_->get_currentAccountId();
@ -97,6 +98,65 @@ CallAdapter::CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject*
&LRCInstance::selectedConvUidChanged,
this,
&CallAdapter::saveConferenceSubcalls);
#ifdef HAVE_GLOBAL_PTT
connectPtt();
#endif
}
CallAdapter::~CallAdapter()
{
#ifdef HAVE_GLOBAL_PTT
disconnectPtt();
#endif
}
void
CallAdapter::connectPtt()
{
#ifdef HAVE_GLOBAL_PTT
if (listener_->getPttState()) {
QObject::connect(
listener_,
&PTTListener::pttKeyPressed,
this,
[this]() {
const auto callId
= lrcInstance_->getCallIdForConversationUid(lrcInstance_->get_selectedConvUid(),
accountId_);
try {
isMicrophoneMuted_ = isMuted(callId);
if (isMicrophoneMuted_)
muteAudioToggle();
} catch (const std::exception& e) {
qWarning() << e.what();
}
},
Qt::QueuedConnection);
QObject::connect(
listener_,
&PTTListener::pttKeyReleased,
this,
[this]() {
if (isMicrophoneMuted_) {
muteAudioToggle();
}
},
Qt::QueuedConnection);
}
#endif
}
void
CallAdapter::disconnectPtt()
{
#ifdef HAVE_GLOBAL_PTT
if (listener_->getPttState()) {
QObject::disconnect(listener_, &PTTListener::pttKeyPressed, this, nullptr);
QObject::disconnect(listener_, &PTTListener::pttKeyReleased, this, nullptr);
}
#endif
}
void
@ -172,6 +232,12 @@ CallAdapter::onCallStarted(const QString& callId)
// update call Information list by adding the new information related to the callId
callInformationListModel_->addElement(
qMakePair(callId, callModel->advancedInformationForCallId(callId)));
if (listener_->getPttState()){
#ifdef HAVE_GLOBAL_PTT
listener_->startListening();
toMute += callId;
#endif
}
}
void
@ -181,6 +247,10 @@ CallAdapter::onCallEnded(const QString& callId)
return;
// update call Information list by removing information related to the callId
callInformationListModel_->removeElement(callId);
#ifdef HAVE_GLOBAL_PTT
if (listener_->getPttState() && !hasCall_)
listener_->stopListening();
#endif
}
void
@ -271,6 +341,15 @@ CallAdapter::onCallStatusChanged(const QString& callId, int code)
}
}
void
CallAdapter::onCallInfosChanged(const QString& accountId, const QString& callId)
{
Q_UNUSED(accountId)
auto mute = toMute.remove(callId);
if (mute && listener_->getPttState())
muteAudioToggle();
}
void
CallAdapter::onCallAddedToConference(const QString& callId, const QString& confId)
{
@ -494,6 +573,12 @@ CallAdapter::connectCallModel(const QString& accountId)
QOverload<const QString&, int>::of(&CallAdapter::onCallStatusChanged),
Qt::UniqueConnection);
connect(accInfo.callModel.get(),
&CallModel::callInfosChanged,
this,
&CallAdapter::onCallInfosChanged,
Qt::UniqueConnection);
connect(accInfo.callModel.get(),
&CallModel::callAddedToConference,
this,
@ -816,6 +901,23 @@ CallAdapter::holdThisCallToggle()
}
}
bool
CallAdapter::isMuted(const QString& callId)
{
if (!(callId.isEmpty() || !lrcInstance_->getCurrentCallModel()->hasCall(callId))) {
auto* callModel = lrcInstance_->getCurrentCallModel();
if (callModel->hasCall(callId)) {
const auto callInfo = lrcInstance_->getCurrentCallModel()->getCall(callId);
auto mute = false;
for (const auto& m : callInfo.mediaList)
if (m[libjami::Media::MediaAttributeKey::LABEL] == "audio_0")
mute = m[libjami::Media::MediaAttributeKey::MUTED] == TRUE_STR;
return mute;
}
}
throw std::runtime_error("CallAdapter::isMuted: callId is empty or call does not exist");
}
void
CallAdapter::muteAudioToggle()
{
@ -825,13 +927,10 @@ CallAdapter::muteAudioToggle()
return;
}
auto* callModel = lrcInstance_->getCurrentCallModel();
if (callModel->hasCall(callId)) {
const auto callInfo = lrcInstance_->getCurrentCallModel()->getCall(callId);
auto mute = false;
for (const auto& m : callInfo.mediaList)
if (m[libjami::Media::MediaAttributeKey::LABEL] == "audio_0")
mute = m[libjami::Media::MediaAttributeKey::MUTED] == FALSE_STR;
callModel->muteMedia(callId, "audio_0", mute);
try {
callModel->muteMedia(callId, "audio_0", !isMuted(callId));
} catch (const std::exception& e) {
qWarning() << e.what();
}
}

View File

@ -25,6 +25,10 @@
#include "screensaver.h"
#include "calloverlaymodel.h"
#ifdef HAVE_GLOBAL_PTT
#include "pttlistener.h"
#endif
#include <QObject>
#include <QString>
#include <QVariant>
@ -46,7 +50,7 @@ public:
Q_ENUM(MuteStates)
explicit CallAdapter(SystemTray* systemTray, LRCInstance* instance, QObject* parent = nullptr);
~CallAdapter() = default;
~CallAdapter();
public:
Q_INVOKABLE void startTimerInformation();
@ -76,6 +80,9 @@ public:
Q_INVOKABLE void holdThisCallToggle();
Q_INVOKABLE void recordThisCallToggle();
Q_INVOKABLE void muteAudioToggle();
Q_INVOKABLE bool isMuted(const QString& callId);
Q_INVOKABLE void connectPtt();
Q_INVOKABLE void disconnectPtt();
Q_INVOKABLE void muteCameraToggle();
Q_INVOKABLE bool isRecordingThisCall();
Q_INVOKABLE void muteParticipant(const QString& accountUri,
@ -109,6 +116,7 @@ public Q_SLOTS:
void onCallAddedToConference(const QString& callId, const QString& confId);
void onCallStarted(const QString& callId);
void onCallEnded(const QString& callId);
void onCallInfosChanged(const QString& accountId, const QString& callId);
private:
void showNotification(const QString& accountId, const QString& convUid);
@ -121,6 +129,9 @@ private:
SystemTray* systemTray_;
QScopedPointer<CallOverlayModel> overlayModel_;
VectorString currentConfSubcalls_;
std::unique_ptr<CallInformationListModel> callInformationListModel_;
PTTListener* listener_ = new PTTListener(systemTray_->getSettingsManager());
bool isMicrophoneMuted_ = true;
QSet<QString> toMute;
};

View File

@ -22,6 +22,7 @@
#include <QEvent>
#include <QMouseEvent>
#include <QQuickWindow>
#include <QKeyEvent>
IndexRangeFilterProxyModel::IndexRangeFilterProxyModel(QAbstractListModel* parent)
: QSortFilterProxyModel(parent)
@ -74,10 +75,10 @@ PendingConferenceesListModel::data(const QModelIndex& index, int role) const
using namespace PendingConferences;
// WARNING: not swarm ready
lrc::api::call::Status callStatus;
QString pendingConferenceeCallId;
QString pendingConferenceeContactUri;
ContactModel* contactModel {nullptr};
lrc::api::call::Status callStatus;
try {
auto callModel = lrcInstance_->getCurrentCallModel();
auto currentPendingConferenceeInfo = callModel->getPendingConferencees().at(index.row());
@ -268,7 +269,7 @@ CallControlListModel::clearData()
data_.clear();
}
CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
CallOverlayModel::CallOverlayModel(LRCInstance* instance, PTTListener* listener, QObject* parent)
: QObject(parent)
, lrcInstance_(instance)
, primaryModel_(new CallControlListModel(this))
@ -283,6 +284,10 @@ CallOverlayModel::CallOverlayModel(LRCInstance* instance, QObject* parent)
this,
&CallOverlayModel::setControlRanges);
overflowVisibleModel_->setFilterRole(CallControl::Role::UrgentCount);
#ifndef HAVE_GLOBAL_PTT
listener_ = listener;
#endif
}
void
@ -386,6 +391,19 @@ CallOverlayModel::eventFilter(QObject* object, QEvent* event)
}
}
}
#ifndef HAVE_GLOBAL_PTT
else if (event->type() == QEvent::KeyPress && listener_->getPttState()) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == listener_->getCurrentKey() && !keyEvent->isAutoRepeat()) {
Q_EMIT pttKeyPressed();
}
} else if (event->type() == QEvent::KeyRelease && listener_->getPttState()) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == listener_->getCurrentKey() && !keyEvent->isAutoRepeat()) {
Q_EMIT pttKeyReleased();
}
}
#endif
return QObject::eventFilter(object, event);
}

View File

@ -21,6 +21,9 @@
#include "lrcinstance.h"
#include "qtutils.h"
#include "mainapplication.h"
#include "pttlistener.h"
#include <QAbstractListModel>
#include <QObject>
@ -36,7 +39,7 @@
namespace CallControl {
Q_NAMESPACE
enum Role { ItemAction = Qt::UserRole + 1, UrgentCount, Enabled};
enum Role { ItemAction = Qt::UserRole + 1, UrgentCount, Enabled };
Q_ENUM_NS(Role)
struct Item
@ -121,7 +124,7 @@ class CallOverlayModel : public QObject
QML_PROPERTY(int, overflowIndex)
public:
CallOverlayModel(LRCInstance* instance, QObject* parent = nullptr);
CallOverlayModel(LRCInstance* instance, PTTListener* listener, QObject* parent = nullptr);
Q_INVOKABLE void addPrimaryControl(const QVariant& action, bool enabled);
Q_INVOKABLE void addSecondaryControl(const QVariant& action, bool enabled);
@ -142,6 +145,8 @@ public:
Q_SIGNALS:
void mouseMoved(QQuickItem* item);
void pttKeyPressed();
void pttKeyReleased();
private Q_SLOTS:
void setControlRanges();
@ -157,4 +162,8 @@ private:
PendingConferenceesListModel* pendingConferenceesModel_;
QList<QQuickItem*> watchedItems_;
#ifndef HAVE_GLOBAL_PTT
PTTListener* listener_ {nullptr};
#endif
};

View File

@ -0,0 +1,123 @@
/*
* Copyright (C) 2023 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 net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
BaseModalDialog {
id: pttPage
property string bestName: ""
property string accountId: ""
property int pressedKey: Qt.Key_unknown
signal accepted
signal choiceMade(int chosenKey)
title: JamiStrings.changeShortcut
popupContent: ColumnLayout {
id: deleteAccountContentColumnLayout
anchors.centerIn: parent
spacing: JamiTheme.preferredMarginSize
Component.onCompleted: keyItem.forceActiveFocus()
Label {
id: instructionLabel
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: JamiTheme.preferredDialogWidth - 4*JamiTheme.preferredMarginSize
color: JamiTheme.textColor
text: JamiStrings.assignmentIndication
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
font.pointSize: JamiTheme.textFontSize
font.kerning: true
wrapMode: Text.Wrap
}
Label {
id: keyLabel
Layout.alignment: Qt.AlignCenter
color: JamiTheme.blackColor
wrapMode: Text.WordWrap
text: ""
font.pointSize: JamiTheme.settingsFontSize
font.kerning: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
background: Rectangle {
id: backgroundRect
anchors.centerIn: parent
width: keyLabel.width + 2 * JamiTheme.preferredMarginSize
height: keyLabel.height + JamiTheme.preferredMarginSize
color: JamiTheme.lightGrey_
border.color: JamiTheme.darkGreyColor
radius: 4
}
}
MaterialButton {
id: btnAssign
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: JamiTheme.preferredMarginSize
preferredWidth: JamiTheme.preferredFieldWidth / 2 - 8
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
color: JamiTheme.buttonTintedBlack
hoveredColor: JamiTheme.buttonTintedBlackHovered
pressedColor: JamiTheme.buttonTintedBlackPressed
secondary: true
text: JamiStrings.assign
autoAccelerator: true
onClicked: {
if (!(pressedKey === Qt.Key_unknown)){
pttListener.setPttKey(pressedKey);
choiceMade(pressedKey);
}
close();
}
}
Item {
id: keyItem
Keys.onPressed: (event)=>{
keyLabel.text = pttListener.keyToString(event.key);
pressedKey = event.key;
}
}
}
}

View File

@ -24,6 +24,7 @@ import net.jami.Constants 1.1
Item {
id: jamiId
property bool slimDisplay: true
property color backgroundColor: JamiTheme.welcomeBlockColor
property color contentColor: JamiTheme.tintedBlue
@ -104,6 +105,8 @@ Item {
visible: usernameTextEdit.readOnly
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: JamiTheme.pushButtonMargins
Layout.maximumWidth: leftRect.width - 50
elide: Text.ElideRight
color: jamiId.contentColor
font.pixelSize : text.length > 16 ? JamiTheme.jamiIdSmallFontSize : JamiTheme.bigFontSize
property string registeredName: CurrentAccount.registeredName

View File

@ -68,6 +68,7 @@ SplitView {
}
handle: Rectangle {
visible: !isSinglePane
implicitWidth: JamiTheme.splitViewHandlePreferredWidth
implicitHeight: root.height
color: JamiTheme.primaryBackgroundColor

View File

@ -35,8 +35,10 @@ ContextMenuAutoLoader {
GeneralMenuItem {
id: copy
canTrigger: lineEditObj.selectedText.length
canTrigger: true
isActif: lineEditObj.selectedText.length
itemName: JamiStrings.copy
hasIcon: false
onClicked: {
lineEditObj.copy();
}
@ -44,9 +46,10 @@ ContextMenuAutoLoader {
GeneralMenuItem {
id: cut
canTrigger: lineEditObj.selectedText.length && !selectOnly
canTrigger: true
isActif: lineEditObj.selectedText.length && !selectOnly
itemName: JamiStrings.cut
hasIcon: false
onClicked: {
lineEditObj.cut();
}
@ -56,6 +59,7 @@ ContextMenuAutoLoader {
canTrigger: !selectOnly
itemName: JamiStrings.paste
hasIcon: false
onClicked: {
if (customizePaste)
root.contextMenuRequirePaste();
@ -76,10 +80,6 @@ ContextMenuAutoLoader {
lineEditObj.select(selectionStart, selectionEnd);
}
contextMenuItemPreferredHeight: JamiTheme.lineEditContextMenuItemsHeight
contextMenuItemPreferredWidth: JamiTheme.lineEditContextMenuItemsWidth
contextMenuSeparatorPreferredHeight: JamiTheme.lineEditContextMenuSeparatorsHeight
Connections {
target: root.item
enabled: root.status === Loader.Ready

View File

@ -1,309 +0,0 @@
/*
* Copyright (C) 2022-2023 Savoir-faire Linux Inc.
* Author: Nicolas Vengeon <nicolas.vengeon@savoirfairelinux.com>
*
* 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 Qt5Compat.GraphicalEffects
import QtQuick.Layouts
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
Popup {
id: root
width: emojiColumn.width + JamiTheme.emojiMargins
height: emojiColumn.height + JamiTheme.emojiMargins
padding: 0
background.visible: false
required property var emojiReactions
property var emojiReplied: emojiReactions.ownEmojis
required property string msgId
required property string msgBody
required property bool isOutgoing
required property int type
required property string transferName
required property Item msgBubble
required property ListView listView
property string transferId: msgId
property string location: msgBody
property bool closeWithoutAnimation: false
property var emojiPicker
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
function xPositionProvider(width) {
// Use the width at function scope to retrigger property evaluation.
const listViewWidth = listView.width
if (isOutgoing) {
const leftMargin = msgBubble.mapToItem(listView, 0, 0).x
return width > leftMargin ? -leftMargin : -width
} else {
const rightMargin = listViewWidth - (msgBubble.x + msgBubble.width)
return width > rightMargin ? msgBubble.width - width : msgBubble.width
}
}
function yPositionProvider(height) {
const topOffset = msgBubble.mapToItem(listView, 0, 0).y
if (topOffset < 0) return -topOffset
const bottomOffset = topOffset + height - listView.height
if (bottomOffset > 0) return -bottomOffset
return 0
}
x: xPositionProvider(width)
y: yPositionProvider(height)
signal addMoreEmoji
onAddMoreEmoji: {
JamiQmlUtils.updateMessageBarButtonsPoints()
openEmojiPicker()
}
function openEmojiPicker() {
var component = WITH_WEBENGINE ?
Qt.createComponent("qrc:/webengine/emojipicker/EmojiPicker.qml") :
Qt.createComponent("qrc:/nowebengine/EmojiPicker.qml")
emojiPicker = component.createObject(root.parent, { listView: listView })
emojiPicker.emojiIsPicked.connect(function(content) {
if (emojiReplied.includes(content)) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, content, msgId)
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, content, msgId)
}
})
if (emojiPicker !== null) {
root.opacity = 0
emojiPicker.closed.connect(() => close())
emojiPicker.x = xPositionProvider(JamiTheme.emojiPickerWidth)
emojiPicker.y = yPositionProvider(JamiTheme.emojiPickerHeight)
emojiPicker.open()
} else {
console.log("Error creating emojiPicker from message options popup");
}
}
// Close the picker when listView vertical properties change.
property real listViewHeight: listView.height
onListViewHeightChanged: close()
property bool isScrolling: listView.verticalScrollBar.active
onIsScrollingChanged: close()
onOpened: root.closeWithoutAnimation = false
onClosed: if (emojiPicker) emojiPicker.closeEmojiPicker()
function getModel() {
const defaultModel = ["👍", "👎", "😂"]
const reactedEmojis = Array.isArray(emojiReplied) ? emojiReplied.slice(0, defaultModel.length) : []
const uniqueEmojis = Array.from(new Set(reactedEmojis))
const missingEmojis = defaultModel.filter(emoji => !uniqueEmojis.includes(emoji))
return uniqueEmojis.concat(missingEmojis)
}
Rectangle {
id: bubble
color: JamiTheme.chatviewBgColor
anchors.fill: parent
radius: JamiTheme.modalPopupRadius
ColumnLayout {
id: emojiColumn
anchors.centerIn: parent
RowLayout {
id: emojiRow
Layout.alignment: Qt.AlignCenter
Repeater {
model: root.getModel()
delegate: Button {
id: emojiButton
height: 50
width: 50
text: modelData
font.pointSize: JamiTheme.emojiBubbleSize
Text {
visible: emojiButton.hovered
anchors.centerIn: parent
text: modelData
font.pointSize: JamiTheme.emojiBubbleSizeBig
z: 1
}
background: Rectangle {
anchors.fill: parent
opacity: emojiReplied ? (emojiReplied.includes(modelData) ? 1 : 0) : 0
color: JamiTheme.emojiReactPushButtonColor
radius: 10
}
onClicked: {
if (emojiReplied.includes(modelData))
MessagesAdapter.removeEmojiReaction(CurrentConversation.id,text,msgId)
else
MessagesAdapter.addEmojiReaction(CurrentConversation.id,text,msgId)
close()
}
}
}
PushButton {
toolTipText: JamiStrings.moreEmojis
source: JamiResources.add_reaction_svg
normalColor: JamiTheme.emojiReactBubbleBgColor
imageColor: JamiTheme.emojiReactPushButtonColor
visible: WITH_WEBENGINE
onClicked: {
root.closeWithoutAnimation = true
root.addMoreEmoji()
//close()
}
}
}
Rectangle {
Layout.margins: 5
color: JamiTheme.timestampColor
Layout.fillWidth: true
Layout.preferredHeight: 1
radius: width * 0.5
opacity: 0.6
}
MessageOptionButton {
textButton: JamiStrings.copy
iconSource: JamiResources.copy_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
UtilsAdapter.setClipboardText(msgBody)
close()
}
}
MessageOptionButton {
visible: type === Interaction.Type.DATA_TRANSFER
textButton: JamiStrings.saveFile
iconSource: JamiResources.save_file_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
MessagesAdapter.copyToDownloads(root.transferId, root.transferName)
close()
}
}
MessageOptionButton {
visible: type === Interaction.Type.DATA_TRANSFER
textButton: JamiStrings.openLocation
iconSource: JamiResources.round_folder_24dp_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
MessagesAdapter.openDirectory(root.location)
close()
}
}
MessageOptionButton {
visible: type === Interaction.Type.DATA_TRANSFER && Status === Interaction.Status.TRANSFER_FINISHED
textButton: JamiStrings.removeLocally
iconSource: JamiResources.trash_black_24dp_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
MessagesAdapter.removeFile(msgId, root.location)
close()
}
}
MessageOptionButton {
id: buttonEdit
visible: root.isOutgoing && type === Interaction.Type.TEXT
textButton: JamiStrings.editMessage
iconSource: JamiResources.edit_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
MessagesAdapter.replyToId = ""
MessagesAdapter.editId = root.msgId
close()
}
}
MessageOptionButton {
visible: root.isOutgoing && type === Interaction.Type.TEXT
textButton: JamiStrings.deleteMessage
iconSource: JamiResources.delete_svg
Layout.fillWidth: true
Layout.margins: 5
onClicked: {
MessagesAdapter.editMessage(CurrentConversation.id, "", root.msgId)
close()
}
}
}
}
Overlay.modal: Rectangle {
color: JamiTheme.transparentColor
// Color animation for overlay when pop up is shown.
ColorAnimation on color {
to: JamiTheme.popupOverlayColor
duration: 500
}
}
DropShadow {
z: -1
width: bubble.width
height: bubble.height
horizontalOffset: 3.0
verticalOffset: 3.0
radius: bubble.radius * 4
color: JamiTheme.shadowColor
source: bubble
transparentBorder: true
samples: radius + 1
}
enter: Transition {
NumberAnimation {
properties: "opacity"; from: 0.0; to: 1.0
duration: JamiTheme.shortFadeDuration
}
}
exit: Transition {
NumberAnimation {
properties: "opacity"; from: 1.0; to: 0.0
duration: root.closeWithoutAnimation ? 0 : JamiTheme.shortFadeDuration
}
}
}

View File

@ -53,6 +53,7 @@ AbstractButton {
property alias toolTipText: toolTip.text
property alias hasShortcut: toolTip.hasShortcut
property alias shortcutKey: toolTip.shortcutKey
property int buttonTextFontSize: 12
// State colors
property string pressedColor: JamiTheme.pressedButtonColor
@ -143,7 +144,7 @@ AbstractButton {
color: JamiTheme.primaryForegroundColor
font.kerning: true
font.pixelSize: 12
font.pixelSize: buttonTextFontSize
elide: Qt.ElideRight
}

View File

@ -37,6 +37,7 @@ ContextMenuAutoLoader {
canTrigger: root.transferId !== ""
itemName: JamiStrings.saveFile
iconSource: JamiResources.save_file_svg
onClicked: MessagesAdapter.copyToDownloads(root.transferId, root.transferName)
},
GeneralMenuItem {
@ -44,6 +45,7 @@ ContextMenuAutoLoader {
canTrigger: root.transferId !== ""
itemName: JamiStrings.openLocation
iconSource: JamiResources.round_folder_24dp_svg
onClicked: {
MessagesAdapter.openDirectory(root.location);
}
@ -52,6 +54,7 @@ ContextMenuAutoLoader {
id: reply
itemName: JamiStrings.reply
iconSource: JamiResources.reply_svg
onClicked: {
MessagesAdapter.editId = "";
MessagesAdapter.replyToId = root.msgId;
@ -62,6 +65,7 @@ ContextMenuAutoLoader {
canTrigger: transferId === "" && isOutgoing
itemName: JamiStrings.edit
iconSource: JamiResources.edit_svg
onClicked: {
MessagesAdapter.replyToId = "";
MessagesAdapter.editId = root.msgId;
@ -73,6 +77,7 @@ ContextMenuAutoLoader {
canTrigger: transferId === "" && isOutgoing
itemName: JamiStrings.optionDelete
iconSource: JamiResources.delete_svg
onClicked: {
MessagesAdapter.editMessage(CurrentConversation.id, "", root.msgId);
}

View File

@ -277,8 +277,8 @@ Control {
anchors.rightMargin: isOutgoing ? 10 : 0
anchors.leftMargin: !isOutgoing ? 10 : 0
imageColor: JamiTheme.emojiReactPushButtonColor
normalColor: JamiTheme.transparentColor
imageColor: hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
normalColor: JamiTheme.primaryBackgroundColor
toolTipText: JamiStrings.moreOptions
anchors.verticalCenter: parent.verticalCenter
anchors.right: isOutgoing ? optionButtonItem.right : undefined
@ -287,9 +287,10 @@ Control {
source: JamiResources.more_vert_24dp_svg
width: optionButtonItem.width / 2
height: optionButtonItem.height
circled: false
onClicked: {
var component = Qt.createComponent("qrc:/commoncomponents/MessageOptionsPopup.qml");
var component = Qt.createComponent("qrc:/commoncomponents/ShowMoreMenu.qml");
var obj = component.createObject(bubble, {
"emojiReactions": emojiReactions,
"isOutgoing": isOutgoing,
@ -307,13 +308,15 @@ Control {
PushButton {
id: reply
imageColor: JamiTheme.emojiReactPushButtonColor
normalColor: JamiTheme.transparentColor
circled: false
imageColor: hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
normalColor: JamiTheme.primaryBackgroundColor
toolTipText: JamiStrings.reply
source: JamiResources.reply_svg
width: optionButtonItem.width / 2
height: optionButtonItem.height
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 5
anchors.right: isOutgoing ? more.left : undefined
anchors.left: !isOutgoing ? more.right : undefined
visible: CurrentAccount.type !== Profile.Type.SIP && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || bgHandler.hovered)

View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2020-2023 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.Constants 1.1
import "contextmenu"
BaseContextMenu {
id: root
property var modelList
signal audioRecordMessageButtonClicked
signal videoRecordMessageButtonClicked
signal showMapClicked
property list<GeneralMenuItem> menuItems: [
GeneralMenuItem {
id: audioMessage
canTrigger: true
iconSource: JamiResources.message_audio_black_24dp_svg
itemName: JamiStrings.leaveAudioMessage
onClicked: {
root.audioRecordMessageButtonClicked();
}
},
GeneralMenuItem {
id: videoMessage
canTrigger: true
iconSource: JamiResources.message_video_black_24dp_svg
itemName: JamiStrings.leaveVideoMessage
onClicked: {
root.videoRecordMessageButtonClicked();
}
},
GeneralMenuItem {
id: shareLocation
canTrigger: true
iconSource: JamiResources.localisation_sharing_send_pin_svg
itemName: JamiStrings.shareLocation
onClicked: {
root.showMapClicked();
}
}
]
Component.onCompleted: {
root.loadMenuItems(menuItems);
}
}

View File

@ -1,134 +0,0 @@
/*
* Copyright (C) 2023 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.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"
Popup {
id: root
padding: 0
property list<Action> menuMoreButton
height: childrenRect.height
width: childrenRect.width
focus: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
Rectangle {
id: rect
color: JamiTheme.primaryBackgroundColor
border.color: JamiTheme.chatViewFooterRectangleBorderColor
border.width: 2
radius: 5
height: listViewMoreButton.childrenRect.height + 16
width: listViewMoreButton.childrenRect.width + 16
ListView {
id: listViewMoreButton
anchors.centerIn: parent
orientation: ListView.Vertical
spacing: 0
width: contentItem.childrenRect.width
height: contentHeight
model: menuMoreButton
Rectangle {
z: -1
anchors.fill: parent
color: "transparent"
}
onCountChanged: {
for (var i = 0; i < count; i++) {
var item = listViewMoreButton.itemAtIndex(i);
item.width = listViewMoreButton.width;
}
}
delegate: ItemDelegate {
id: control
text: modelData.toolTip
contentItem: RowLayout {
Rectangle {
id: image
width: 26
height: 26
radius: 5
color: JamiTheme.transparentColor
ResponsiveImage {
anchors.fill: parent
source: modelData.iconSrc
color: control.hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
}
}
Text {
Layout.alignment: Qt.AlignLeft
text: control.text
color: control.hovered ? JamiTheme.chatViewFooterImgHoverColor : "#7f7f7f"
}
}
background: Rectangle {
color: control.hovered ? JamiTheme.showMoreButtonOpenColor : JamiTheme.transparentColor
}
action: modelData
onClicked: {
root.close();
}
}
}
}
background: Rectangle {
anchors.fill: parent
color: JamiTheme.transparentColor
radius: 5
z: -1
}
enter: Transition {
NumberAnimation {
properties: "opacity"
from: 0.0
to: 1.0
duration: JamiTheme.shortFadeDuration
}
}
exit: Transition {
NumberAnimation {
properties: "opacity"
from: 1.0
to: 0.0
duration: JamiTheme.shortFadeDuration
}
}
}

View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2020-2023 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.Constants 1.1
import Qt5Compat.GraphicalEffects
import QtQuick.Controls
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import "contextmenu"
BaseContextMenu {
id: root
required property var emojiReactions
property var emojiReplied: emojiReactions.ownEmojis
required property string msgId
required property string msgBody
required property bool isOutgoing
required property int type
required property string transferName
required property Item msgBubble
required property ListView listView
property string location: msgBody
property bool closeWithoutAnimation: false
property var emojiPicker
function xPositionProvider(width) {
// Use the width at function scope to retrigger property evaluation.
const listViewWidth = listView.width;
if (isOutgoing) {
const leftMargin = msgBubble.mapToItem(listView, 0, 0).x;
return width > leftMargin ? -leftMargin - 35 : -width - 35;
} else {
const rightMargin = listViewWidth - (msgBubble.x + msgBubble.width);
return width > rightMargin ? msgBubble.width - width + 35 : msgBubble.width + 35;
}
}
function yPositionProvider(height) {
const topOffset = msgBubble.mapToItem(listView, 0, 0).y;
if (topOffset < 0)
return -topOffset;
const bottomOffset = topOffset + height - listView.height;
if (bottomOffset > 0)
return -bottomOffset;
return 0;
}
x: xPositionProvider(width)
y: yPositionProvider(height)
signal addMoreEmoji
onAddMoreEmoji: {
JamiQmlUtils.updateMessageBarButtonsPoints();
openEmojiPicker();
}
function openEmojiPicker() {
var component = WITH_WEBENGINE ? Qt.createComponent("qrc:/webengine/emojipicker/EmojiPicker.qml") : Qt.createComponent("qrc:/nowebengine/EmojiPicker.qml");
emojiPicker = component.createObject(root.parent, {
"listView": listView
});
emojiPicker.emojiIsPicked.connect(function (content) {
if (emojiReplied.includes(content)) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, content, msgId);
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, content, msgId);
}
});
if (emojiPicker !== null) {
root.opacity = 0;
emojiPicker.closed.connect(() => close());
emojiPicker.x = xPositionProvider(JamiTheme.emojiPickerWidth);
emojiPicker.y = yPositionProvider(JamiTheme.emojiPickerHeight);
emojiPicker.open();
} else {
console.log("Error creating emojiPicker from message options popup");
}
}
// Close the picker when listView vertical properties change.
property real listViewHeight: listView.height
onListViewHeightChanged: close()
property bool isScrolling: listView.verticalScrollBar.active
onIsScrollingChanged: close()
onOpened: root.closeWithoutAnimation = false
onClosed: if (emojiPicker)
emojiPicker.closeEmojiPicker()
function getModel() {
const defaultModel = ["👍", "👎", "😂"];
const reactedEmojis = Array.isArray(emojiReplied) ? emojiReplied.slice(0, defaultModel.length) : [];
const uniqueEmojis = Array.from(new Set(reactedEmojis));
const missingEmojis = defaultModel.filter(emoji => !uniqueEmojis.includes(emoji));
return uniqueEmojis.concat(missingEmojis);
}
property list<MenuItem> menuItems: [
GeneralMenuItemList {
id: audioMessage
modelList: getModel()
canTrigger: true
iconSource: JamiResources.add_reaction_svg
itemName: JamiStrings.copy
addMenuSeparatorAfter: true
messageId: msgId
},
GeneralMenuItem {
id: saveFile
canTrigger: type === Interaction.Type.DATA_TRANSFER
iconSource: JamiResources.save_file_svg
itemName: JamiStrings.saveFile
onClicked: {
MessagesAdapter.copyToDownloads(root.msgId, root.transferName);
}
},
GeneralMenuItem {
id: openLocation
canTrigger: type === Interaction.Type.DATA_TRANSFER
iconSource: JamiResources.round_folder_24dp_svg
itemName: JamiStrings.openLocation
onClicked: {
MessagesAdapter.openDirectory(root.location);
}
},
GeneralMenuItem {
id: removeLocally
canTrigger: type === Interaction.Type.DATA_TRANSFER && Status === Interaction.Status.TRANSFER_FINISHED
iconSource: JamiResources.trash_black_24dp_svg
itemName: JamiStrings.removeLocally
onClicked: {
MessagesAdapter.removeFile(msgId, root.location);
;
}
},
GeneralMenuItem {
id: editMessage
canTrigger: root.isOutgoing && type === Interaction.Type.TEXT
iconSource: JamiResources.edit_svg
itemName: JamiStrings.editMessage
onClicked: {
MessagesAdapter.replyToId = "";
MessagesAdapter.editId = root.msgId;
}
},
GeneralMenuItem {
id: deleteMessage
canTrigger: root.isOutgoing && type === Interaction.Type.TEXT
iconSource: JamiResources.delete_svg
itemName: JamiStrings.deleteMessage
onClicked: {
MessagesAdapter.editMessage(CurrentConversation.id, "", root.msgId);
}
},
GeneralMenuItem {
id: copyMessage
canTrigger: true
iconSource: JamiResources.copy_svg
itemName: JamiStrings.copy
onClicked: {
UtilsAdapter.setClipboardText(msgBody);
}
}
]
Component.onCompleted: {
root.loadMenuItems(menuItems);
}
}

View File

@ -43,11 +43,9 @@ Menu {
function loadMenuItems(menuItems) {
root.addItem(menuTopBorder);
// use the maximum text width as the preferred width for menu
for (var j = 0; j < menuItems.length; ++j) {
var currentItemWidth = menuItems[j].itemPreferredWidth;
if (currentItemWidth !== JamiTheme.menuItemsPreferredWidth && currentItemWidth > menuPreferredWidth)
if (currentItemWidth !== JamiTheme.menuItemsPreferredWidth && currentItemWidth > menuPreferredWidth && menuItems[j].canTrigger)
menuPreferredWidth = currentItemWidth;
}
for (var i = 0; i < menuItems.length; ++i) {
@ -55,17 +53,28 @@ Menu {
menuItems[i].parentMenu = root;
root.addItem(menuItems[i]);
if (menuPreferredWidth)
menuItems[i].itemPreferredWidth = menuPreferredWidth;
menuItems[i].itemRealWidth = menuPreferredWidth;
if (menuItemsPreferredHeight)
menuItems[i].itemPreferredHeight = menuItemsPreferredHeight;
}
if (menuItems[i].addMenuSeparatorAfter) {
// If the QML file to be loaded is a local file,
// you could omit the finishCreation() function
var menuSeparatorComponent = Qt.createComponent("GeneralMenuSeparator.qml", Component.PreferSynchronous, root);
var menuSeparatorComponentObj = menuSeparatorComponent.createObject();
generalMenuSeparatorList.push(menuSeparatorComponentObj);
root.addItem(menuSeparatorComponentObj);
if (i !== menuItems.length - 1) {
var menuSeparatorComponent = Qt.createComponent("GeneralMenuSeparator.qml", Component.PreferSynchronous, root);
var menuSeparatorComponentObj = menuSeparatorComponent.createObject();
generalMenuSeparatorList.push(menuSeparatorComponentObj);
root.addItem(menuSeparatorComponentObj);
}
if (menuItems[i].addMenuSeparatorAfter) {
var menuSeparatorComponent = Qt.createComponent("GeneralMenuSeparator.qml", Component.PreferSynchronous, root);
var menuSeparatorComponentObj = menuSeparatorComponent.createObject(root, {
"separatorColor": "#DEDEDE",
"separatorPreferredHeight": 0
});
generalMenuSeparatorList.push(menuSeparatorComponentObj);
root.addItem(menuSeparatorComponentObj);
var menuSeparatorComponent = Qt.createComponent("GeneralMenuSeparator.qml", Component.PreferSynchronous, root);
var menuSeparatorComponentObj = menuSeparatorComponent.createObject();
generalMenuSeparatorList.push(menuSeparatorComponentObj);
root.addItem(menuSeparatorComponentObj);
}
}
}
root.addItem(menuBottomBorder);
@ -81,24 +90,23 @@ Menu {
Overlay.modal: Rectangle {
color: "transparent"
}
font.pointSize: JamiTheme.menuFontSize
background: Rectangle {
id: container
implicitWidth: menuPreferredWidth ? menuPreferredWidth : JamiTheme.menuItemsPreferredWidth
border.width: JamiTheme.menuItemsCommonBorderWidth
border.color: JamiTheme.tabbarBorderColor
color: JamiTheme.backgroundColor
color: JamiTheme.primaryBackgroundColor
radius: 5
layer.enabled: true
layer.effect: DropShadow {
z: -1
horizontalOffset: 3.0
horizontalOffset: 0.0
verticalOffset: 3.0
radius: 16.0
color: JamiTheme.shadowColor
radius: 6
color: "#29000000"
transparentBorder: true
samples: radius + 1
}

View File

@ -30,6 +30,8 @@ Loader {
active: false
visible: false
function openMenu() {
root.active = true;
root.sourceComponent = menuComponent;

View File

@ -1,6 +1,5 @@
/*
* Copyright (C) 2020-2023 Savoir-faire Linux Inc.
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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
@ -32,34 +31,41 @@ MenuItem {
property alias iconSource: contextMenuItemImage.source
property string iconColor: ""
property bool canTrigger: true
property bool hasIcon: true
property bool addMenuSeparatorAfter: false
property bool autoTextSizeAdjustment: true
property bool dangerous: false
property BaseContextMenu parentMenu
property bool isActif: true
property int itemPreferredWidth: JamiTheme.menuItemsPreferredWidth
property int itemPreferredWidth: hasIcon ? 50 + contextMenuItemText.contentWidth + contextMenuItemImage.width : 35 + contextMenuItemText.contentWidth
property int itemRealWidth: itemPreferredWidth
property int itemPreferredHeight: JamiTheme.menuItemsPreferredHeight
property int leftBorderWidth: JamiTheme.menuItemsCommonBorderWidth
property int rightBorderWidth: JamiTheme.menuItemsCommonBorderWidth
property int itemImageLeftMargin: 24
property int itemTextMargin: 20
property int itemImageLeftMargin: 10
property int itemTextMargin: 10
signal clicked
property bool itemHovered: menuItemContentRect.hovered
contentItem: AbstractButton {
width: itemRealWidth
contentItem: PushButton {
id: menuItemContentRect
background: Rectangle {
id: background
enabled: isActif
hoverEnabled: isActif
anchors.fill: parent
anchors.leftMargin: 1
anchors.rightMargin: 1
hoveredColor: JamiTheme.hoverColor
normalColor: JamiTheme.primaryBackgroundColor
circled: false
radius: 5
color: menuItemContentRect.hovered ? JamiTheme.hoverColor : JamiTheme.backgroundColor
}
//duration: 1000
anchors.leftMargin: 6
anchors.rightMargin: 6
anchors.fill: parent
@ -76,41 +82,25 @@ MenuItem {
visible: status === Image.Ready
color: iconColor !== "" ? iconColor : JamiTheme.textColor
opacity: 0.7
color: menuItemContentRect.hovered ? JamiTheme.textColor : JamiTheme.chatViewFooterImgColor
}
Text {
id: contextMenuItemText
Item {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: contextMenuItemImage.status === Image.Ready ? itemTextMargin : itemTextMargin / 2
Layout.rightMargin: contextMenuItemImage.status === Image.Ready ? itemTextMargin : itemTextMargin / 2
Layout.leftMargin: contextMenuItemImage.status === Image.Ready ? itemTextMargin : itemTextMargin
Layout.rightMargin: contextMenuItemImage.status === Image.Ready ? itemImageLeftMargin : itemTextMargin
Layout.preferredHeight: itemPreferredHeight
Layout.fillWidth: true
text: itemName
color: dangerous ? JamiTheme.redColor : JamiTheme.textColor
font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
TextMetrics {
id: contextMenuItemTextMetrics
font: contextMenuItemText.font
text: contextMenuItemText.text
onBoundingRectChanged: {
var sizeToCompare = itemPreferredWidth - (contextMenuItemImage.source.toString().length > 0 ? itemTextMargin + itemImageLeftMargin + contextMenuItemImage.width : itemTextMargin / 2);
if (autoTextSizeAdjustment && boundingRect.width > sizeToCompare) {
if (boundingRect.width > JamiTheme.contextMenuItemTextMaxWidth) {
itemPreferredWidth += JamiTheme.contextMenuItemTextMaxWidth - JamiTheme.contextMenuItemTextPreferredWidth + itemTextMargin;
contextMenuItemText.elide = Text.ElideRight;
} else
itemPreferredWidth += boundingRect.width + itemTextMargin - sizeToCompare;
}
}
Text {
id: contextMenuItemText
height: parent.height
text: itemName
color: dangerous ? JamiTheme.redColor : isActif ? JamiTheme.textColor : JamiTheme.chatViewFooterImgColor
font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
}
@ -130,7 +120,9 @@ MenuItem {
anchors.leftMargin: leftBorderWidth
anchors.rightMargin: rightBorderWidth
implicitWidth: itemPreferredWidth
color: JamiTheme.primaryBackgroundColor
implicitWidth: itemRealWidth
implicitHeight: itemPreferredHeight
border.width: 0
@ -141,7 +133,7 @@ MenuItem {
rBorderwidth: rightBorderWidth
tBorderwidth: 0
bBorderwidth: 0
borderColor: JamiTheme.tabbarBorderColor
borderColor: JamiTheme.primaryBackgroundColor
}
}
}

View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2020-2023 Savoir-faire Linux Inc.
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* 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 net.jami.Constants 1.1
import "../"
import net.jami.Adapters 1.1
// General menu item.
// Can control top, bottom, left, right border width.
// Use onClicked slot to simulate item click event.
// Can have image icon at the left of the text.
MenuItem {
id: menuItem
property var modelList: undefined
property string itemName: ""
property var iconSource: undefined
property string iconColor: ""
property bool canTrigger: true
property bool hasIcon: true
property bool addMenuSeparatorAfter: false
property bool autoTextSizeAdjustment: true
property bool dangerous: false
property BaseContextMenu parentMenu
property string messageId
signal addMoreEmoji
property int itemPreferredWidth: 207
property int itemRealWidth: itemPreferredWidth
property int itemPreferredHeight: JamiTheme.menuItemsPreferredHeight
property int leftBorderWidth: JamiTheme.menuItemsCommonBorderWidth
property int rightBorderWidth: JamiTheme.menuItemsCommonBorderWidth
property int itemImageLeftMargin: 18
signal clicked
width: itemRealWidth
contentItem: Item {
id: menuItemContentRect
anchors.fill: parent
RowLayout {
spacing: 0
anchors.fill: menuItemContentRect
Rectangle {
id: contextMenuItemImage
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: itemImageLeftMargin
height: 36
width: 36
color: emojiReplied.includes(modelList[0]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor
radius: 5
Text {
anchors.centerIn: parent
text: modelList[0]
font.pointSize: JamiTheme.emojiBubbleSize
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
contextMenuItemImage.color = JamiTheme.hoveredButtonColor;
}
onExited: {
contextMenuItemImage.color = emojiReplied.includes(modelList[0]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor;
}
onClicked: {
if (emojiReplied.includes(modelList[0])) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, modelList[0], msgId);
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, modelList[0], msgId);
}
close();
}
}
}
Rectangle {
id: contextMenuItemImage2
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: itemImageLeftMargin / 2
height: 36
width: 36
color: emojiReplied.includes(modelList[1]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor
radius: 5
Text {
anchors.centerIn: parent
text: modelList[1]
font.pointSize: JamiTheme.emojiBubbleSize
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
contextMenuItemImage2.color = JamiTheme.hoveredButtonColor;
}
onExited: {
contextMenuItemImage2.color = emojiReplied.includes(modelList[1]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor;
}
onClicked: {
if (emojiReplied.includes(modelList[1])) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, modelList[1], msgId);
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, modelList[1], msgId);
}
close();
}
}
}
Rectangle {
id: contextMenuItemImage3
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: itemImageLeftMargin / 2
height: 36
width: 36
color: emojiReplied.includes(modelList[2]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor
radius: 5
Text {
anchors.centerIn: parent
text: modelList[2]
font.pointSize: JamiTheme.emojiBubbleSize
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
contextMenuItemImage3.color = JamiTheme.hoveredButtonColor;
}
onExited: {
contextMenuItemImage3.color = emojiReplied.includes(modelList[2]) ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor;
}
onClicked: {
if (emojiReplied.includes(modelList[2])) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, modelList[2], msgId);
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, modelList[2], msgId);
}
close();
}
}
}
PushButton {
id: contextMenuItemImage4
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: itemImageLeftMargin / 2
Layout.rightMargin: itemImageLeftMargin
height: 36
width: 36
imageColor: hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
normalColor: JamiTheme.primaryBackgroundColor
radius: 5
source: iconSource
onClicked: {
root.addMoreEmoji();
}
}
}
}
highlighted: true
background: Rectangle {
id: contextMenuBackgroundRect
anchors.fill: parent
anchors.leftMargin: leftBorderWidth
anchors.rightMargin: rightBorderWidth
color: JamiTheme.primaryBackgroundColor
implicitWidth: itemRealWidth
implicitHeight: itemPreferredHeight
border.width: 0
CustomBorder {
commonBorder: false
lBorderwidth: leftBorderWidth
rBorderwidth: rightBorderWidth
tBorderwidth: 0
bBorderwidth: 0
borderColor: JamiTheme.primaryBackgroundColor
}
}
}

View File

@ -23,19 +23,24 @@ MenuSeparator {
id: menuSeparator
property int separatorPreferredWidth: JamiTheme.menuItemsPreferredWidth
property int separatorPreferredHeight: 1
property string separatorColor: JamiTheme.tabbarBorderColor
property int separatorPreferredHeight: 5
property string separatorColor: JamiTheme.primaryBackgroundColor
padding: 0
topPadding: 1
bottomPadding: 1
contentItem: Rectangle {
implicitWidth: separatorPreferredWidth
implicitHeight: separatorPreferredHeight
color: separatorColor
radius: 5
}
background: Rectangle {
color: JamiTheme.backgroundColor
width: parent.width - 10
anchors.horizontalCenter: parent.horizontalCenter
color: separatorColor
radius: 5
}
}

View File

@ -0,0 +1,228 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "connectioninfolistmodel.h"
ConnectionInfoListModel::ConnectionInfoListModel(LRCInstance* instance, QObject* parent)
: AbstractListModelBase(parent)
{
lrcInstance_ = instance;
connect(lrcInstance_,
&LRCInstance::currentAccountIdChanged,
this,
&ConnectionInfoListModel::resetData);
}
int
ConnectionInfoListModel::rowCount(const QModelIndex& parent) const
{
return peerIds_.size();
}
QVariant
ConnectionInfoListModel::data(const QModelIndex& index, int role) const
{
const auto accountId = lrcInstance_->get_currentAccountId();
if (accountId.isEmpty()) {
qWarning() << "ConnectionInfoListModel::data: accountId or peerID is empty";
return {};
}
const auto peerId = peerIds_[index.row()];
const auto peerData = peerData_[peerId];
switch (role) {
case ConnectionInfoList::ChannelsMap: {
QVariantMap channelsMapMap;
int i = 0;
for (const auto& device : peerData.keys()) {
QString channelsId = peerData[device]["id"].toString();
QVariantMap channelsMap;
const auto channelInfoList = lrcInstance_->getChannelList(accountId, channelsId);
for (const auto& channelInfo : channelInfoList) {
channelsMap.insert(channelInfo["id"], channelInfo["name"]);
}
channelsMapMap.insert(QString::number(i++), channelsMap);
}
return QVariant(channelsMapMap);
}
case ConnectionInfoList::ConnectionDatas: {
QString peerString;
peerString += "Peer:" + peerId;
for (const auto& device : peerData.keys()) {
peerString += "{";
peerString += "Device:" + device + ",";
peerString += "Status:" + peerData[device]["status"].toString() + ",";
peerString += "Channels:" + peerData[device]["channels"].toString() + ",";
peerString += "Remote Address" + peerData[device]["remoteAddress"].toString();
peerString += "}";
}
return peerString;
}
case ConnectionInfoList::PeerId:
return peerId;
case ConnectionInfoList::RemoteAddress: {
QVariantMap remoteAddressMap;
int i = 0;
for (const auto& device : peerData.keys()) {
remoteAddressMap.insert(QString::number(i++), peerData[device]["remoteAddress"]);
}
return QVariant(remoteAddressMap);
}
case ConnectionInfoList::DeviceId: {
QVariantMap deviceMap;
int i = 0;
for (const auto& device : peerData.keys()) {
deviceMap.insert(QString::number(i++), device);
}
return QVariant(deviceMap);
}
case ConnectionInfoList::Status: {
QVariantMap statusMap;
int i = 0;
for (const auto& device : peerData.keys()) {
statusMap.insert(QString::number(i++), peerData[device]["status"]);
}
return QVariantMap(statusMap);
}
case ConnectionInfoList::Channels: {
QVariantMap channelsMap;
int i = 0;
for (const auto& device : peerData.keys()) {
channelsMap.insert(QString::number(i++), peerData[device]["channels"]);
}
return QVariant(channelsMap);
}
case ConnectionInfoList::Count:
return peerData.size();
}
return {};
}
QHash<int, QByteArray>
ConnectionInfoListModel::roleNames() const
{
using namespace ConnectionInfoList;
QHash<int, QByteArray> roles;
#define X(role) roles[role] = #role;
CONNECTONINFO_ROLES
#undef X
return roles;
}
void
ConnectionInfoListModel::update()
{
const auto accountId = lrcInstance_->get_currentAccountId();
if (accountId.isEmpty()) {
return;
}
aggregateData();
}
template<typename T>
std::tuple<QVector<T>, QVector<T>>
getSetDiff(QVector<T> u, QVector<T> v)
{
using namespace std;
QVector<T> a, r;
set_difference(v.begin(), v.end(), u.begin(), u.end(), inserter(a, a.begin()));
set_difference(u.begin(), u.end(), v.begin(), v.end(), inserter(r, r.begin()));
return {a, r};
}
void
ConnectionInfoListModel::aggregateData()
{
const auto accountId = lrcInstance_->get_currentAccountId();
if (accountId.isEmpty()) {
return;
}
connectionInfoList_ = lrcInstance_->getConnectionList(accountId);
peerData_ = {};
QSet<QString> newPeerIds;
for (const auto& connectionInfo : connectionInfoList_) {
if (!connectionInfo["peer"].isEmpty()) {
newPeerIds.insert(connectionInfo["peer"]);
}
const auto channelInfoList = lrcInstance_->getChannelList(accountId, connectionInfo["id"]);
peerData_[connectionInfo["peer"]][connectionInfo["device"]] = {};
peerData_[connectionInfo["peer"]][connectionInfo["device"]]["status"]
= connectionInfo["status"];
peerData_[connectionInfo["peer"]][connectionInfo["device"]]["channels"] = channelInfoList
.size();
peerData_[connectionInfo["peer"]][connectionInfo["device"]]["id"] = connectionInfo["id"];
peerData_[connectionInfo["peer"]][connectionInfo["device"]]["remoteAddress"]
= connectionInfo["remoteAddress"];
}
QVector<QString> oldVector;
for (const auto& peerId : peerIds_) {
oldVector << peerId;
}
QVector<QString> newVector;
for (const auto& peerId : newPeerIds) {
newVector << peerId;
}
std::sort(oldVector.begin(), oldVector.end());
std::sort(newVector.begin(), newVector.end());
QVector<QString> removed, added;
std::tie(added, removed) = getSetDiff(oldVector, newVector);
Q_FOREACH (const auto& key, added) {
auto index = std::distance(newVector.begin(),
std::find(newVector.begin(), newVector.end(), key));
beginInsertRows(QModelIndex(), index, index);
peerIds_.insert(index, key);
endInsertRows();
}
Q_FOREACH (const auto& key, removed) {
auto index = std::distance(oldVector.begin(),
std::find(oldVector.begin(), oldVector.end(), key));
beginRemoveRows(QModelIndex(), index, index);
if (peerIds_.size() > index) {
peerIds_.remove(index);
} else {
qWarning() << "ConnectionInfoListModel::aggregateData: index out of range";
qWarning() << "index: " << index;
qWarning() << "key: " << key;
}
endRemoveRows();
}
// HACK: loop through all the peerIds_ and update the data for each one.
// This is not efficient, but it works.
Q_FOREACH (const auto& peerId, peerIds_) {
auto index = std::distance(peerIds_.begin(),
std::find(peerIds_.begin(), peerIds_.end(), peerId));
Q_EMIT dataChanged(this->index(index), this->index(index));
}
}
void
ConnectionInfoListModel::resetData()
{
beginResetModel();
peerIds_.clear();
peerData_.clear();
endResetModel();
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "abstractlistmodelbase.h"
#define CONNECTONINFO_ROLES \
X(ConnectionDatas) \
X(ChannelsMap) \
X(PeerName) \
X(PeerId) \
X(DeviceId) \
X(Status) \
X(Channels) \
X(RemoteAddress) \
X(Count) // this is the number of connections (convenience)
namespace ConnectionInfoList {
Q_NAMESPACE
enum Role {
DummyRole = Qt::UserRole + 1,
#define X(role) role,
CONNECTONINFO_ROLES
#undef X
};
Q_ENUM_NS(Role)
} // namespace ConnectionInfoList
class ConnectionInfoListModel : public AbstractListModelBase
{
public:
explicit ConnectionInfoListModel(LRCInstance* instance, QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
Q_INVOKABLE void update();
private:
using Role = ConnectionInfoList::Role;
VectorMapStringString connectionInfoList_;
QVector<QString> peerIds_;
QMap<QString, QMap<QString, QMap<QString, QVariant>>> peerData_;
void aggregateData();
void resetData();
};

View File

@ -20,6 +20,7 @@
pragma Singleton
import QtQuick
import net.jami.Adapters 1.1
import net.jami.Enums 1.1
Item {
property string qmlFilePrefix: "file:/"
@ -69,4 +70,13 @@ Item {
function clamp(val, min, max) {
return Math.min(Math.max(val, min), max);
}
function isDonationBannerVisible() {
// The banner is visible if the current date is after the date set in the settings and before the end date
// And if the donation toggle is checked
var isDonationVisible = UtilsAdapter.getAppValue(Settings.Key.IsDonationVisible);
var endDonationDate = new Date(Date.parse(UtilsAdapter.getAppValue(Settings.Key.DonationEndDate)));
var donationVisibleDate = new Date(Date.parse(UtilsAdapter.getAppValue(Settings.Key.DonationVisibleDate)));
return new Date() < endDonationDate && new Date() > donationVisibleDate && isDonationVisible && false;
}
}

View File

@ -83,6 +83,15 @@ Item {
property string selectNewRingtone: qsTr("Select a new ringtone")
property string certificateFile: qsTr("Certificate File (*.crt)")
property string audioFile: qsTr("Audio File (*.wav *.ogg *.opus *.mp3 *.aiff *.wma)")
property string pushToTalk: qsTr("Push-to-talk")
property string enablePTT: qsTr("Enable push-to-talk")
property string keyboardShortcut: qsTr("Keyboard shortcut")
property string changeKeyboardShortcut: qsTr("Change keyboard shortcut")
// ChangePttKeyPopup
property string changeShortcut: qsTr("Change shortcut")
property string assignmentIndication: qsTr("Press the key to be assigned to push-to-talk shortcut")
property string assign: qsTr("Assign")
// AdvancedChatSettings
property string enableReadReceipts: qsTr("Enable read receipts")
@ -436,7 +445,7 @@ Item {
// LinkedDevices
property string tipLinkNewDevice: qsTr("Link a new device to this account")
property string linkNewDevice: qsTr("Exporting account…")
property string linkDevice: qsTr("Exporting account…")
property string removeDevice: qsTr("Remove Device")
property string sureToRemoveDevice: qsTr("Are you sure you wish to remove this device?")
property string yourPinIs: qsTr("Your PIN is:")
@ -513,6 +522,8 @@ Item {
property string updateDownloading: "Downloading"
property string confirmBeta: qsTr("This will uninstall your current Release version and you can always download the latest Release version on our website")
property string networkDisconnected: qsTr("Network disconnected")
property string accessError: qsTr("Content access error")
property string contentNotFoundError: qsTr("Content not found")
property string genericError: qsTr("Something went wrong")
//Troubleshoot Settings
@ -575,13 +586,20 @@ Item {
// LinkDevicesDialog
property string pinTimerInfos: qsTr("The PIN and the account password should be entered in your device within 10 minutes.")
property string close: qsTr("Close")
property string enterAccountPassword: qsTr("Enter account's password")
property string enterAccountPassword: qsTr("Enter account password")
property string enterPasswordPinCode: qsTr("This account is password encrypted, enter the password to generate a PIN code.")
property string addDevice: qsTr("Add Device")
property string pinExpired: qsTr("PIN expired")
property string onAnotherDevice: qsTr("On another device")
property string onAnotherDeviceInstruction: qsTr("Install and launch Jami, select \"Import from another device\" and scan the QR code.")
property string linkNewDevice: qsTr("Link new device")
property string linkingInstructions: qsTr("In Jami, scan QR code or manually enter the PIN.")
property string pinValidity: qsTr("The PIN code is valid for: ")
// PasswordDialog
property string enterPassword: qsTr("Enter the password")
property string enterPassword: qsTr("Enter password")
property string enterCurrentPassword: qsTr("Enter current password")
property string confirmRemoval: qsTr("Enter this account's password to confirm the removal of this device")
property string confirmRemoval: qsTr("Enter account password to confirm the removal of this device")
property string enterNewPassword: qsTr("Enter new password")
property string confirmNewPassword: qsTr("Confirm new password")
property string change: qsTr("Change")
@ -724,6 +742,7 @@ Item {
property string showLess: qsTr("Show less")
property string showPreview: qsTr("Show preview")
property string continueEditing: qsTr("Continue editing")
property string bold: qsTr("Bold")
property string italic: qsTr("Italic")
property string strikethrough: qsTr("Strikethrough")
@ -827,4 +846,30 @@ Item {
// Appearence
property string theme: qsTr("Theme")
property string zoomLevel: qsTr("Text zoom level")
//Donation campaign
property string donationTipBoxText: qsTr("Free and private sharing. <a href=\"https://jami.net/donate/\">Donate</a> to expand it.")
property string donation: qsTr("Donate")
property string donationText: qsTr("If you enjoy using Jami and believe in our mission, would you make a donation?")
property string notNow: qsTr("Not now")
property string enableDonation: qsTr("Enable donation campaign")
//Chat setting page
property string enter: qsTr("Enter")
property string shiftEnter: qsTr("Shift+Enter")
property string textFormattingDescription: qsTr("Enter or Shift+Enter to insert a new line")
property string textFormatting: qsTr("Text formatting")
//Connection monitoring
property string connected: qsTr("Connected")
property string connectingTLS: qsTr("Connecting TLS")
property string connectingICE: qsTr("Connecting ICE")
property string connecting: qsTr("Connecting")
property string waiting: qsTr("Waiting")
property string contact: qsTr("Contact")
property string connection: qsTr("Connection")
property string channels: qsTr("Channels")
property string copyAllData: qsTr("Copy all data")
property string remote: qsTr("Remote: ")
property string view: qsTr("View")
}

View File

@ -76,7 +76,7 @@ Item {
property color greyBorderColor: "#333"
property color selectionBlue: darkTheme ? "#0061a5" : "#109ede"
property color hoverColor: darkTheme ? "#4d4d4d" : "#c7c7c7"
property color hoverColor: darkTheme ? "#4d4d4d" : "#DEDEDE"
property color pressColor: darkTheme ? "#777" : "#c0c0c0"
property color selectedColor: darkTheme ? "#0e81c5" : "#e0e0e0"
property color smartListHoveredColor: darkTheme ? "#4d4d4d" : "#dedede"
@ -367,9 +367,9 @@ Item {
property int avatarReadReceiptSize: 18
property int menuItemsPreferredWidth: 220
property int menuItemsPreferredHeight: 48
property int menuItemsPreferredHeight: 36
property int menuItemsCommonBorderWidth: 1
property int menuBorderPreferredHeight: 8
property int menuBorderPreferredHeight: 5
property real maximumWidthSettingsView: 516
property real settingsHeaderpreferredHeight: 64
@ -492,6 +492,7 @@ Item {
// MessageBar
property int messageBarMarginSize: 10
property int messageBarMinimumWidth: 438
// InvitationView
property real invitationViewAvatarSize: 112
@ -532,6 +533,7 @@ Item {
// WizardView Welcome Page
property real welcomeLabelPointSize: 30
property var welcomeLogo: darkTheme ? JamiResources.logo_jami_standard_coul_white_svg : JamiResources.logo_jami_standard_coul_svg
property real welcomeLogoWidth: 100
property real welcomeLogoHeight: 100
property real wizardButtonWidth: 400
@ -541,9 +543,9 @@ Item {
property real welcomeRectTopMargin: 90
property real welcomePageSpacing: 13
property real welcomeGridWidth: 3 * JamiTheme.tipBoxWidth + 2 * JamiTheme.welcomePageSpacing
property real welcomeHalfGridWidth: (welcomeGridWidth - JamiTheme.welcomePageSpacing) / 2
property real welcomeThirdGridWidth: (welcomeGridWidth - JamiTheme.welcomePageSpacing) / 3
property real welcomeShortGridWidth: 2 * JamiTheme.tipBoxWidth + JamiTheme.welcomePageSpacing
readonly property string welcomeBg: darkTheme ? JamiResources.bg_darkmode_id_jami_png : JamiResources.bg_lightmode_id_jami_png
readonly property string welcomeBg: darkTheme ? JamiResources.background_don_dark_jpg : JamiResources.background_don_white_jpg
property color welcomeBlockColor: darkTheme ? "#4D000000" : "#4DFFFFFF"
// WizardView Advanced Account Settings
@ -643,6 +645,9 @@ Item {
property int settingsMenuHeaderButtonHeight: 50
property int settingsListViewsSpacing: 10
// Link Device
property color pinBackgroundColor: "#D6E4EF"
// MaterialRadioButton
property int radioImageSize: 30
property color radioBackgroundColor: darkTheme ? "#303030" : "#F0EFEF"
@ -654,7 +659,22 @@ Item {
property color darkThemeCheckedColor: "#03B9E9"
property color darkThemeBorderColor: "#03B9E9"
// Donation campaign
property color donationButtonTextColor: "#005699"
property color donationBackgroundColor: "#D5E4EF"
property string donationUrl: "https://jami.net/donate/"
//Connection monitoring
property color connectionMonitoringTableColor1: "#f0efef"
property color connectionMonitoringTableColor2: "#f6f5f5"
property color connectionMonitoringHeaderColor: "#d1d1d1"
function setTheme(dark) {
darkTheme = dark;
}
//Chat setting page
property color chatSettingButtonBackgroundColor: darkTheme ? "#303030" : "#F0EFEF"
property color chatSettingButtonBorderColor: darkTheme ? "#03B9E9" : "#005699"
property color chatSettingButtonTextColor: textColor
}

View File

@ -21,10 +21,16 @@
#include "contactadapter.h"
#include "lrcinstance.h"
#include "qmlregister.h"
ContactAdapter::ContactAdapter(LRCInstance* instance, QObject* parent)
: QmlAdapterBase(instance, parent)
, connectionInfoListModel_(new ConnectionInfoListModel(lrcInstance_, this))
{
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS,
connectionInfoListModel_.get(),
"ConnectionInfoListModel");
selectableProxyModel_.reset(new SelectableProxyModel(this));
if (lrcInstance_) {
connectSignals();
@ -246,6 +252,12 @@ ContactAdapter::removeContact(const QString& peerUri, bool banContact)
accInfo.contactModel->removeContact(peerUri, banContact);
}
void
ContactAdapter::updateConnectionInfo()
{
connectionInfoListModel_->update();
}
void
ContactAdapter::connectSignals()
{

View File

@ -21,6 +21,7 @@
#include "qmladapterbase.h"
#include "smartlistmodel.h"
#include "conversationlistmodel.h"
#include "connectioninfolistmodel.h"
#include <QObject>
#include <QSortFilterProxyModel>
@ -90,6 +91,7 @@ public:
Q_INVOKABLE void setSearchFilter(const QString& filter);
Q_INVOKABLE void contactSelected(int index);
Q_INVOKABLE void removeContact(const QString& peerUri, bool banContact);
Q_INVOKABLE void updateConnectionInfo();
void connectSignals();
@ -104,6 +106,7 @@ private:
SmartListModel::Type listModeltype_;
QScopedPointer<SmartListModel> smartListModel_;
QScopedPointer<SelectableProxyModel> selectableProxyModel_;
QScopedPointer<ConnectionInfoListModel> connectionInfoListModel_;
QStringList defaultModerators_;

View File

@ -458,3 +458,15 @@ LRCInstance::set_selectedConvUid(QString selectedConvUid)
Q_EMIT selectedConvUidChanged();
}
}
VectorMapStringString
LRCInstance::getConnectionList(const QString& accountId, const QString& uid)
{
return Lrc::getConnectionList(accountId, uid);
}
VectorMapStringString
LRCInstance::getChannelList(const QString& accountId, const QString& uid)
{
return Lrc::getChannelList(accountId, uid);
}

View File

@ -135,6 +135,10 @@ public:
return debugMode_;
}
VectorMapStringString getConnectionList(const QString& accountId, const QString& uid = {});
VectorMapStringString getChannelList(const QString& accountId, const QString& uid = {});
Q_SIGNALS:
void accountListChanged();
void selectedConvUidChanged();

View File

@ -20,6 +20,7 @@
*/
#include "mainapplication.h"
#include "pttlistener.h"
#include "qmlregister.h"
#include "appsettingsmanager.h"
@ -105,7 +106,7 @@ ScreenInfo::onPhysicalDotsPerInchChanged()
}
MainApplication::MainApplication(int& argc, char** argv)
: QApplication(argc, argv)
: QApplication(argc, argv), isCleanupped(false)
{
const char* qtVersion = qVersion();
qInfo() << "Using Qt runtime version:" << qtVersion;
@ -132,6 +133,7 @@ MainApplication::init()
connectivityMonitor_.reset(new ConnectivityMonitor(this));
settingsManager_.reset(new AppSettingsManager(this));
systemTray_.reset(new SystemTray(settingsManager_.get(), this));
listener_ = new PTTListener(settingsManager_.get(), this);
QObject::connect(settingsManager_.get(),
&AppSettingsManager::retranslate,
@ -350,6 +352,7 @@ MainApplication::initQmlLayer()
auto videoProvider = new VideoProvider(lrcInstance_->avModel(), this);
engine_->rootContext()->setContextProperty("videoProvider", videoProvider);
engine_->rootContext()->setContextProperty("pttListener", listener_);
engine_->load(QUrl(QStringLiteral("qrc:/MainApplicationWindow.qml")));
qWarning().noquote() << "Main window loaded using" << getRenderInterfaceString();
@ -401,13 +404,17 @@ MainApplication::initSystray()
void
MainApplication::cleanup()
{
QApplication::exit(0);
// In Qt 6.5, QApplication::exit(0) will signal aboutToQuit, and aboutToQuit is connected to cleanup
// TODO: delete cleanup.
if (!isCleanupped) {
isCleanupped = true;
QApplication::exit(0);
}
}
#ifdef Q_OS_MACOS
void
MainApplication::setEventFilter()
{
installEventFilter(this);
}
#endif

View File

@ -23,6 +23,7 @@
#include "imagedownloader.h"
#include "lrcinstance.h"
#include "qtutils.h"
#include "pttlistener.h"
#include <QFile>
#include <QApplication>
@ -82,17 +83,20 @@ public:
return runOptions_[opt];
};
#ifdef Q_OS_MACOS
Q_INVOKABLE void setEventFilter();
bool eventFilter(QObject* object, QEvent* event)
{
#ifdef Q_OS_MACOS
if (event->type() == QEvent::ApplicationActivate) {
restoreApp();
}
#endif // Q_OS_MACOS
return QApplication::eventFilter(object, event);
}
#endif // Q_OS_MACOS
Q_SIGNALS:
void closeRequested();
@ -120,5 +124,9 @@ private:
QScopedPointer<SystemTray> systemTray_;
QScopedPointer<ImageDownloader> imageDownloader_;
PTTListener* listener_;
ScreenInfo screenInfo_;
bool isCleanupped;
};

View File

@ -203,61 +203,70 @@ ItemDelegate {
anchors.fill: parent
color: menuItem.down ? "#c4aaaaaa" : menuItem.hovered ? "#c4777777" : "transparent"
}
contentItem: ColumnLayout {
// After update to qt 6.4.3 the layout was broken, adding a Rectangle
// as top level in the contentIntem is a workaround which removal can be
// tested with newer qt versions
contentItem: Rectangle {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.fillWidth: true
Layout.rightMargin: 15
Layout.leftMargin: 20
Layout.fillHeight: true
Layout.alignment: {
if (menuAction.popupMode !== CallActionBar.ActionPopupMode.LayoutOption || TopMargin && BottomMargin) {
return Qt.AlignLeft | Qt.AlignVCenter;
}
if (TopMargin) {
Layout.bottomMargin = 4;
return Qt.AlignBottom;
}
Layout.topMargin = 4;
return Qt.AlignTop;
}
color: "transparent"
ColumnLayout {
anchors.fill: parent
spacing: 0
spacing: 6
ResponsiveImage {
source: menuAction.popupMode === CallActionBar.ActionPopupMode.ListElement || menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? IconSource : (menuItem.ListView.isCurrentItem ? JamiResources.check_box_24dp_svg : JamiResources.check_box_outline_blank_24dp_svg)
color: "white"
width: 20
height: 20
}
Text {
id: delegateText
RowLayout {
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: menuAction.popupMode === CallActionBar.ActionPopupMode.ListElement || menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? Name : DeviceName
elide: Text.ElideRight
font.pointSize: JamiTheme.participantFontSize
color: "white"
Layout.fillHeight: true
Layout.rightMargin: 15
Layout.leftMargin: 20
Layout.alignment: {
if (menuAction.popupMode !== CallActionBar.ActionPopupMode.LayoutOption || TopMargin && BottomMargin) {
return Qt.AlignLeft | Qt.AlignVCenter;
}
if (TopMargin) {
Layout.bottomMargin = 4;
return Qt.AlignBottom;
}
Layout.topMargin = 4;
return Qt.AlignTop;
}
spacing: 6
ResponsiveImage {
source: menuAction.popupMode === CallActionBar.ActionPopupMode.ListElement || menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? IconSource : (menuItem.ListView.isCurrentItem ? JamiResources.check_box_24dp_svg : JamiResources.check_box_outline_blank_24dp_svg)
color: "white"
width: 20
height: 20
}
Text {
id: delegateText
Layout.fillWidth: true
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: menuAction.popupMode === CallActionBar.ActionPopupMode.ListElement || menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? Name : DeviceName
elide: Text.ElideRight
font.pointSize: JamiTheme.participantFontSize
color: "white"
}
ResponsiveImage {
source: JamiResources.check_black_24dp_svg
color: "white"
width: 20
height: 20
visible: menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? ActiveSetting : false
}
}
ResponsiveImage {
source: JamiResources.check_black_24dp_svg
color: "white"
width: 20
height: 20
visible: menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? ActiveSetting : false
Rectangle {
id: buttonDiv
visible: menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? SectionEnd : false
Layout.fillWidth: true
height: 1
opacity: 0.2
border.width: 0
color: JamiTheme.separationLine
Layout.alignment: Qt.AlignBottom
}
}
Rectangle {
id: buttonDiv
visible: menuAction.popupMode === CallActionBar.ActionPopupMode.LayoutOption ? SectionEnd : false
Layout.fillWidth: true
height: 1
opacity: 0.2
border.width: 0
color: JamiTheme.separationLine
Layout.alignment: Qt.AlignBottom
}
}
}

View File

@ -25,7 +25,6 @@ import "../../commoncomponents"
Item {
id: root
property alias chatViewContainer: ongoingCallPage.chatViewContainer
property alias contentView: callStackMainView
@ -49,6 +48,16 @@ Item {
}
}
Connections {
target: CallOverlayModel
function onPttKeyPressed() {
CallAdapter.muteAudioToggle();
}
function onPttKeyReleased() {
CallAdapter.muteAudioToggle();
}
}
// TODO: this should all be done by listening to
// parent visibility change or parent `Component.onDestruction`
function needToCloseInCallConversationAndPotentialWindow() {

View File

@ -106,13 +106,18 @@ Popup {
height: Top || Bottom ? 10 : 45
background: Rectangle {
radius: 5
visible: !Top && !Bottom
anchors.fill: parent
anchors.leftMargin: 5
anchors.rightMargin: 5
color: menuItem.down ? "#c4aaaaaa" : menuItem.hovered ? "#c4777777" : "transparent"
}
RowLayout {
anchors.fill: parent
anchors.leftMargin: 5
anchors.rightMargin: 5
visible: !Top && !Bottom
ResponsiveImage {
Layout.leftMargin: JamiTheme.preferredMarginSize

View File

@ -130,7 +130,7 @@ Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: footerColumnLayout.width
Layout.leftMargin: marginSize
Layout.leftMargin: 0
Layout.rightMargin: marginSize
Layout.bottomMargin: marginSize
Layout.preferredHeight: height

View File

@ -86,8 +86,7 @@ Rectangle {
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 8
preferredSize: 24
//preferredSize: 24
mirror: UtilsAdapter.isRTL
source: JamiResources.back_24dp_svg
@ -155,12 +154,12 @@ Rectangle {
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.preferredHeight: 30
Layout.preferredWidth: 40 + (isOpen? JamiTheme.searchbarSize : 0)
Layout.preferredWidth: 40 + (isOpen ? JamiTheme.searchbarSize : 0)
colorSearchBar: JamiTheme.backgroundColor
hoverButtonRadius: JamiTheme.chatViewHeaderButtonRadius
Behavior on Layout.preferredWidth {
Behavior on Layout.preferredWidth {
NumberAnimation {
duration: 150
}
@ -168,7 +167,7 @@ Rectangle {
visible: root.swarmDetailsVisibility
onSearchBarTextChanged: function(text){
onSearchBarTextChanged: function (text) {
MessagesAdapter.searchbarPrompt = text;
}

View File

@ -104,7 +104,6 @@ ContextMenuAutoLoader {
canTrigger: hasCall
itemName: JamiStrings.endCall
iconSource: JamiResources.ic_call_end_white_24dp_svg
addMenuSeparatorAfter: contactType !== Profile.Type.SIP && (contactType === Profile.Type.PENDING || !hasCall)
onClicked: CallAdapter.hangUpACall(responsibleAccountId, responsibleConvUid)
},
GeneralMenuItem {
@ -129,7 +128,6 @@ ContextMenuAutoLoader {
canTrigger: !hasCall && contactType !== Profile.Type.SIP && !root.isBanned && isCoreDialog && root.idText !== CurrentAccount.uri
itemName: JamiStrings.blockContact
iconSource: JamiResources.block_black_24dp_svg
addMenuSeparatorAfter: canTrigger
onClicked: {
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/ConfirmDialog.qml", {
"title": JamiStrings.confirmAction,
@ -147,7 +145,6 @@ ContextMenuAutoLoader {
canTrigger: root.isBanned
itemName: JamiStrings.reinstateContact
iconSource: JamiResources.round_remove_circle_24dp_svg
addMenuSeparatorAfter: canTrigger
onClicked: MessagesAdapter.unbanConversation(responsibleConvUid)
},
GeneralMenuItem {

View File

@ -0,0 +1,149 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "../../commoncomponents"
import "../../settingsview/components"
Rectangle {
id: donation
property bool donationVisible: JamiQmlUtils.isDonationBannerVisible()
width: parent.width - 30
height: donationTextRect.height + 45 > donationIcon.height + 20 ? donationTextRect.height + 45 : donationIcon.height + 20
radius: 5
color: JamiTheme.donationBackgroundColor
GridLayout {
id: donationLayout
anchors.fill: parent
columns: 3
rows: 2
rowSpacing: 0
columnSpacing: 10
Rectangle {
id: donationIcon
Layout.row: 0
Layout.column: 0
Layout.rowSpan: 2
Layout.preferredHeight: 70
Layout.preferredWidth: 45
Layout.leftMargin: 10
Layout.topMargin: 10
Layout.bottomMargin: 15
color: JamiTheme.transparentColor
Image {
id: donationImage
height: parent.height
width: 50
anchors.centerIn: parent
source: JamiResources.icon_donate_svg
}
}
Rectangle {
id: donationTextRect
Layout.topMargin: 10
Layout.row: 0
Layout.column: 1
Layout.columnSpan: 2
Layout.preferredHeight: donationText.height
Layout.preferredWidth: parent.width - 74
Layout.bottomMargin: 5
color: JamiTheme.transparentColor
Text {
id: donationText
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
width: parent.width
height: contentHeight
text: JamiStrings.donationText
wrapMode: Text.WordWrap
font.pointSize: JamiTheme.textFontSize
}
}
Rectangle {
id: notNowRect
Layout.row: 1
Layout.column: 1
Layout.preferredHeight: 30
Layout.preferredWidth: (parent.width - 55) / 2
color: JamiTheme.transparentColor
Text {
id: notNowText
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
// When the user clicks on "Not now", we set the donation date to 7 days from now (1 for the test)
UtilsAdapter.setAppValue(Settings.Key.DonationVisibleDate, new Date(new Date().getTime() + 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 16).replace("T", " "));
donation.donationVisible = Qt.binding(() => JamiQmlUtils.isDonationBannerVisible());
}
}
text: JamiStrings.notNow
color: JamiTheme.donationButtonTextColor
anchors.top: parent.top
anchors.left: parent.left
font.pointSize: JamiTheme.textFontSize
}
}
Rectangle {
id: donateRect
Layout.row: 1
Layout.column: 2
Layout.preferredHeight: 30
Layout.preferredWidth: (parent.width - 50) / 2
color: JamiTheme.transparentColor
Text {
id: donateText
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
onClicked: {
Qt.openUrlExternally(JamiTheme.donationUrl);
}
}
text: JamiStrings.donation
font.pointSize: JamiTheme.textFontSize
color: JamiTheme.donationButtonTextColor
anchors.top: parent.top
anchors.left: parent.left
}
}
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (C) 2023 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 net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import "../../commoncomponents"
Item {
id: root
focus: true
width: parent.width
height: backupLayout.height
property real iconSize: 26
property real margin: 5
property real preferredWidth: 170
property real maxHeight: 250
property color textColor: JamiTheme.textColor
property color iconColor: JamiTheme.tintedBlue
ColumnLayout {
id: backupLayout
anchors.top: parent.top
width: parent.width
RowLayout {
id: rowlayout
Layout.leftMargin: 15
Layout.alignment: Qt.AlignLeft
ResponsiveImage {
id: icon
visible: !opened
Layout.alignment: Qt.AlignLeft
Layout.topMargin: root.margin
Layout.preferredWidth: root.iconSize
Layout.preferredHeight: root.iconSize
containerHeight: Layout.preferredHeight
containerWidth: Layout.preferredWidth
color: JamiTheme.tintedBlue
source: JamiResources.favorite_black_24dp_svg
}
Text {
id: title
text: JamiStrings.donation
color: root.textColor
font.weight: Font.Medium
Layout.topMargin: root.margin
Layout.alignment: Qt.AlignLeft
Layout.leftMargin: root.margin
Layout.preferredWidth: root.preferredWidth - 2 * root.margin - root.iconSize
font.pixelSize: JamiTheme.tipBoxTitleFontSize
horizontalAlignment: Text.AlignLeft
elide: Qt.ElideRight
}
}
Text {
id: content
Layout.preferredWidth: root.preferredWidth
focus: true
Layout.leftMargin: 20
Layout.topMargin: 8
Layout.bottomMargin: 8
font.pixelSize: JamiTheme.tipBoxContentFontSize
visible: true
wrapMode: Text.WordWrap
font.weight: Font.Normal
text: JamiStrings.donationTipBoxText
color: root.textColor
horizontalAlignment: Text.AlignLeft
linkColor: JamiTheme.buttonTintedBlue
onLinkActivated: {
Qt.openUrlExternally(JamiTheme.donationUrl);
}
}
}
}

View File

@ -54,12 +54,14 @@ RowLayout {
height: showTypo || multiLine ? messageBarTextArea.height + 25 + 3 * marginSize + 1 : textAreaObj.height + marginSize + 1
Rectangle {
Layout.preferredHeight: parent.height
Layout.preferredWidth: childrenRect.width
visible: !CurrentConversation.isSip
color: JamiTheme.transparentColor
ComboBox {
id: showMoreButton
focus: true
width: JamiTheme.chatViewFooterButtonSize
height: JamiTheme.chatViewFooterButtonSize
anchors.bottom: parent.bottom
@ -95,6 +97,7 @@ RowLayout {
}
onHoveredChanged: {
console.log("Hovered changed");
if (!sharePopup.opened) {
showMoreButton.indicator.color = hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor;
showMoreButton.background.color = hovered ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor;
@ -103,18 +106,24 @@ RowLayout {
}
onPressedChanged: {
console.log("Pressed changed");
if (sharePopup.enabled)
sharePopup.close();
}
popup: SharePopup {
popup: ShareMenu {
id: sharePopup
y: -180
x: -20
menuMoreButton: listViewMoreButton.menuMoreButton
onClosed: messageBar.textAreaObj.forceActiveFocus()
onAudioRecordMessageButtonClicked: {
root.audioRecordMessageButtonClicked();
}
onVideoRecordMessageButtonClicked: {
root.videoRecordMessageButtonClicked();
}
onShowMapClicked: {
root.showMapClicked();
}
modelList: listViewMoreButton.menuMoreButton
y: -140
}
}
}
@ -132,8 +141,6 @@ RowLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.rightMargin: marginSize
Layout.leftMargin: marginSize
radius: 5
color: JamiTheme.transparentColor
@ -142,12 +149,10 @@ RowLayout {
onWidthChanged: {
height = Qt.binding(() => root.height);
if (width < 468) {
if (width < JamiTheme.messageBarMinimumWidth) {
showTypoSecond = false;
} else {
if (width >= 468) {
showTypoSecond = true;
}
showTypoSecond = true;
}
}
@ -219,32 +224,32 @@ RowLayout {
},
"Link": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(0).action.triggered();
listViewTypoFirst.itemAtIndex(4).action.triggered();
}
},
"Code": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(1).action.triggered();
listViewTypoFirst.itemAtIndex(5).action.triggered();
}
},
"Quote": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(2).action.triggered();
listViewTypoSecond.itemAtIndex(0).action.triggered();
}
},
"Unordered list": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(3).action.triggered();
listViewTypoSecond.itemAtIndex(1).action.triggered();
}
},
"Ordered list": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(4).action.triggered();
listViewTypoSecond.itemAtIndex(2).action.triggered();
}
},
"Enter is new line": function () {
if (!showPreview) {
listViewTypoSecond.itemAtIndex(5).action.triggered();
listViewTypoSecond.itemAtIndex(3).action.triggered();
}
}
}
@ -308,6 +313,8 @@ RowLayout {
context: Qt.ApplicationShortcut
onActivated: {
showTypo = !showTypo;
messageBarTextArea.isShowTypo = showTypo;
UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo);
}
}
@ -671,11 +678,11 @@ RowLayout {
normalColor: {
if (showPreview) {
return JamiTheme.transparentColor;
return JamiTheme.primaryBackgroundColor;
} else if (modelData.isStyle) {
return JamiTheme.hoveredButtonColor;
} else {
return JamiTheme.transparentColor;
return JamiTheme.primaryBackgroundColor;
}
}
imageColor: {
@ -698,7 +705,7 @@ RowLayout {
Rectangle {
height: JamiTheme.chatViewFooterButtonSize
color: JamiTheme.transparentColor
color: JamiTheme.primaryBackgroundColor
visible: showTypo && showTypoSecond
width: 2
@ -713,7 +720,7 @@ RowLayout {
Rectangle {
z: -1
radius: 0
color: JamiTheme.transparentColor
color: JamiTheme.primaryBackgroundColor
width: JamiTheme.chatViewFooterButtonSize
height: JamiTheme.chatViewFooterButtonSize
@ -762,7 +769,7 @@ RowLayout {
id: markdownPopup
y: 1.5 * parent.height
x: -parent.width * 2
width: 155
width: 105
height: JamiTheme.chatViewFooterButtonSize
menuTypoActionsSecond: listViewTypoSecond.menuTypoActionsSecond
@ -818,20 +825,6 @@ RowLayout {
onTriggered: function clickAction() {
listViewTypo.addPrefixStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "", true);
}
},
Action {
id: shiftEnterActiom
property var iconSrc: JamiResources.shift_enter_black_24dp_svg
property var shortcutText: chatViewEnterIsNewLine ? JamiStrings.enterNewLine : JamiStrings.shiftEnterNewLine
property var imageColor: chatViewEnterIsNewLine ? JamiTheme.chatViewFooterImgHoverColor : "#7f7f7f"
property var normalColor: chatViewEnterIsNewLine ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor
property var hasShortcut: false
property var shortcutKey: null
property bool isStyle: false
onTriggered: function clickAction() {
root.chatViewEnterIsNewLine = !root.chatViewEnterIsNewLine;
UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, chatViewEnterIsNewLine);
}
}
]
@ -855,13 +848,13 @@ RowLayout {
normalColor: {
if (showPreview) {
return JamiTheme.transparentColor;
return JamiTheme.primaryBackgroundColor;
} else if (modelData.normalColor != null) {
return modelData.normalColor;
} else if (modelData.isStyle) {
return JamiTheme.hoveredButtonColor;
} else {
return JamiTheme.transparentColor;
return JamiTheme.primaryBackgroundColor;
}
}
imageColor: {
@ -900,24 +893,18 @@ RowLayout {
toolTipText: showTypo ? JamiStrings.hideFormatting : JamiStrings.showFormatting
source: JamiResources.text_edit_black_24dp_svg
normalColor: showPreview ? JamiTheme.transparentColor : (showTypo ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor)
normalColor: showPreview ? JamiTheme.primaryBackgroundColor : (showTypo ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor)
imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered || showTypo ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
onClicked: {
showTypo = !showTypo;
messageBarTextArea.isShowTypo = showTypo;
if (messageBar.width < messageBarLayoutMaximumWidth + sendMessageButton.width + 2 * JamiTheme.preferredMarginSize)
showTypoSecond = false;
if (!showDefault)
showDefault = true;
if (showTypo) {
root.chatViewEnterIsNewLine = true;
UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, true);
} else {
root.chatViewEnterIsNewLine = false;
UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, false);
}
UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo);
UtilsAdapter.setAppValue(Settings.Key.ShowSendOption, !showDefault);
}
@ -1022,7 +1009,7 @@ RowLayout {
toolTipText: modelData.toolTip
source: modelData.iconSrc
normalColor: JamiTheme.transparentColor
normalColor: JamiTheme.primaryBackgroundColor
imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
@ -1161,11 +1148,11 @@ RowLayout {
imageContainerHeight: 25
radius: 5
source: JamiResources.preview_black_24dp_svg
normalColor: showPreview ? hoveredColor : JamiTheme.transparentColor
normalColor: showPreview ? hoveredColor : JamiTheme.primaryBackgroundColor
imageColor: (hovered || showPreview) ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
toolTipText: JamiStrings.showPreview
toolTipText: showPreview ? JamiStrings.continueEditing : JamiStrings.showPreview
onClicked: {
showPreview = !showPreview;

View File

@ -41,6 +41,7 @@ JamiFlickable {
property alias selectionStart: textArea.selectionStart
property alias selectionEnd: textArea.selectionEnd
property bool showPreview: false
property bool isShowTypo: UtilsAdapter.getAppValue(Settings.Key.ShowMardownOption)
ScrollBar.vertical.visible: textArea.text
ScrollBar.horizontal.visible: textArea.text
@ -157,7 +158,7 @@ JamiFlickable {
persistentSelection: true
height: this.paintedHeight
height: textArea.lineCount === 1 ? 35 : textArea.paintedHeight
verticalAlignment: TextEdit.AlignVCenter
@ -206,7 +207,13 @@ JamiFlickable {
const isEnterNewLine = UtilsAdapter.getAppValue(Settings.Key.ChatViewEnterIsNewLine);
const isShiftPressed = (keyEvent.modifiers & Qt.ShiftModifier);
const isCtrlPressed = (keyEvent.modifiers & Qt.ControlModifier);
if (!isEnterNewLine && !isShiftPressed || isCtrlPressed) {
if (!root.isShowTypo && !isShiftPressed) {
root.sendMessagesRequired();
keyEvent.accepted = true;
} else if (isCtrlPressed) {
root.sendMessagesRequired();
keyEvent.accepted = true;
} else if (!isEnterNewLine && !isShiftPressed) {
root.sendMessagesRequired();
keyEvent.accepted = true;
}

View File

@ -76,7 +76,7 @@ Rectangle {
hoveredColor: JamiTheme.hoveredButtonColor
source: JamiResources.ic_baseline_search_24dp_svg
toolTipText: JamiStrings.search
normalColor: "transparent"
normalColor: JamiTheme.primaryBackgroundColor
imageColor: {
if (reductionEnabled) {
if (hovered) {

View File

@ -16,21 +16,19 @@
* 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 net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "../../commoncomponents"
import "../../settingsview/components"
SidePanelBase {
id: root
objectName: "SidePanel"
color: JamiTheme.backgroundColor
@ -39,7 +37,7 @@ SidePanelBase {
target: LRCInstance
function onCurrentAccountIdChanged() {
clearContactSearchBar()
clearContactSearchBar();
}
}
@ -47,8 +45,8 @@ SidePanelBase {
target: ConversationsAdapter
function onConversationReady() {
selectTab(SidePanelTabBar.Conversations)
clearContactSearchBar()
selectTab(SidePanelTabBar.Conversations);
clearContactSearchBar();
}
}
@ -56,46 +54,46 @@ SidePanelBase {
target: ConversationsAdapter
function onShowSearchStatus(status) {
searchStatusText.text = status
searchStatusText.text = status;
}
function onTextFilterChanged(text) {
// In the swarm details, "Go to conversation" can
// change the search bar. Be sure to be synced
contactSearchBar.textContent = text
contactSearchBar.textContent = text;
}
}
function toggleCreateSwarmView() {
if (!inNewSwarm) {
viewCoordinator.present("NewSwarmPage")
const newSwarmPage = viewCoordinator.getView("NewSwarmPage")
viewCoordinator.present("NewSwarmPage");
const newSwarmPage = viewCoordinator.getView("NewSwarmPage");
newSwarmPage.removeMember.connect((convId, member) => {
removeMember(convId, member)
})
removeMember(convId, member);
});
newSwarmPage.createSwarmClicked.connect((title, description, avatar) => {
var uris = []
for (var idx in newSwarmPage.members) {
var uri = newSwarmPage.members[idx].uri
if (uris.indexOf(uri) === -1) {
uris.push(uri)
var uris = [];
for (var idx in newSwarmPage.members) {
var uri = newSwarmPage.members[idx].uri;
if (uris.indexOf(uri) === -1) {
uris.push(uri);
}
}
}
let convuid = ConversationsAdapter.createSwarm(title, description, avatar, uris)
viewCoordinator.dismiss("NewSwarmPage")
LRCInstance.selectConversation(convuid)
})
let convuid = ConversationsAdapter.createSwarm(title, description, avatar, uris);
viewCoordinator.dismiss("NewSwarmPage");
LRCInstance.selectConversation(convuid);
});
} else {
viewCoordinator.dismiss("NewSwarmPage")
viewCoordinator.dismiss("NewSwarmPage");
}
}
function clearContactSearchBar() {
contactSearchBar.clearText()
contactSearchBar.clearText();
}
function selectTab(tabIndex) {
sidePanelTabBar.selectTab(tabIndex)
sidePanelTabBar.selectTab(tabIndex);
}
property bool inNewSwarm: viewCoordinator.currentViewName === "NewSwarmPage"
@ -104,65 +102,64 @@ SidePanelBase {
property var highlightedMembers: []
onHighlightedMembersChanged: {
if (inNewSwarm) {
const newSwarmPage = viewCoordinator.getView("NewSwarmPage")
newSwarmPage.members = highlightedMembers
const newSwarmPage = viewCoordinator.getView("NewSwarmPage");
newSwarmPage.members = highlightedMembers;
}
}
function refreshHighlighted(convId, highlightedStatus) {
var newH = root.highlighted
var newHm = root.highlightedMembers
var newH = root.highlighted;
var newHm = root.highlightedMembers;
if (highlightedStatus) {
var item = ConversationsAdapter.getConvInfoMap(convId)
var added = false
var item = ConversationsAdapter.getConvInfoMap(convId);
var added = false;
for (var idx in item.uris) {
var uri = item.uris[idx]
if (!Array.from(newHm).find(r => r.uri === uri) &&
uri !== CurrentAccount.uri) {
newHm.push({"uri": uri, "convId": convId})
added = true
var uri = item.uris[idx];
if (!Array.from(newHm).find(r => r.uri === uri) && uri !== CurrentAccount.uri) {
newHm.push({
"uri": uri,
"convId": convId
});
added = true;
}
}
if (!added)
return false
return false;
} else {
newH = Array.from(newH).filter(r => r !== convId)
newHm = Array.from(newHm).filter(r => r.convId !== convId)
newH = Array.from(newH).filter(r => r !== convId);
newHm = Array.from(newHm).filter(r => r.convId !== convId);
}
newH.push(convId)
root.highlighted = newH
root.highlightedMembers = newHm
ConversationsAdapter.ignoreFiltering(root.highlighted)
return true
newH.push(convId);
root.highlighted = newH;
root.highlightedMembers = newHm;
ConversationsAdapter.ignoreFiltering(root.highlighted);
return true;
}
function clearHighlighted() {
root.highlighted = []
root.highlightedMembers = []
root.highlighted = [];
root.highlightedMembers = [];
}
function removeMember(convId, member) {
var refreshHighlighted = true
var newHm = []
var refreshHighlighted = true;
var newHm = [];
for (var hm in root.highlightedMembers) {
var m = root.highlightedMembers[hm]
var m = root.highlightedMembers[hm];
if (m.convId === convId && m.uri === member) {
continue;
} else if (m.convId === convId) {
refreshHighlighted = false
refreshHighlighted = false;
}
newHm.push(m)
newHm.push(m);
}
root.highlightedMembers = newHm
root.highlightedMembers = newHm;
if (refreshHighlighted) {
// Remove highlighted status if necessary
for (var d in swarmCurrentConversationList.contentItem.children) {
var delegate = swarmCurrentConversationList.contentItem.children[d]
var delegate = swarmCurrentConversationList.contentItem.children[d];
if (delegate.convId === convId)
delegate.highlighted = false
delegate.highlighted = false;
}
}
}
@ -176,11 +173,16 @@ SidePanelBase {
color: JamiTheme.backgroundColor
}
header: AccountComboBox {}
header: AccountComboBox {
}
Item {
anchors.fill: parent
onVisibleChanged: {
donation.donationVisible = Qt.binding(() => JamiQmlUtils.isDonationBannerVisible());
}
RowLayout {
id: titleBar
@ -240,7 +242,7 @@ SidePanelBase {
sequence: "Ctrl+F"
context: Qt.ApplicationShortcut
onActivated: {
contactSearchBar.forceActiveFocus()
contactSearchBar.forceActiveFocus();
}
}
@ -250,20 +252,18 @@ SidePanelBase {
Layout.fillHeight: true
Layout.fillWidth: true
onSearchBarTextChanged: function(text){
onSearchBarTextChanged: function (text) {
// not calling positionViewAtBeginning will cause
// sort animation visual bugs
conversationListView.positionViewAtBeginning()
ConversationsAdapter.ignoreFiltering(root.highlighted)
ConversationsAdapter.setFilter(text)
conversationListView.positionViewAtBeginning();
ConversationsAdapter.ignoreFiltering(root.highlighted);
ConversationsAdapter.setFilter(text);
}
onReturnPressedWhileSearching: {
var listView = searchResultsListView.count ?
searchResultsListView :
conversationListView
var listView = searchResultsListView.count ? searchResultsListView : conversationListView;
if (listView.count)
listView.model.select(0)
listView.model.select(0);
}
}
@ -291,8 +291,7 @@ SidePanelBase {
SidePanelTabBar {
id: sidePanelTabBar
visible: ConversationsAdapter.pendingRequestCount &&
!contactSearchBar.textContent && smartListLayout.visible
visible: ConversationsAdapter.pendingRequestCount && !contactSearchBar.textContent && smartListLayout.visible
anchors.top: startBar.bottom
anchors.topMargin: visible ? 10 : 0
width: page.width
@ -311,7 +310,6 @@ SidePanelBase {
height: visible ? 42 : 0
color: JamiTheme.backgroundColor
Text {
id: searchStatusText
@ -326,13 +324,22 @@ SidePanelBase {
}
}
DonationBanner {
id: donation
anchors.horizontalCenter: parent.horizontalCenter
anchors.leftMargin: 15
anchors.rightMargin: 15
anchors.top: sidePanelTabBar.bottom
anchors.topMargin: 10
visible: donation.donationVisible
}
ColumnLayout {
id: smartListLayout
width: parent.width
anchors.top: searchStatusRect.bottom
anchors.topMargin: (sidePanelTabBar.visible ||
searchStatusRect.visible) ? 0 : 12
anchors.top: donation.donationVisible ? donation.bottom : searchStatusRect.bottom
anchors.topMargin: (sidePanelTabBar.visible || searchStatusRect.visible) ? 0 : 12
anchors.bottom: parent.bottom
spacing: 4
@ -350,14 +357,14 @@ SidePanelBase {
Layout.fillWidth: true
Layout.preferredHeight: visible ? contentHeight : 0
Layout.maximumHeight: {
var otherContentHeight = conversationListView.contentHeight + 16
var otherContentHeight = conversationListView.contentHeight + 16;
if (conversationListView.visible)
if (otherContentHeight < parent.height / 2)
return parent.height - otherContentHeight
return parent.height - otherContentHeight;
else
return parent.height / 2
return parent.height / 2;
else
return parent.height
return parent.height;
}
model: SearchResultsListModel
@ -385,9 +392,8 @@ SidePanelBase {
visible: inNewSwarm
width: parent.width
anchors.top: searchStatusRect.bottom
anchors.topMargin: (sidePanelTabBar.visible ||
searchStatusRect.visible) ? 0 : 12
anchors.top: donation.donationVisible ? donation.bottom : sidePanelTabBar.bottom
anchors.topMargin: (sidePanelTabBar.visible || searchStatusRect.visible) ? 0 : 12
anchors.bottom: parent.bottom
spacing: 4
@ -404,8 +410,8 @@ SidePanelBase {
onVisibleChanged: {
if (!swarmCurrentConversationList.visible) {
highlighted = false
root.clearHighlighted()
highlighted = false;
root.clearHighlighted();
}
}
@ -414,26 +420,26 @@ SidePanelBase {
// destroyed from the memory. So, re-add the highlighted
// status if necessary
if (Array.from(root.highlighted).find(r => r === UID)) {
highlighted = true
highlighted = true;
}
}
onHighlightedChanged: function onHighlightedChanged() {
if (highlighted && Array.from(root.highlighted).find(r => r === UID)) {
// Due to scrolling destruction/reconstruction
return
return;
}
var currentHighlighted = root.highlighted
var currentHighlighted = root.highlighted;
if (!root.refreshHighlighted(UID, highlighted)) {
highlighted = false
return
highlighted = false;
return;
}
if (highlighted) {
root.highlighted.push(UID)
root.highlighted.push(UID);
} else {
root.highlighted = Array.from(root.highlighted).filter(r => r !== UID)
root.highlighted = Array.from(root.highlighted).filter(r => r !== UID);
}
root.clearContactSearchBar()
root.clearContactSearchBar();
}
}
currentIndex: model.currentFilteredRow
@ -448,7 +454,9 @@ SidePanelBase {
interval: 750
running: isSharingPosition || isReceivingPosition
repeat: true
onTriggered: {showIconArrow = !showIconArrow}
onTriggered: {
showIconArrow = !showIconArrow;
}
}
}
}

View File

@ -37,7 +37,6 @@ FocusScope {
property color textColor: JamiTheme.textColor
property color iconColor: JamiTheme.tintedBlue
property string customizeTip: "CustomizeTipBox {}"
property string backupTip: "BackupTipBox {" + " onIgnore: {" + " root.ignoreClicked()" + " }" + "}"
@ -56,7 +55,6 @@ FocusScope {
focus: true
activeFocusOnTab: true
Rectangle {
id: rect
anchors.fill: parent
@ -73,6 +71,18 @@ FocusScope {
width: parent.width
anchors.topMargin: 10
Loader {
id: loader_donationTip
active: type === "donation"
focus: true
sourceComponent: DonationTipBox {
maxHeight: root.maximumHeight
textColor: root.textColor
iconColor: root.iconColor
}
width: parent.width
}
Loader {
id: loader_backupTip
active: type === "backup"
@ -95,7 +105,6 @@ FocusScope {
}
width: parent.width
focus: true
}
Loader {
id: loader_infoTip
@ -106,7 +115,6 @@ FocusScope {
iconColor: root.iconColor
}
width: parent.width
}
}
}
@ -119,6 +127,7 @@ FocusScope {
TapHandler {
target: rect
enabled: type !== "donation"
onTapped: {
return opened ? focus = false : root.forceActiveFocus();
}

View File

@ -31,7 +31,7 @@ Item {
property color textColor: JamiTheme.textColor
property color idColor: JamiTheme.welcomeBlockColor
property color contentIdColor: JamiTheme.tintedBlue
property bool hasTitle: true
property bool hasTitle: false
property bool hasDescription: true
property string title: JamiStrings.welcomeToJami
@ -39,8 +39,6 @@ Item {
property real contentWidth: welcomeInfo.width - 2 * JamiTheme.mainViewMargin
function getHeight() {
return bgRect.height;
}
@ -70,7 +68,6 @@ Item {
Loader {
id: loader_identifierDescription
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: contentWidth
Layout.preferredHeight: item ? item.contentHeight : 0
Layout.bottomMargin: loader_bottomIdentifier.item ? JamiTheme.mainViewMargin - 10 : 0
sourceComponent: {
@ -93,7 +90,6 @@ Item {
sourceComponent: JamiIdentifier {
backgroundColor: welcomeInfo.idColor
contentColor: contentIdColor
}
Layout.alignment: Qt.AlignHCenter
Layout.preferredHeight: active ? item.getHeight() : 0
@ -133,7 +129,7 @@ Item {
width: welcomeInfo.contentWidth
height: contentHeight
font.pixelSize: JamiTheme.headerFontSize
font.pixelSize: JamiTheme.tipBoxContentFontSize
wrapMode: Text.WordWrap

View File

@ -36,18 +36,18 @@ Item {
width: getWidth()
function getWidth() {
return JamiTheme.welcomeHalfGridWidth;
return JamiTheme.welcomeThirdGridWidth;
}
function getHeight() {
return 120;
return 80;
}
CachedImage {
id: cachedImgLogo
objectName: "cachedImgLogo"
downloadUrl: logoUrl
defaultImage: JamiResources.jami_logo_icon_svg
defaultImage: JamiTheme.welcomeLogo
visible: welcomeLogo.visible
height: parent.height * logoSize
width: parent.width * logoSize

View File

@ -49,7 +49,7 @@ ListSelectionView {
property bool hasCustomUi: false
property bool hasTitle: true
property bool hasTitle: false
property bool hasDescription: true
property bool hasCustomTitle: false
@ -95,7 +95,7 @@ ListSelectionView {
function updateUiFlags() {
hasCustomUi = Object.keys(uiCustomization).length > 0;
hasTitle = hasCustomUi ? uiCustomization.title !== "" : true;
hasTitle = hasCustomUi ? uiCustomization.title !== "" : false;
hasDescription = hasCustomUi ? uiCustomization.description !== "" : true;
title = hasCustomUi && uiCustomization.title !== undefined ? uiCustomization.title : JamiStrings.welcomeToJami;
description = hasCustomUi && uiCustomization.description !== undefined ? uiCustomization.description : JamiStrings.hereIsIdentifier;
@ -261,16 +261,14 @@ ListSelectionView {
TextMetrics {
id: textSize
font.weight: Font.Bold
font.pixelSize: 20
font.capitalization: Font.AllUppercase
text: aboutJami.text
}
tertiary: true
anchors.horizontalCenter: parent.horizontalCenter
preferredWidth: textSize.width
preferredWidth: text.width
text: JamiStrings.aboutJami
fontSize: 12
onClicked: viewCoordinator.presentDialog(appWindow, "mainview/components/AboutPopUp.qml")
}

View File

@ -25,6 +25,28 @@
#include <QtNetwork>
#include <QScopedPointer>
namespace {
NetworkManager::GetError
translateErrorCode(QNetworkReply::NetworkError error)
{
// From qnetworkreply.h:
// network layer errors (1-99): / proxy errors (101-199):
// content errors (201-299): ContentAccessDenied = 201,
// protocol errors / Server side errors (401-499)
static auto inRange = [](int value, int min, int max) -> bool {
return (value >= min && value <= max);
};
if (inRange(error, 1, 199))
return NetworkManager::NETWORK_ERROR;
if (inRange(error, 201, 201))
return NetworkManager::ACCESS_DENIED;
if (inRange(error, 202, 299))
return NetworkManager::CONTENT_NOT_FOUND;
return NetworkManager::NETWORK_ERROR;
}
} // namespace
NetworkManager::NetworkManager(ConnectivityMonitor* cm, QObject* parent)
: QObject(parent)
, manager_(new QNetworkAccessManager(this))
@ -45,7 +67,7 @@ NetworkManager::NetworkManager(ConnectivityMonitor* cm, QObject* parent)
});
#endif
connect(connectivityMonitor_, &ConnectivityMonitor::connectivityChanged, this, [this] {
auto connected = connectivityMonitor_->isOnline();
const auto connected = connectivityMonitor_->isOnline();
if (connected && !lastConnectionState_) {
manager_->deleteLater();
manager_ = new QNetworkAccessManager(this);
@ -59,7 +81,7 @@ void
NetworkManager::sendGetRequest(const QUrl& url,
std::function<void(const QByteArray&)>&& onDoneCallback)
{
QNetworkRequest request = QNetworkRequest(url);
const QNetworkRequest request = QNetworkRequest(url);
sendGetRequest(request, std::move(onDoneCallback));
}
@ -98,9 +120,8 @@ NetworkManager::downloadFile(const QUrl& url,
const QString& filePath,
const QString& extension)
{
// If there is already a download in progress, return.
if ((downloadReplies_.value(replyId) != NULL || !(replyId == 0))
&& downloadReplies_[replyId]->isRunning()) {
// Don't replace the download if there is already a download in progress for this id.
if (downloadReplies_.contains(replyId) && downloadReplies_.value(replyId)->isRunning()) {
qWarning() << Q_FUNC_INFO << "Download already in progress";
return replyId;
}
@ -121,6 +142,7 @@ NetworkManager::downloadFile(const QUrl& url,
}
// set the id for the request
// NOLINTNEXTLINE(misc-const-correctness)
std::uniform_int_distribution<int> dist(1, std::numeric_limits<int>::max());
auto uuid = dist(rng_);
@ -133,7 +155,7 @@ NetworkManager::downloadFile(const QUrl& url,
const QFileInfo fileInfo(url.path());
const QString fileName = fileInfo.fileName();
auto& file = files_[uuid];
file = new QFile(filePath + fileName + extension);
file = new QFile(filePath + QDir::separator() + fileName + extension);
if (!file->open(QIODevice::WriteOnly)) {
Q_EMIT errorOccurred(GetError::ACCESS_DENIED);
files_.remove(uuid);
@ -167,7 +189,7 @@ NetworkManager::downloadFile(const QUrl& url,
resetDownload(uuid);
qWarning() << Q_FUNC_INFO
<< QMetaEnum::fromType<QNetworkReply::NetworkError>().valueToKey(error);
Q_EMIT errorOccurred(GetError::NETWORK_ERROR);
Q_EMIT errorOccurred(translateErrorCode(error));
});
connect(reply, &QNetworkReply::finished, this, [this, uuid, onDoneCallback, reply, file]() {

View File

@ -23,6 +23,7 @@
#include <QMap>
#include <QString>
#include <QNetworkReply>
#include <random>
class QNetworkAccessManager;
@ -35,7 +36,14 @@ public:
explicit NetworkManager(ConnectivityMonitor* cm, QObject* parent = nullptr);
virtual ~NetworkManager() = default;
enum GetError { DISCONNECTED, NETWORK_ERROR, ACCESS_DENIED, SSL_ERROR, CANCELED };
enum GetError {
DISCONNECTED,
CONTENT_NOT_FOUND,
ACCESS_DENIED,
SSL_ERROR,
CANCELED,
NETWORK_ERROR,
};
Q_ENUM(GetError)
void sendGetRequest(const QUrl& url, std::function<void(const QByteArray&)>&& onDoneCallback);
@ -48,7 +56,7 @@ public:
int replyId,
std::function<void(bool, const QString&)>&& onDoneCallback,
const QString& filePath,
const QString& extension = "");
const QString& extension = {});
void resetDownload(int replyId);
void cancelDownload(int replyId);
Q_SIGNALS:

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pttlistener.h"
#include <QCoreApplication>
#include <QVariant>
class PTTListener::Impl : public QObject
{
Q_OBJECT
public:
Impl(PTTListener* parent)
: QObject(parent)
{}
~Impl() = default;
};
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
: settingsManager_(settingsManager)
, QObject(parent)
, pimpl_(std::make_unique<Impl>(this))
{}
PTTListener::~PTTListener() = default;
#include "pttlistener.moc"

View File

@ -0,0 +1,390 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
#include "pttlistener.h"
#include <QCoreApplication>
#include <QVariant>
class PTTListener::Impl : public QObject
{
Q_OBJECT
public:
Impl(PTTListener* parent)
: QObject(parent)
{
qApp->setProperty("PTTListener", QVariant::fromValue(parent));
}
~Impl()
{
stopListening();
};
void startListening()
{
CGEventMask eventMask = (1 << kCGEventKeyDown) | (1 << kCGEventKeyUp);
CFMachPortRef eventTap = CGEventTapCreate(kCGHIDEventTap,
kCGHeadInsertEventTap,
kCGEventTapOptionDefault,
eventMask,
CGEventCallback,
this);
if (eventTap) {
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
eventTap,
0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
CFRelease(runLoopSource);
CGEventTapEnable(eventTap, true);
} else {
qDebug() << "Impossible to create the keyboard tap.";
}
}
void stopListening()
{
if (eventTap) {
CGEventTapEnable(eventTap, false);
CFRelease(eventTap);
}
}
static CGEventRef CGEventCallback(CGEventTapProxy proxy,
CGEventType type,
CGEventRef event,
void* refcon)
{
auto* pThis = qApp->property("PTTListener").value<PTTListener*>();
CGKeyCode keycode = (CGKeyCode) CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);
if (pThis == nullptr) {
qWarning() << "PTTListener not found";
return {};
}
CGKeyCode pttKey = (CGKeyCode) pThis->pimpl_->qtKeyTokVKey(pThis->getCurrentKey());
static bool isKeyDown = false;
if (keycode == pttKey) {
if (type == kCGEventKeyDown && !isKeyDown) {
Q_EMIT pThis->pttKeyPressed();
isKeyDown = true;
} else if (type == kCGEventKeyUp && isKeyDown) {
Q_EMIT pThis->pttKeyReleased();
isKeyDown = false;
}
}
return event;
}
quint32 qtKeyTokVKey(Qt::Key key);
private:
CFMachPortRef eventTap;
};
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
: settingsManager_(settingsManager)
, QObject(parent)
, pimpl_(std::make_unique<Impl>(this))
{}
PTTListener::~PTTListener() = default;
void
PTTListener::startListening()
{
pimpl_->startListening();
}
void
PTTListener::stopListening()
{
pimpl_->stopListening();
}
quint32
PTTListener::Impl::qtKeyTokVKey(Qt::Key key)
{
UTF16Char ch;
// Constants found in NSEvent.h from AppKit.framework
switch (key) {
case Qt::Key_Return:
return kVK_Return;
case Qt::Key_Enter:
return kVK_ANSI_KeypadEnter;
case Qt::Key_Tab:
return kVK_Tab;
case Qt::Key_Space:
return kVK_Space;
case Qt::Key_Backspace:
return kVK_Delete;
case Qt::Key_Control:
return kVK_Command;
case Qt::Key_Shift:
return kVK_Shift;
case Qt::Key_CapsLock:
return kVK_CapsLock;
case Qt::Key_Option:
return kVK_Option;
case Qt::Key_Meta:
return kVK_Control;
case Qt::Key_F17:
return kVK_F17;
case Qt::Key_VolumeUp:
return kVK_VolumeUp;
case Qt::Key_VolumeDown:
return kVK_VolumeDown;
case Qt::Key_F18:
return kVK_F18;
case Qt::Key_F19:
return kVK_F19;
case Qt::Key_F20:
return kVK_F20;
case Qt::Key_F5:
return kVK_F5;
case Qt::Key_F6:
return kVK_F6;
case Qt::Key_F7:
return kVK_F7;
case Qt::Key_F3:
return kVK_F3;
case Qt::Key_F8:
return kVK_F8;
case Qt::Key_F9:
return kVK_F9;
case Qt::Key_F11:
return kVK_F11;
case Qt::Key_F13:
return kVK_F13;
case Qt::Key_F16:
return kVK_F16;
case Qt::Key_F14:
return kVK_F14;
case Qt::Key_F10:
return kVK_F10;
case Qt::Key_F12:
return kVK_F12;
case Qt::Key_F15:
return kVK_F15;
case Qt::Key_Help:
return kVK_Help;
case Qt::Key_Home:
return kVK_Home;
case Qt::Key_PageUp:
return kVK_PageUp;
case Qt::Key_Delete:
return kVK_ForwardDelete;
case Qt::Key_F4:
return kVK_F4;
case Qt::Key_End:
return kVK_End;
case Qt::Key_F2:
return kVK_F2;
case Qt::Key_PageDown:
return kVK_PageDown;
case Qt::Key_F1:
return kVK_F1;
case Qt::Key_Left:
return kVK_LeftArrow;
case Qt::Key_Right:
return kVK_RightArrow;
case Qt::Key_Down:
return kVK_DownArrow;
case Qt::Key_Up:
return kVK_UpArrow;
default:;
}
if (key == Qt::Key_Escape)
ch = 27;
else if (key == Qt::Key_Return)
ch = 13;
else if (key == Qt::Key_Enter)
ch = 3;
else if (key == Qt::Key_Tab)
ch = 9;
else
ch = key;
CFDataRef currentLayoutData;
TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
if (currentKeyboard == nullptr)
return 0;
currentLayoutData = (CFDataRef) TISGetInputSourceProperty(currentKeyboard,
kTISPropertyUnicodeKeyLayoutData);
CFRelease(currentKeyboard);
if (currentLayoutData == nullptr)
return 0;
UCKeyboardLayout* header = (UCKeyboardLayout*) CFDataGetBytePtr(currentLayoutData);
UCKeyboardTypeHeader* table = header->keyboardTypeList;
uint8_t* data = (uint8_t*) header;
// God, would a little documentation for this shit kill you...
for (quint32 i = 0; i < header->keyboardTypeCount; i++) {
UCKeyStateRecordsIndex* stateRec = 0;
if (table[i].keyStateRecordsIndexOffset != 0) {
stateRec = reinterpret_cast<UCKeyStateRecordsIndex*>(
data + table[i].keyStateRecordsIndexOffset);
if (stateRec->keyStateRecordsIndexFormat != kUCKeyStateRecordsIndexFormat)
stateRec = 0;
}
UCKeyToCharTableIndex* charTable = reinterpret_cast<UCKeyToCharTableIndex*>(
data + table[i].keyToCharTableIndexOffset);
if (charTable->keyToCharTableIndexFormat != kUCKeyToCharTableIndexFormat)
continue;
for (quint32 j = 0; j < charTable->keyToCharTableCount; j++) {
UCKeyOutput* keyToChar = reinterpret_cast<UCKeyOutput*>(
data + charTable->keyToCharTableOffsets[j]);
for (quint32 k = 0; k < charTable->keyToCharTableSize; k++) {
if (keyToChar[k] & kUCKeyOutputTestForIndexMask) {
long idx = keyToChar[k] & kUCKeyOutputGetIndexMask;
if (stateRec && idx < stateRec->keyStateRecordCount) {
UCKeyStateRecord* rec = reinterpret_cast<UCKeyStateRecord*>(
data + stateRec->keyStateRecordOffsets[idx]);
if (rec->stateZeroCharData == ch)
return k;
}
} else if (!(keyToChar[k] & kUCKeyOutputSequenceIndexMask)
&& keyToChar[k] < 0xFFFE) {
if (keyToChar[k] == ch)
return k;
}
} // for k
} // for j
} // for i
// The code above fails to translate keys like semicolon with Qt 5.7.1.
// Last resort is to try mapping the rest of the keys directly.
switch (key) {
case Qt::Key_A:
return kVK_ANSI_A;
case Qt::Key_S:
return kVK_ANSI_S;
case Qt::Key_D:
return kVK_ANSI_D;
case Qt::Key_F:
return kVK_ANSI_F;
case Qt::Key_H:
return kVK_ANSI_H;
case Qt::Key_G:
return kVK_ANSI_G;
case Qt::Key_Z:
return kVK_ANSI_Z;
case Qt::Key_X:
return kVK_ANSI_X;
case Qt::Key_C:
return kVK_ANSI_C;
case Qt::Key_V:
return kVK_ANSI_V;
case Qt::Key_B:
return kVK_ANSI_B;
case Qt::Key_Q:
return kVK_ANSI_Q;
case Qt::Key_W:
return kVK_ANSI_W;
case Qt::Key_E:
return kVK_ANSI_E;
case Qt::Key_R:
return kVK_ANSI_R;
case Qt::Key_Y:
return kVK_ANSI_Y;
case Qt::Key_T:
return kVK_ANSI_T;
case Qt::Key_1:
return kVK_ANSI_1;
case Qt::Key_2:
return kVK_ANSI_2;
case Qt::Key_3:
return kVK_ANSI_3;
case Qt::Key_4:
return kVK_ANSI_4;
case Qt::Key_6:
return kVK_ANSI_6;
case Qt::Key_5:
return kVK_ANSI_5;
case Qt::Key_Equal:
return kVK_ANSI_Equal;
case Qt::Key_9:
return kVK_ANSI_9;
case Qt::Key_7:
return kVK_ANSI_7;
case Qt::Key_Minus:
return kVK_ANSI_Minus;
case Qt::Key_8:
return kVK_ANSI_8;
case Qt::Key_0:
return kVK_ANSI_0;
case Qt::Key_BracketRight:
return kVK_ANSI_RightBracket;
case Qt::Key_O:
return kVK_ANSI_O;
case Qt::Key_U:
return kVK_ANSI_U;
case Qt::Key_BracketLeft:
return kVK_ANSI_LeftBracket;
case Qt::Key_I:
return kVK_ANSI_I;
case Qt::Key_P:
return kVK_ANSI_P;
case Qt::Key_L:
return kVK_ANSI_L;
case Qt::Key_J:
return kVK_ANSI_J;
case Qt::Key_QuoteDbl:
return kVK_ANSI_Quote;
case Qt::Key_K:
return kVK_ANSI_K;
case Qt::Key_Semicolon:
return kVK_ANSI_Semicolon;
case Qt::Key_Backslash:
return kVK_ANSI_Backslash;
case Qt::Key_Comma:
return kVK_ANSI_Comma;
case Qt::Key_Slash:
return kVK_ANSI_Slash;
case Qt::Key_N:
return kVK_ANSI_N;
case Qt::Key_M:
return kVK_ANSI_M;
case Qt::Key_Period:
return kVK_ANSI_Period;
case Qt::Key_Dead_Grave:
return kVK_ANSI_Grave;
case Qt::Key_Asterisk:
return kVK_ANSI_KeypadMultiply;
case Qt::Key_Plus:
return kVK_ANSI_KeypadPlus;
case Qt::Key_Clear:
return kVK_ANSI_KeypadClear;
case Qt::Key_Escape:
return kVK_Escape;
default:;
}
return 0;
}
#include "pttlistener.moc"

View File

@ -0,0 +1,309 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pttlistener.h"
#include <QCoreApplication>
#include <QVariant>
#include <Windows.h>
class PTTListener::Impl : public QObject
{
Q_OBJECT
public:
Impl(PTTListener* parent)
: QObject(nullptr)
{
qApp->setProperty("PTTListener", QVariant::fromValue(parent));
}
~Impl()
{
stopListening();
};
void startListening()
{
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, GlobalKeyboardProc, NULL, 0);
}
void stopListening()
{
UnhookWindowsHookEx(keyboardHook);
}
static LRESULT CALLBACK GlobalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
auto* pThis = qApp->property("PTTListener").value<PTTListener*>();
if (pThis == nullptr) {
qWarning() << "PTTListener not found";
return {};
}
auto* keyboardHook = pThis->pimpl_->keyboardHook;
quint32 key = qtKeyToVKey(pThis->getCurrentKey());
static bool isKeyDown = false;
if (nCode == HC_ACTION) {
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
KBDLLHOOKSTRUCT* keyInfo = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
if (keyInfo->vkCode == key && !isKeyDown) {
Q_EMIT pThis->pttKeyPressed();
isKeyDown = true;
}
} else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
KBDLLHOOKSTRUCT* keyInfo = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
if (keyInfo->vkCode == key) {
Q_EMIT pThis->pttKeyReleased();
isKeyDown = false;
}
}
}
return CallNextHookEx(keyboardHook, nCode, wParam, lParam);
}
HHOOK keyboardHook;
static quint32 qtKeyToVKey(Qt::Key key);
};
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
: settingsManager_(settingsManager)
, QObject(parent)
, pimpl_(std::make_unique<Impl>(this))
{}
PTTListener::~PTTListener() = default;
#ifdef HAVE_GLOBAL_PTT
void
PTTListener::startListening()
{
pimpl_->startListening();
}
void
PTTListener::stopListening()
{
pimpl_->stopListening();
}
#endif
quint32
PTTListener::Impl::qtKeyToVKey(Qt::Key key)
{
switch (key) {
case Qt::Key_Escape:
return VK_ESCAPE;
case Qt::Key_Tab:
case Qt::Key_Backtab:
return VK_TAB;
case Qt::Key_Backspace:
return VK_BACK;
case Qt::Key_Return:
case Qt::Key_Enter:
return VK_RETURN;
case Qt::Key_Insert:
return VK_INSERT;
case Qt::Key_Delete:
return VK_DELETE;
case Qt::Key_Pause:
return VK_PAUSE;
case Qt::Key_Print:
return VK_PRINT;
case Qt::Key_Clear:
return VK_CLEAR;
case Qt::Key_Home:
return VK_HOME;
case Qt::Key_End:
return VK_END;
case Qt::Key_Left:
return VK_LEFT;
case Qt::Key_Up:
return VK_UP;
case Qt::Key_Right:
return VK_RIGHT;
case Qt::Key_Down:
return VK_DOWN;
case Qt::Key_PageUp:
return VK_PRIOR;
case Qt::Key_PageDown:
return VK_NEXT;
case Qt::Key_F1:
return VK_F1;
case Qt::Key_F2:
return VK_F2;
case Qt::Key_F3:
return VK_F3;
case Qt::Key_F4:
return VK_F4;
case Qt::Key_F5:
return VK_F5;
case Qt::Key_F6:
return VK_F6;
case Qt::Key_F7:
return VK_F7;
case Qt::Key_F8:
return VK_F8;
case Qt::Key_F9:
return VK_F9;
case Qt::Key_F10:
return VK_F10;
case Qt::Key_F11:
return VK_F11;
case Qt::Key_F12:
return VK_F12;
case Qt::Key_F13:
return VK_F13;
case Qt::Key_F14:
return VK_F14;
case Qt::Key_F15:
return VK_F15;
case Qt::Key_F16:
return VK_F16;
case Qt::Key_F17:
return VK_F17;
case Qt::Key_F18:
return VK_F18;
case Qt::Key_F19:
return VK_F19;
case Qt::Key_F20:
return VK_F20;
case Qt::Key_F21:
return VK_F21;
case Qt::Key_F22:
return VK_F22;
case Qt::Key_F23:
return VK_F23;
case Qt::Key_F24:
return VK_F24;
case Qt::Key_Space:
return VK_SPACE;
case Qt::Key_Asterisk:
return VK_MULTIPLY;
case Qt::Key_Plus:
return VK_ADD;
case Qt::Key_Minus:
return VK_SUBTRACT;
case Qt::Key_Slash:
return VK_DIVIDE;
case Qt::Key_MediaNext:
return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious:
return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay:
return VK_MEDIA_PLAY_PAUSE;
case Qt::Key_MediaStop:
return VK_MEDIA_STOP;
// couldn't find those in VK_*
// case Qt::Key_MediaLast:
// case Qt::Key_MediaRecord:
case Qt::Key_VolumeDown:
return VK_VOLUME_DOWN;
case Qt::Key_VolumeUp:
return VK_VOLUME_UP;
case Qt::Key_VolumeMute:
return VK_VOLUME_MUTE;
case Qt::Key_0:
return VK_NUMPAD0;
case Qt::Key_1:
return VK_NUMPAD1;
case Qt::Key_2:
return VK_NUMPAD2;
case Qt::Key_3:
return VK_NUMPAD3;
case Qt::Key_4:
return VK_NUMPAD4;
case Qt::Key_5:
return VK_NUMPAD5;
case Qt::Key_6:
return VK_NUMPAD6;
case Qt::Key_7:
return VK_NUMPAD7;
case Qt::Key_8:
return VK_NUMPAD8;
case Qt::Key_9:
return VK_NUMPAD9;
case Qt::Key_A:
return 'A';
case Qt::Key_B:
return 'B';
case Qt::Key_C:
return 'C';
case Qt::Key_D:
return 'D';
case Qt::Key_E:
return 'E';
case Qt::Key_F:
return 'F';
case Qt::Key_G:
return 'G';
case Qt::Key_H:
return 'H';
case Qt::Key_I:
return 'I';
case Qt::Key_J:
return 'J';
case Qt::Key_K:
return 'K';
case Qt::Key_L:
return 'L';
case Qt::Key_M:
return 'M';
case Qt::Key_N:
return 'N';
case Qt::Key_O:
return 'O';
case Qt::Key_P:
return 'P';
case Qt::Key_Q:
return 'Q';
case Qt::Key_R:
return 'R';
case Qt::Key_S:
return 'S';
case Qt::Key_T:
return 'T';
case Qt::Key_U:
return 'U';
case Qt::Key_V:
return 'V';
case Qt::Key_W:
return 'W';
case Qt::Key_X:
return 'X';
case Qt::Key_Y:
return 'Y';
case Qt::Key_Z:
return 'Z';
default:
//Try to get virtual key from current keyboard layout or US.
const HKL layout = GetKeyboardLayout(0);
int vk = VkKeyScanEx(key, layout);
if (vk == -1) {
const HKL layoutUs = GetKeyboardLayout(0x409);
vk = VkKeyScanEx(key, layoutUs);
}
return vk == -1 ? 0 : vk;
}
}
#include "pttlistener.moc"

View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pttlistener.h"
#include "appsettingsmanager.h"
#include "xcbkeyboard.h"
#include <QCoreApplication>
#include <QVariant>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <thread>
class PTTListener::Impl : public QObject
{
Q_OBJECT
public:
Impl(PTTListener* parent)
: QObject(nullptr)
, parent_(*parent)
, display_(XOpenDisplay(NULL))
, root_(DefaultRootWindow(display_))
{
thread_.reset(new QThread());
moveToThread(thread_.get());
}
~Impl()
{
stopListening();
XCloseDisplay(display_);
};
void startListening()
{
stop_.store(false);
connect(thread_.get(), &QThread::started, this, &Impl::processEvents);
thread_->start();
}
void stopListening()
{
stop_.store(true);
thread_->quit();
thread_->wait();
}
static const unsigned int* keyTbl_;
KeySym getKeySymFromQtKey(Qt::Key qtKey);
QString keySymToQString(KeySym ks);
KeySym qtKeyToXKeySym(Qt::Key key);
private Q_SLOTS:
void processEvents()
{
Window curFocus;
char buf[17];
KeySym ks;
XComposeStatus comp;
int len;
int revert;
static auto flags = KeyPressMask | KeyReleaseMask | FocusChangeMask;
XGetInputFocus(display_, &curFocus, &revert);
XSelectInput(display_, curFocus, flags);
bool pressed = false;
KeySym key = qtKeyToXKeySym(parent_.getCurrentKey());
while (!stop_.load()) {
std::this_thread::sleep_for(std::chrono::milliseconds(10));
while (XPending(display_)) {
XEvent ev;
XNextEvent(display_, &ev);
XLookupString(&ev.xkey, buf, 16, &ks, &comp);
switch (ev.type) {
case FocusOut:
if (curFocus != root_)
XSelectInput(display_, curFocus, 0);
XGetInputFocus(display_, &curFocus, &revert);
if (curFocus == PointerRoot)
curFocus = root_;
XSelectInput(display_, curFocus, flags);
break;
case KeyPress: {
if (!(pressed) && ks == key) {
Q_EMIT parent_.pttKeyPressed();
pressed = true;
}
break;
}
case KeyRelease:
bool is_retriggered = false;
if (XEventsQueued(display_, QueuedAfterReading)) {
XEvent nev;
XPeekEvent(display_, &nev);
if (nev.type == KeyPress && nev.xkey.time == ev.xkey.time
&& nev.xkey.keycode == ev.xkey.keycode) {
is_retriggered = true;
}
}
if (!is_retriggered && ks == key) {
Q_EMIT parent_.pttKeyReleased();
pressed = false;
}
break;
}
}
}
}
private:
PTTListener& parent_;
Display* display_;
Window root_;
QScopedPointer<QThread> thread_;
std::atomic_bool stop_ {false};
};
QString
PTTListener::Impl::keySymToQString(KeySym ks)
{
return QString::fromUtf8(XKeysymToString(ks));
}
KeySym
PTTListener::Impl::qtKeyToXKeySym(Qt::Key key)
{
const auto keySym = getKeySymFromQtKey(key);
if (keySym != NoSymbol) {
return keySym;
}
for (int i = 0; keyTbl_[i] != 0; i += 2) {
if (keyTbl_[i + 1] == key)
return keyTbl_[i];
}
return static_cast<ushort>(key);
}
PTTListener::PTTListener(AppSettingsManager* settingsManager, QObject* parent)
: settingsManager_(settingsManager)
, QObject(parent)
, pimpl_(std::make_unique<Impl>(this))
{}
PTTListener::~PTTListener() = default;
void
PTTListener::startListening()
{
pimpl_->startListening();
}
void
PTTListener::stopListening()
{
pimpl_->stopListening();
}
KeySym
PTTListener::Impl::getKeySymFromQtKey(Qt::Key qtKey)
{
QString keyString = QKeySequence(qtKey).toString().toLower();
KeySym keySym = XStringToKeysym(keyString.toUtf8().data());
return keySym;
}
const unsigned int* PTTListener::Impl::keyTbl_ = keyTable;
#include "pttlistener.moc"

View File

@ -0,0 +1,856 @@
#include "pttlistener.h"
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
// Following definitions and table are taken from
// "qt5/qtbase/src/plugins/platforms/xcb/qxcbkeyboard.cpp".
#include <Qt>
#include <X11/keysym.h>
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
#endif
#ifndef XK_dead_hook
#define XK_dead_hook 0xFE61
#endif
#ifndef XK_dead_horn
#define XK_dead_horn 0xFE62
#endif
#ifndef XK_Codeinput
#define XK_Codeinput 0xFF37
#endif
#ifndef XK_Kanji_Bangou
#define XK_Kanji_Bangou 0xFF37 /* same as codeinput */
#endif
// Fix old X libraries
#ifndef XK_KP_Home
#define XK_KP_Home 0xFF95
#endif
#ifndef XK_KP_Left
#define XK_KP_Left 0xFF96
#endif
#ifndef XK_KP_Up
#define XK_KP_Up 0xFF97
#endif
#ifndef XK_KP_Right
#define XK_KP_Right 0xFF98
#endif
#ifndef XK_KP_Down
#define XK_KP_Down 0xFF99
#endif
#ifndef XK_KP_Prior
#define XK_KP_Prior 0xFF9A
#endif
#ifndef XK_KP_Next
#define XK_KP_Next 0xFF9B
#endif
#ifndef XK_KP_End
#define XK_KP_End 0xFF9C
#endif
#ifndef XK_KP_Insert
#define XK_KP_Insert 0xFF9E
#endif
#ifndef XK_KP_Delete
#define XK_KP_Delete 0xFF9F
#endif
// the next lines are taken on 10/2009 from X.org (X11/XF86keysym.h), defining some special
// multimedia keys. They are included here as not every system has them.
#define XF86XK_MonBrightnessUp 0x1008FF02
#define XF86XK_MonBrightnessDown 0x1008FF03
#define XF86XK_KbdLightOnOff 0x1008FF04
#define XF86XK_KbdBrightnessUp 0x1008FF05
#define XF86XK_KbdBrightnessDown 0x1008FF06
#define XF86XK_Standby 0x1008FF10
#define XF86XK_AudioLowerVolume 0x1008FF11
#define XF86XK_AudioMute 0x1008FF12
#define XF86XK_AudioRaiseVolume 0x1008FF13
#define XF86XK_AudioPlay 0x1008FF14
#define XF86XK_AudioStop 0x1008FF15
#define XF86XK_AudioPrev 0x1008FF16
#define XF86XK_AudioNext 0x1008FF17
#define XF86XK_HomePage 0x1008FF18
#define XF86XK_Mail 0x1008FF19
#define XF86XK_Start 0x1008FF1A
#define XF86XK_Search 0x1008FF1B
#define XF86XK_AudioRecord 0x1008FF1C
#define XF86XK_Calculator 0x1008FF1D
#define XF86XK_Memo 0x1008FF1E
#define XF86XK_ToDoList 0x1008FF1F
#define XF86XK_Calendar 0x1008FF20
#define XF86XK_PowerDown 0x1008FF21
#define XF86XK_ContrastAdjust 0x1008FF22
#define XF86XK_Back 0x1008FF26
#define XF86XK_Forward 0x1008FF27
#define XF86XK_Stop 0x1008FF28
#define XF86XK_Refresh 0x1008FF29
#define XF86XK_PowerOff 0x1008FF2A
#define XF86XK_WakeUp 0x1008FF2B
#define XF86XK_Eject 0x1008FF2C
#define XF86XK_ScreenSaver 0x1008FF2D
#define XF86XK_WWW 0x1008FF2E
#define XF86XK_Sleep 0x1008FF2F
#define XF86XK_Favorites 0x1008FF30
#define XF86XK_AudioPause 0x1008FF31
#define XF86XK_AudioMedia 0x1008FF32
#define XF86XK_MyComputer 0x1008FF33
#define XF86XK_LightBulb 0x1008FF35
#define XF86XK_Shop 0x1008FF36
#define XF86XK_History 0x1008FF37
#define XF86XK_OpenURL 0x1008FF38
#define XF86XK_AddFavorite 0x1008FF39
#define XF86XK_HotLinks 0x1008FF3A
#define XF86XK_BrightnessAdjust 0x1008FF3B
#define XF86XK_Finance 0x1008FF3C
#define XF86XK_Community 0x1008FF3D
#define XF86XK_AudioRewind 0x1008FF3E
#define XF86XK_BackForward 0x1008FF3F
#define XF86XK_Launch0 0x1008FF40
#define XF86XK_Launch1 0x1008FF41
#define XF86XK_Launch2 0x1008FF42
#define XF86XK_Launch3 0x1008FF43
#define XF86XK_Launch4 0x1008FF44
#define XF86XK_Launch5 0x1008FF45
#define XF86XK_Launch6 0x1008FF46
#define XF86XK_Launch7 0x1008FF47
#define XF86XK_Launch8 0x1008FF48
#define XF86XK_Launch9 0x1008FF49
#define XF86XK_LaunchA 0x1008FF4A
#define XF86XK_LaunchB 0x1008FF4B
#define XF86XK_LaunchC 0x1008FF4C
#define XF86XK_LaunchD 0x1008FF4D
#define XF86XK_LaunchE 0x1008FF4E
#define XF86XK_LaunchF 0x1008FF4F
#define XF86XK_ApplicationLeft 0x1008FF50
#define XF86XK_ApplicationRight 0x1008FF51
#define XF86XK_Book 0x1008FF52
#define XF86XK_CD 0x1008FF53
#define XF86XK_Calculater 0x1008FF54
#define XF86XK_Clear 0x1008FF55
#define XF86XK_ClearGrab 0x1008FE21
#define XF86XK_Close 0x1008FF56
#define XF86XK_Copy 0x1008FF57
#define XF86XK_Cut 0x1008FF58
#define XF86XK_Display 0x1008FF59
#define XF86XK_DOS 0x1008FF5A
#define XF86XK_Documents 0x1008FF5B
#define XF86XK_Excel 0x1008FF5C
#define XF86XK_Explorer 0x1008FF5D
#define XF86XK_Game 0x1008FF5E
#define XF86XK_Go 0x1008FF5F
#define XF86XK_iTouch 0x1008FF60
#define XF86XK_LogOff 0x1008FF61
#define XF86XK_Market 0x1008FF62
#define XF86XK_Meeting 0x1008FF63
#define XF86XK_MenuKB 0x1008FF65
#define XF86XK_MenuPB 0x1008FF66
#define XF86XK_MySites 0x1008FF67
#define XF86XK_New 0x1008FF68
#define XF86XK_News 0x1008FF69
#define XF86XK_OfficeHome 0x1008FF6A
#define XF86XK_Open 0x1008FF6B
#define XF86XK_Option 0x1008FF6C
#define XF86XK_Paste 0x1008FF6D
#define XF86XK_Phone 0x1008FF6E
#define XF86XK_Reply 0x1008FF72
#define XF86XK_Reload 0x1008FF73
#define XF86XK_RotateWindows 0x1008FF74
#define XF86XK_RotationPB 0x1008FF75
#define XF86XK_RotationKB 0x1008FF76
#define XF86XK_Save 0x1008FF77
#define XF86XK_Send 0x1008FF7B
#define XF86XK_Spell 0x1008FF7C
#define XF86XK_SplitScreen 0x1008FF7D
#define XF86XK_Support 0x1008FF7E
#define XF86XK_TaskPane 0x1008FF7F
#define XF86XK_Terminal 0x1008FF80
#define XF86XK_Tools 0x1008FF81
#define XF86XK_Travel 0x1008FF82
#define XF86XK_Video 0x1008FF87
#define XF86XK_Word 0x1008FF89
#define XF86XK_Xfer 0x1008FF8A
#define XF86XK_ZoomIn 0x1008FF8B
#define XF86XK_ZoomOut 0x1008FF8C
#define XF86XK_Away 0x1008FF8D
#define XF86XK_Messenger 0x1008FF8E
#define XF86XK_WebCam 0x1008FF8F
#define XF86XK_MailForward 0x1008FF90
#define XF86XK_Pictures 0x1008FF91
#define XF86XK_Music 0x1008FF92
#define XF86XK_Battery 0x1008FF93
#define XF86XK_Bluetooth 0x1008FF94
#define XF86XK_WLAN 0x1008FF95
#define XF86XK_UWB 0x1008FF96
#define XF86XK_AudioForward 0x1008FF97
#define XF86XK_AudioRepeat 0x1008FF98
#define XF86XK_AudioRandomPlay 0x1008FF99
#define XF86XK_Subtitle 0x1008FF9A
#define XF86XK_AudioCycleTrack 0x1008FF9B
#define XF86XK_Time 0x1008FF9F
#define XF86XK_Select 0x1008FFA0
#define XF86XK_View 0x1008FFA1
#define XF86XK_TopMenu 0x1008FFA2
#define XF86XK_Red 0x1008FFA3
#define XF86XK_Green 0x1008FFA4
#define XF86XK_Yellow 0x1008FFA5
#define XF86XK_Blue 0x1008FFA6
#define XF86XK_Suspend 0x1008FFA7
#define XF86XK_Hibernate 0x1008FFA8
#define XF86XK_TouchpadToggle 0x1008FFA9
#define XF86XK_TouchpadOn 0x1008FFB0
#define XF86XK_TouchpadOff 0x1008FFB1
#define XF86XK_AudioMicMute 0x1008FFB2
// end of XF86keysyms.h
// keyboard mapping table
static const unsigned int keyTable[] = {
// misc keys
XK_Escape,
Qt::Key_Escape,
XK_Tab,
Qt::Key_Tab,
XK_ISO_Left_Tab,
Qt::Key_Backtab,
XK_BackSpace,
Qt::Key_Backspace,
XK_Return,
Qt::Key_Return,
XK_Insert,
Qt::Key_Insert,
XK_Delete,
Qt::Key_Delete,
XK_Clear,
Qt::Key_Delete,
XK_Pause,
Qt::Key_Pause,
XK_Print,
Qt::Key_Print,
0x1005FF60,
Qt::Key_SysReq, // hardcoded Sun SysReq
0x1007ff00,
Qt::Key_SysReq, // hardcoded X386 SysReq
// cursor movement
XK_Home,
Qt::Key_Home,
XK_End,
Qt::Key_End,
XK_Left,
Qt::Key_Left,
XK_Up,
Qt::Key_Up,
XK_Right,
Qt::Key_Right,
XK_Down,
Qt::Key_Down,
XK_Prior,
Qt::Key_PageUp,
XK_Next,
Qt::Key_PageDown,
// modifiers
XK_Shift_L,
Qt::Key_Shift,
XK_Shift_R,
Qt::Key_Shift,
XK_Shift_Lock,
Qt::Key_Shift,
XK_Control_L,
Qt::Key_Control,
XK_Control_R,
Qt::Key_Control,
XK_Meta_L,
Qt::Key_Meta,
XK_Meta_R,
Qt::Key_Meta,
XK_Alt_L,
Qt::Key_Alt,
XK_Alt_R,
Qt::Key_Alt,
XK_Caps_Lock,
Qt::Key_CapsLock,
XK_Num_Lock,
Qt::Key_NumLock,
XK_Scroll_Lock,
Qt::Key_ScrollLock,
XK_Super_L,
Qt::Key_Super_L,
XK_Super_R,
Qt::Key_Super_R,
XK_Menu,
Qt::Key_Menu,
XK_Hyper_L,
Qt::Key_Hyper_L,
XK_Hyper_R,
Qt::Key_Hyper_R,
XK_Help,
Qt::Key_Help,
0x1000FF74,
Qt::Key_Backtab, // hardcoded HP backtab
0x1005FF10,
Qt::Key_F11, // hardcoded Sun F36 (labeled F11)
0x1005FF11,
Qt::Key_F12, // hardcoded Sun F37 (labeled F12)
// numeric and function keypad keys
XK_KP_Space,
Qt::Key_Space,
XK_KP_Tab,
Qt::Key_Tab,
XK_KP_Enter,
Qt::Key_Enter,
XK_KP_F1,
Qt::Key_F1,
XK_F2,
Qt::Key_F2,
XK_F3,
Qt::Key_F3,
XK_F4,
Qt::Key_F4,
XK_F5,
Qt::Key_F5,
XK_F6,
Qt::Key_F6,
XK_F7,
Qt::Key_F7,
XK_F8,
Qt::Key_F8,
XK_F9,
Qt::Key_F9,
XK_F10,
Qt::Key_F10,
XK_KP_Home,
Qt::Key_Home,
XK_KP_Left,
Qt::Key_Left,
XK_KP_Up,
Qt::Key_Up,
XK_KP_Right,
Qt::Key_Right,
XK_KP_Down,
Qt::Key_Down,
XK_KP_Prior,
Qt::Key_PageUp,
XK_KP_Next,
Qt::Key_PageDown,
XK_KP_End,
Qt::Key_End,
XK_KP_Begin,
Qt::Key_Clear,
XK_KP_Insert,
Qt::Key_Insert,
XK_KP_Delete,
Qt::Key_Delete,
XK_KP_Equal,
Qt::Key_Equal,
XK_KP_Multiply,
Qt::Key_Asterisk,
XK_KP_Add,
Qt::Key_Plus,
XK_KP_Separator,
Qt::Key_Comma,
XK_KP_Subtract,
Qt::Key_Minus,
XK_KP_Decimal,
Qt::Key_Period,
XK_KP_Divide,
Qt::Key_Slash,
// International input method support keys
// International & multi-key character composition
XK_ISO_Level3_Shift,
Qt::Key_AltGr,
XK_Multi_key,
Qt::Key_Multi_key,
XK_Codeinput,
Qt::Key_Codeinput,
XK_SingleCandidate,
Qt::Key_SingleCandidate,
XK_MultipleCandidate,
Qt::Key_MultipleCandidate,
XK_PreviousCandidate,
Qt::Key_PreviousCandidate,
// Misc Functions
XK_Mode_switch,
Qt::Key_Mode_switch,
XK_script_switch,
Qt::Key_Mode_switch,
// Japanese keyboard support
XK_Kanji,
Qt::Key_Kanji,
XK_Muhenkan,
Qt::Key_Muhenkan,
// XK_Henkan_Mode, Qt::Key_Henkan_Mode,
XK_Henkan_Mode,
Qt::Key_Henkan,
XK_Henkan,
Qt::Key_Henkan,
XK_Romaji,
Qt::Key_Romaji,
XK_Hiragana,
Qt::Key_Hiragana,
XK_Katakana,
Qt::Key_Katakana,
XK_Hiragana_Katakana,
Qt::Key_Hiragana_Katakana,
XK_Zenkaku,
Qt::Key_Zenkaku,
XK_Hankaku,
Qt::Key_Hankaku,
XK_Zenkaku_Hankaku,
Qt::Key_Zenkaku_Hankaku,
XK_Touroku,
Qt::Key_Touroku,
XK_Massyo,
Qt::Key_Massyo,
XK_Kana_Lock,
Qt::Key_Kana_Lock,
XK_Kana_Shift,
Qt::Key_Kana_Shift,
XK_Eisu_Shift,
Qt::Key_Eisu_Shift,
XK_Eisu_toggle,
Qt::Key_Eisu_toggle,
// XK_Kanji_Bangou, Qt::Key_Kanji_Bangou,
// XK_Zen_Koho, Qt::Key_Zen_Koho,
// XK_Mae_Koho, Qt::Key_Mae_Koho,
XK_Kanji_Bangou,
Qt::Key_Codeinput,
XK_Zen_Koho,
Qt::Key_MultipleCandidate,
XK_Mae_Koho,
Qt::Key_PreviousCandidate,
#ifdef XK_KOREAN
// Korean keyboard support
XK_Hangul,
Qt::Key_Hangul,
XK_Hangul_Start,
Qt::Key_Hangul_Start,
XK_Hangul_End,
Qt::Key_Hangul_End,
XK_Hangul_Hanja,
Qt::Key_Hangul_Hanja,
XK_Hangul_Jamo,
Qt::Key_Hangul_Jamo,
XK_Hangul_Romaja,
Qt::Key_Hangul_Romaja,
// XK_Hangul_Codeinput, Qt::Key_Hangul_Codeinput,
XK_Hangul_Codeinput,
Qt::Key_Codeinput,
XK_Hangul_Jeonja,
Qt::Key_Hangul_Jeonja,
XK_Hangul_Banja,
Qt::Key_Hangul_Banja,
XK_Hangul_PreHanja,
Qt::Key_Hangul_PreHanja,
XK_Hangul_PostHanja,
Qt::Key_Hangul_PostHanja,
// XK_Hangul_SingleCandidate,Qt::Key_Hangul_SingleCandidate,
// XK_Hangul_MultipleCandidate,Qt::Key_Hangul_MultipleCandidate,
// XK_Hangul_PreviousCandidate,Qt::Key_Hangul_PreviousCandidate,
XK_Hangul_SingleCandidate,
Qt::Key_SingleCandidate,
XK_Hangul_MultipleCandidate,
Qt::Key_MultipleCandidate,
XK_Hangul_PreviousCandidate,
Qt::Key_PreviousCandidate,
XK_Hangul_Special,
Qt::Key_Hangul_Special,
// XK_Hangul_switch, Qt::Key_Hangul_switch,
XK_Hangul_switch,
Qt::Key_Mode_switch,
#endif // XK_KOREAN
// dead keys
XK_dead_grave,
Qt::Key_Dead_Grave,
XK_dead_acute,
Qt::Key_Dead_Acute,
XK_dead_circumflex,
Qt::Key_Dead_Circumflex,
XK_dead_tilde,
Qt::Key_Dead_Tilde,
XK_dead_macron,
Qt::Key_Dead_Macron,
XK_dead_breve,
Qt::Key_Dead_Breve,
XK_dead_abovedot,
Qt::Key_Dead_Abovedot,
XK_dead_diaeresis,
Qt::Key_Dead_Diaeresis,
XK_dead_abovering,
Qt::Key_Dead_Abovering,
XK_dead_doubleacute,
Qt::Key_Dead_Doubleacute,
XK_dead_caron,
Qt::Key_Dead_Caron,
XK_dead_cedilla,
Qt::Key_Dead_Cedilla,
XK_dead_ogonek,
Qt::Key_Dead_Ogonek,
XK_dead_iota,
Qt::Key_Dead_Iota,
XK_dead_voiced_sound,
Qt::Key_Dead_Voiced_Sound,
XK_dead_semivoiced_sound,
Qt::Key_Dead_Semivoiced_Sound,
XK_dead_belowdot,
Qt::Key_Dead_Belowdot,
XK_dead_hook,
Qt::Key_Dead_Hook,
XK_dead_horn,
Qt::Key_Dead_Horn,
// Special keys from X.org - This include multimedia keys,
// wireless/bluetooth/uwb keys, special launcher keys, etc.
XF86XK_Back,
Qt::Key_Back,
XF86XK_Forward,
Qt::Key_Forward,
XF86XK_Stop,
Qt::Key_Stop,
XF86XK_Refresh,
Qt::Key_Refresh,
XF86XK_Favorites,
Qt::Key_Favorites,
XF86XK_AudioMedia,
Qt::Key_LaunchMedia,
XF86XK_OpenURL,
Qt::Key_OpenUrl,
XF86XK_HomePage,
Qt::Key_HomePage,
XF86XK_Search,
Qt::Key_Search,
XF86XK_AudioLowerVolume,
Qt::Key_VolumeDown,
XF86XK_AudioMute,
Qt::Key_VolumeMute,
XF86XK_AudioRaiseVolume,
Qt::Key_VolumeUp,
XF86XK_AudioPlay,
Qt::Key_MediaPlay,
XF86XK_AudioStop,
Qt::Key_MediaStop,
XF86XK_AudioPrev,
Qt::Key_MediaPrevious,
XF86XK_AudioNext,
Qt::Key_MediaNext,
XF86XK_AudioRecord,
Qt::Key_MediaRecord,
XF86XK_AudioPause,
Qt::Key_MediaPause,
XF86XK_Mail,
Qt::Key_LaunchMail,
XF86XK_MyComputer,
Qt::Key_Launch0, // ### Qt 6: remap properly
XF86XK_Calculator,
Qt::Key_Launch1,
XF86XK_Memo,
Qt::Key_Memo,
XF86XK_ToDoList,
Qt::Key_ToDoList,
XF86XK_Calendar,
Qt::Key_Calendar,
XF86XK_PowerDown,
Qt::Key_PowerDown,
XF86XK_ContrastAdjust,
Qt::Key_ContrastAdjust,
XF86XK_Standby,
Qt::Key_Standby,
XF86XK_MonBrightnessUp,
Qt::Key_MonBrightnessUp,
XF86XK_MonBrightnessDown,
Qt::Key_MonBrightnessDown,
XF86XK_KbdLightOnOff,
Qt::Key_KeyboardLightOnOff,
XF86XK_KbdBrightnessUp,
Qt::Key_KeyboardBrightnessUp,
XF86XK_KbdBrightnessDown,
Qt::Key_KeyboardBrightnessDown,
XF86XK_PowerOff,
Qt::Key_PowerOff,
XF86XK_WakeUp,
Qt::Key_WakeUp,
XF86XK_Eject,
Qt::Key_Eject,
XF86XK_ScreenSaver,
Qt::Key_ScreenSaver,
XF86XK_WWW,
Qt::Key_WWW,
XF86XK_Sleep,
Qt::Key_Sleep,
XF86XK_LightBulb,
Qt::Key_LightBulb,
XF86XK_Shop,
Qt::Key_Shop,
XF86XK_History,
Qt::Key_History,
XF86XK_AddFavorite,
Qt::Key_AddFavorite,
XF86XK_HotLinks,
Qt::Key_HotLinks,
XF86XK_BrightnessAdjust,
Qt::Key_BrightnessAdjust,
XF86XK_Finance,
Qt::Key_Finance,
XF86XK_Community,
Qt::Key_Community,
XF86XK_AudioRewind,
Qt::Key_AudioRewind,
XF86XK_BackForward,
Qt::Key_BackForward,
XF86XK_ApplicationLeft,
Qt::Key_ApplicationLeft,
XF86XK_ApplicationRight,
Qt::Key_ApplicationRight,
XF86XK_Book,
Qt::Key_Book,
XF86XK_CD,
Qt::Key_CD,
XF86XK_Calculater,
Qt::Key_Calculator,
XF86XK_Clear,
Qt::Key_Clear,
XF86XK_ClearGrab,
Qt::Key_ClearGrab,
XF86XK_Close,
Qt::Key_Close,
XF86XK_Copy,
Qt::Key_Copy,
XF86XK_Cut,
Qt::Key_Cut,
XF86XK_Display,
Qt::Key_Display,
XF86XK_DOS,
Qt::Key_DOS,
XF86XK_Documents,
Qt::Key_Documents,
XF86XK_Excel,
Qt::Key_Excel,
XF86XK_Explorer,
Qt::Key_Explorer,
XF86XK_Game,
Qt::Key_Game,
XF86XK_Go,
Qt::Key_Go,
XF86XK_iTouch,
Qt::Key_iTouch,
XF86XK_LogOff,
Qt::Key_LogOff,
XF86XK_Market,
Qt::Key_Market,
XF86XK_Meeting,
Qt::Key_Meeting,
XF86XK_MenuKB,
Qt::Key_MenuKB,
XF86XK_MenuPB,
Qt::Key_MenuPB,
XF86XK_MySites,
Qt::Key_MySites,
#if QT_VERSION >= 0x050400
XF86XK_New,
Qt::Key_New,
#endif
XF86XK_News,
Qt::Key_News,
XF86XK_OfficeHome,
Qt::Key_OfficeHome,
#if QT_VERSION >= 0x050400
XF86XK_Open,
Qt::Key_Open,
#endif
XF86XK_Option,
Qt::Key_Option,
XF86XK_Paste,
Qt::Key_Paste,
XF86XK_Phone,
Qt::Key_Phone,
XF86XK_Reply,
Qt::Key_Reply,
XF86XK_Reload,
Qt::Key_Reload,
XF86XK_RotateWindows,
Qt::Key_RotateWindows,
XF86XK_RotationPB,
Qt::Key_RotationPB,
XF86XK_RotationKB,
Qt::Key_RotationKB,
XF86XK_Save,
Qt::Key_Save,
XF86XK_Send,
Qt::Key_Send,
XF86XK_Spell,
Qt::Key_Spell,
XF86XK_SplitScreen,
Qt::Key_SplitScreen,
XF86XK_Support,
Qt::Key_Support,
XF86XK_TaskPane,
Qt::Key_TaskPane,
XF86XK_Terminal,
Qt::Key_Terminal,
XF86XK_Tools,
Qt::Key_Tools,
XF86XK_Travel,
Qt::Key_Travel,
XF86XK_Video,
Qt::Key_Video,
XF86XK_Word,
Qt::Key_Word,
XF86XK_Xfer,
Qt::Key_Xfer,
XF86XK_ZoomIn,
Qt::Key_ZoomIn,
XF86XK_ZoomOut,
Qt::Key_ZoomOut,
XF86XK_Away,
Qt::Key_Away,
XF86XK_Messenger,
Qt::Key_Messenger,
XF86XK_WebCam,
Qt::Key_WebCam,
XF86XK_MailForward,
Qt::Key_MailForward,
XF86XK_Pictures,
Qt::Key_Pictures,
XF86XK_Music,
Qt::Key_Music,
XF86XK_Battery,
Qt::Key_Battery,
XF86XK_Bluetooth,
Qt::Key_Bluetooth,
XF86XK_WLAN,
Qt::Key_WLAN,
XF86XK_UWB,
Qt::Key_UWB,
XF86XK_AudioForward,
Qt::Key_AudioForward,
XF86XK_AudioRepeat,
Qt::Key_AudioRepeat,
XF86XK_AudioRandomPlay,
Qt::Key_AudioRandomPlay,
XF86XK_Subtitle,
Qt::Key_Subtitle,
XF86XK_AudioCycleTrack,
Qt::Key_AudioCycleTrack,
XF86XK_Time,
Qt::Key_Time,
XF86XK_Select,
Qt::Key_Select,
XF86XK_View,
Qt::Key_View,
XF86XK_TopMenu,
Qt::Key_TopMenu,
#if QT_VERSION >= 0x050400
XF86XK_Red,
Qt::Key_Red,
XF86XK_Green,
Qt::Key_Green,
XF86XK_Yellow,
Qt::Key_Yellow,
XF86XK_Blue,
Qt::Key_Blue,
#endif
XF86XK_Bluetooth,
Qt::Key_Bluetooth,
XF86XK_Suspend,
Qt::Key_Suspend,
XF86XK_Hibernate,
Qt::Key_Hibernate,
#if QT_VERSION >= 0x050400
XF86XK_TouchpadToggle,
Qt::Key_TouchpadToggle,
XF86XK_TouchpadOn,
Qt::Key_TouchpadOn,
XF86XK_TouchpadOff,
Qt::Key_TouchpadOff,
XF86XK_AudioMicMute,
Qt::Key_MicMute,
#endif
XF86XK_Launch0,
Qt::Key_Launch2, // ### Qt 6: remap properly
XF86XK_Launch1,
Qt::Key_Launch3,
XF86XK_Launch2,
Qt::Key_Launch4,
XF86XK_Launch3,
Qt::Key_Launch5,
XF86XK_Launch4,
Qt::Key_Launch6,
XF86XK_Launch5,
Qt::Key_Launch7,
XF86XK_Launch6,
Qt::Key_Launch8,
XF86XK_Launch7,
Qt::Key_Launch9,
XF86XK_Launch8,
Qt::Key_LaunchA,
XF86XK_Launch9,
Qt::Key_LaunchB,
XF86XK_LaunchA,
Qt::Key_LaunchC,
XF86XK_LaunchB,
Qt::Key_LaunchD,
XF86XK_LaunchC,
Qt::Key_LaunchE,
XF86XK_LaunchD,
Qt::Key_LaunchF,
XF86XK_LaunchE,
Qt::Key_LaunchG,
XF86XK_LaunchF,
Qt::Key_LaunchH,
0,
0};

View File

@ -40,13 +40,10 @@ PluginAdapter::PluginAdapter(LRCInstance* instance,
QString baseUrl)
: QmlAdapterBase(instance, parent)
, pluginStoreListModel_(new PluginStoreListModel(instance, this))
, pluginVersionManager_(new PluginVersionManager(instance, baseUrl, this))
, pluginVersionManager_(new PluginVersionManager(instance, this))
, pluginListModel_(new PluginListModel(instance, this))
, lrcInstance_(instance)
, settingsManager_(settingsManager)
, tempPath_(QDir::tempPath())
, baseUrl_(baseUrl)
{
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, pluginStoreListModel_, "PluginStoreListModel");
QML_REGISTERSINGLETONTYPE_POBJECT(NS_MODELS, pluginListModel_, "PluginListModel")
@ -99,7 +96,7 @@ PluginAdapter::getPluginsFromStore()
const auto& language = settingsManager_->getLanguage();
header["Accept-Language"] = QByteArray(language.toStdString().c_str(), language.size());
pluginVersionManager_
->sendGetRequest(QUrl(baseUrl_
->sendGetRequest(QUrl(baseUrl()
+ "?arch=" + lrcInstance_->pluginModel().getPlatformInfo()["os"]),
header,
[this, errorHandler](const QByteArray& data) {
@ -127,7 +124,7 @@ PluginAdapter::getPluginDetails(const QString& pluginId)
const auto& language = settingsManager_->getLanguage();
header["Accept-Language"] = QByteArray(language.toStdString().c_str(), language.size());
pluginVersionManager_
->sendGetRequest(QUrl(baseUrl_ + "/details/" + pluginId
->sendGetRequest(QUrl(baseUrl() + "/details/" + pluginId
+ "?arch=" + lrcInstance_->pluginModel().getPlatformInfo()["os"]),
header,
[this](const QByteArray& data) {
@ -214,19 +211,19 @@ PluginAdapter::checkVersionStatus(const QString& pluginId)
QString
PluginAdapter::baseUrl() const
{
return baseUrl_;
return settingsManager_->getValue("PluginStoreEndpoint").toString();
}
QString
PluginAdapter::getIconUrl(const QString& pluginId) const
{
return baseUrl_ + "/icons/" + pluginId
return baseUrl() + "/icons/" + pluginId
+ "?arch=" + lrcInstance_->pluginModel().getPlatformInfo()["os"];
}
QString
PluginAdapter::getBackgroundImageUrl(const QString& pluginId) const
{
return baseUrl_ + "/backgrounds/" + pluginId
return baseUrl() + "/backgrounds/" + pluginId
+ "?arch=" + lrcInstance_->pluginModel().getPlatformInfo()["os"];
}

View File

@ -22,6 +22,7 @@
#include "pluginlistmodel.h"
#include "pluginhandlerlistmodel.h"
#include "pluginlistpreferencemodel.h"
#include "appsettingsmanager.h"
#include "pluginversionmanager.h"
#include "pluginstorelistmodel.h"
#include "preferenceitemlistmodel.h"
@ -78,8 +79,7 @@ private:
std::unique_ptr<PluginHandlerListModel> pluginHandlerListModel_;
LRCInstance* lrcInstance_;
std::mutex mtx_;
QString tempPath_;
QString baseUrl_;
AppSettingsManager* settingsManager_;
std::mutex mtx_;
QString baseUrl_;
};

View File

@ -80,6 +80,8 @@ PluginListModel::data(const QModelIndex& index, int role) const
return QVariant(pluginStatus_.value(installedPlugins_.at(index.row())));
case Role::NewPluginAvailable:
return QVariant(newVersionAvailable_.value(installedPlugins_.at(index.row())));
case Role::Id:
return QVariant(details.id);
}
return QVariant();
}
@ -98,6 +100,7 @@ PluginListModel::roleNames() const
roles[Status] = "Status";
roles[PluginDescription] = "PluginDescription";
roles[NewPluginAvailable] = "NewPluginAvailable";
roles[Id] = "Id";
return roles;
}

View File

@ -38,7 +38,8 @@ public:
PluginIcon,
NewPluginAvailable,
IsLoaded,
Status
Status,
Id
};
Q_ENUM(Role)

View File

@ -79,7 +79,6 @@ void
PluginStoreListModel::reset()
{
beginResetModel();
plugins_.clear();
endResetModel();
}
@ -88,8 +87,8 @@ PluginStoreListModel::addPlugin(const QVariantMap& plugin)
{
beginInsertRows(QModelIndex(), plugins_.size(), plugins_.size());
plugins_.append(plugin);
endInsertRows();
sort();
endInsertRows();
}
void
@ -97,8 +96,8 @@ PluginStoreListModel::setPlugins(const QList<QVariantMap>& plugins)
{
beginResetModel();
plugins_ = filterPlugins(plugins);
endResetModel();
sort();
endResetModel();
}
void
@ -109,12 +108,12 @@ PluginStoreListModel::removePlugin(const QString& pluginId)
if (plugin["id"].toString() == pluginId) {
beginRemoveRows(QModelIndex(), index, index);
plugins_.removeAt(index);
sort();
endRemoveRows();
return;
}
index++;
}
sort();
}
void
@ -129,7 +128,6 @@ PluginStoreListModel::updatePlugin(const QVariantMap& plugin)
}
index++;
}
sort();
}
QColor
@ -221,11 +219,9 @@ PluginStoreListModel::rowFromPluginId(const QString& pluginId) const
void
PluginStoreListModel::sort()
{
beginResetModel();
std::sort(plugins_.begin(), plugins_.end(), [](const QVariantMap& a, const QVariantMap& b) {
return a["timestamp"].toString() < b["timestamp"].toString();
});
endResetModel();
}
QList<QVariantMap>

View File

@ -33,9 +33,8 @@ public:
Impl(LRCInstance* instance, PluginVersionManager& parent)
: QObject(nullptr)
, parent_(parent)
, appSettingsManager_(new AppSettingsManager(this))
, settingsManager_(new AppSettingsManager(this))
, lrcInstance_(instance)
, tempPath_(QDir::tempPath())
, updateTimer_(new QTimer(this))
{
connect(updateTimer_, &QTimer::timeout, this, [this] { checkForUpdates(); });
@ -78,12 +77,12 @@ public:
bool isAutoUpdaterEnabled()
{
return appSettingsManager_->getValue(Settings::Key::PluginAutoUpdate).toBool();
return settingsManager_->getValue(Settings::Key::PluginAutoUpdate).toBool();
}
void setAutoUpdate(bool state)
{
appSettingsManager_->setValue(Settings::Key::PluginAutoUpdate, state);
settingsManager_->setValue(Settings::Key::PluginAutoUpdate, state);
}
void checkVersionStatus(const QString& pluginId)
@ -103,13 +102,14 @@ public:
return;
}
parent_.sendGetRequest(QUrl(parent_.baseUrl + "/versions/" + plugin.id + "?arch="
parent_.sendGetRequest(QUrl(settingsManager_->getValue("PluginStoreEndpoint").toString()
+ "/versions/" + plugin.id + "?arch="
+ lrcInstance_->pluginModel().getPlatformInfo()["os"]),
[this, plugin](const QByteArray& data) {
// `data` represents the version in this case.
if (plugin.version < data) {
if (isAutoUpdaterEnabled()) {
installRemotePlugin(plugin.name);
installRemotePlugin(plugin.id);
return;
}
}
@ -121,7 +121,7 @@ public:
void installRemotePlugin(const QString& pluginId)
{
parent_.downloadFile(
QUrl(parent_.baseUrl + "/download/"
QUrl(settingsManager_->getValue("PluginStoreEndpoint").toString() + "/download/"
+ lrcInstance_->pluginModel().getPlatformInfo()["os"] + "/" + pluginId),
pluginId,
0,
@ -132,9 +132,9 @@ public:
return;
}
QThreadPool::globalInstance()->start([this, pluginId] {
auto res = lrcInstance_->pluginModel().installPlugin(QDir(tempPath_).filePath(
pluginId + ".jpl"),
true);
auto res = lrcInstance_->pluginModel()
.installPlugin(QDir(QDir::tempPath()).filePath(pluginId + ".jpl"),
true);
if (res) {
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLED);
} else {
@ -143,7 +143,7 @@ public:
});
parent_.versionStatusChanged(pluginId, PluginStatus::Role::INSTALLING);
},
tempPath_ + '/');
QDir::tempPath());
Q_EMIT parent_.versionStatusChanged(pluginId, PluginStatus::Role::DOWNLOADING);
}
@ -158,15 +158,13 @@ public:
};
PluginVersionManager& parent_;
AppSettingsManager* appSettingsManager_ {nullptr};
AppSettingsManager* settingsManager_ {nullptr};
LRCInstance* lrcInstance_ {nullptr};
QString tempPath_;
QTimer* updateTimer_;
};
PluginVersionManager::PluginVersionManager(LRCInstance* instance, QString& baseUrl, QObject* parent)
PluginVersionManager::PluginVersionManager(LRCInstance* instance, QObject* parent)
: NetworkManager(&instance->connectivityMonitor(), parent)
, baseUrl(baseUrl)
, pimpl_(std::make_unique<Impl>(instance, *this))
{}

View File

@ -46,9 +46,7 @@ class PluginVersionManager final : public NetworkManager
{
Q_OBJECT
public:
explicit PluginVersionManager(LRCInstance* instance,
QString& baseUrl,
QObject* parent = nullptr);
explicit PluginVersionManager(LRCInstance* instance, QObject* parent = nullptr);
~PluginVersionManager();
Q_INVOKABLE bool isAutoUpdaterEnabled();

52
src/app/pttlistener.h Normal file
View File

@ -0,0 +1,52 @@
#pragma once
#include "systemtray.h"
#include "appsettingsmanager.h"
#include <QObject>
#include <QThread>
#include <QKeyEvent>
class PTTListener : public QObject
{
Q_OBJECT
public:
Q_INVOKABLE Qt::Key getCurrentKey()
{
int keyInt = settingsManager_->getValue(Settings::Key::pttKey).toInt();
Qt::Key key = static_cast<Qt::Key>(keyInt);
return key;
}
Q_INVOKABLE QString keyToString(Qt::Key key)
{
return QKeySequence(key).toString();
}
Q_INVOKABLE void setPttKey(Qt::Key key)
{
settingsManager_->setValue(Settings::Key::pttKey, key);
}
Q_INVOKABLE bool getPttState()
{
return settingsManager_->getValue(Settings::Key::EnablePtt).toBool();
}
PTTListener(AppSettingsManager* settingsManager, QObject* parent = nullptr);
~PTTListener();
Q_SIGNALS:
void pttKeyPressed();
void pttKeyReleased();
#ifdef HAVE_GLOBAL_PTT
public Q_SLOTS:
void startListening();
void stopListening();
#endif
private:
class Impl;
std::unique_ptr<Impl> pimpl_;
AppSettingsManager* settingsManager_;
};

View File

@ -33,7 +33,7 @@ public:
instance)
{}
enum class QrType { Account, Contact };
enum class QrType { Account, Contact, Raw };
/*
* Id should be string like account_0 (account index),
@ -64,6 +64,8 @@ public:
} catch (...) {
}
return {QrType::Contact, {}};
} else if (list.contains("raw") && list.size() > 1) {
return {QrType::Raw, list[1]};
}
return {QrType::Account, {}};
}
@ -73,26 +75,24 @@ public:
Q_UNUSED(size);
QString uri;
auto indexPair = getIndexFromID(id);
auto [type, identifier] = getIndexFromID(id);
if (indexPair.first == QrType::Contact) {
uri = indexPair.second;
} else {
if (indexPair.second.isEmpty())
if (type == QrType::Account) {
if (identifier.isEmpty())
return QImage();
auto accountId = indexPair.second;
try {
auto& accountInfo = lrcInstance_->getAccountInfo(accountId);
auto& accountInfo = lrcInstance_->getAccountInfo(identifier);
uri = accountInfo.profileInfo.uri;
} catch (const std::out_of_range&) {
qWarning() << "Couldn't get account info for id:" << accountId;
qWarning() << "Couldn't get account info for id:" << identifier;
return QImage();
}
}
} else
uri = identifier;
if (!requestedSize.isEmpty())
return Utils::setupQRCode(uri, 0).scaled(requestedSize, Qt::KeepAspectRatio);
return Utils::getQRCodeImage(uri, 0).scaled(requestedSize, Qt::KeepAspectRatio);
else
return Utils::setupQRCode(uri, 0);
return Utils::getQRCodeImage(uri, 0);
}
};

View File

@ -70,10 +70,10 @@ SidePanelBase {
"title": JamiStrings.appearance
}, {
"id": 7,
"title": JamiStrings.locationSharingLabel
"title": JamiStrings.chatSettingsTitle
}, {
"id": 8,
"title": JamiStrings.fileTransfer
"title": JamiStrings.locationSharingLabel
}, {
"id": 9,
"title": JamiStrings.callRecording

View File

@ -42,8 +42,8 @@ ListSelectionView {
"AdvancedSettingsPage": Qt.resolvedUrl("components/AdvancedSettingsPage.qml"),
"SystemSettingsPage": Qt.resolvedUrl("components/SystemSettingsPage.qml"),
"AppearanceSettingsPage": Qt.resolvedUrl("components/AppearanceSettingsPage.qml"),
"Chat": Qt.resolvedUrl("components/ChatSettingsPage.qml"),
"LocationSharingSettingsPage": Qt.resolvedUrl("components/LocationSharingSettingsPage.qml"),
"FileTransferSettingsPage": Qt.resolvedUrl("components/FileTransferSettingsPage.qml"),
"CallRecordingSettingsPage": Qt.resolvedUrl("components/CallRecordingSettingsPage.qml"),
"TroubleshootSettingsPage": Qt.resolvedUrl("components/TroubleshootSettingsPage.qml"),
"UpdateSettingsPage": Qt.resolvedUrl("components/UpdateSettingsPage.qml"),
@ -119,10 +119,10 @@ ListSelectionView {
replace(currentItem, viewNode.resources["AppearanceSettingsPage"], StackView.Immediate);
break;
case 7:
replace(currentItem, viewNode.resources["LocationSharingSettingsPage"], StackView.Immediate);
replace(currentItem, viewNode.resources["Chat"], StackView.Immediate);
break;
case 8:
replace(currentItem, viewNode.resources["FileTransferSettingsPage"], StackView.Immediate);
replace(currentItem, viewNode.resources["LocationSharingSettingsPage"], StackView.Immediate);
break;
case 9:
replace(currentItem, viewNode.resources["CallRecordingSettingsPage"], StackView.Immediate);

View File

@ -42,60 +42,6 @@ SettingsPageBase {
anchors.left: parent.left
anchors.leftMargin: JamiTheme.preferredSettingsMarginSize
ColumnLayout {
id: generalSettings
width: parent.width
spacing: JamiTheme.settingsCategorySpacing
Text {
id: enableAccountTitle
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.generalSettingsTitle
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
}
ToggleSwitch {
id: enableTypingIndicatorCheckbox
Layout.fillWidth: true
checked: UtilsAdapter.getAppValue(Settings.EnableTypingIndicator)
labelText: JamiStrings.enableTypingIndicator
descText: JamiStrings.enableTypingIndicatorDescription
tooltipText: JamiStrings.enableTypingIndicator
onSwitchToggled: UtilsAdapter.setAppValue(Settings.Key.EnableTypingIndicator, checked)
}
ToggleSwitch {
id: displayImagesCheckbox
visible: WITH_WEBENGINE
Layout.fillWidth: true
checked: UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews)
labelText: JamiStrings.displayHyperlinkPreviews
descText: JamiStrings.displayHyperlinkPreviewsDescription
tooltipText: JamiStrings.displayHyperlinkPreviews
onSwitchToggled: {
UtilsAdapter.setAppValue(Settings.Key.DisplayHyperlinkPreviews, checked);
}
}
}
ColumnLayout {
id: themeSettings
@ -308,11 +254,7 @@ SettingsPageBase {
preferredWidth: defaultSettingsTextSize.width + 2 * JamiTheme.buttontextWizzardPadding
onClicked: {
enableTypingIndicatorCheckbox.checked = UtilsAdapter.getDefault(Settings.Key.EnableTypingIndicator);
displayImagesCheckbox.checked = UtilsAdapter.getDefault(Settings.Key.DisplayHyperlinkPreviews);
zoomSpinBox.value = Math.round(UtilsAdapter.getDefault(Settings.BaseZoom) * 100.0);
UtilsAdapter.setToDefault(Settings.Key.EnableTypingIndicator);
UtilsAdapter.setToDefault(Settings.Key.DisplayHyperlinkPreviews);
UtilsAdapter.setToDefault(Settings.Key.AppTheme);
UtilsAdapter.setToDefault(Settings.Key.BaseZoom);
themeSettings.isComplete();

View File

@ -28,11 +28,13 @@ import "../../commoncomponents"
import "../../mainview/components"
import "../../mainview/js/contactpickercreation.js" as ContactPickerCreation
SettingsPageBase {
id: root
property bool isSIP: CurrentAccount.type === Profile.Type.SIP
property int itemWidth: 132
property string key: pttListener.keyToString(pttListener.getCurrentKey())
title: JamiStrings.callSettingsTitle
function updateAndShowModeratorsSlot() {
@ -374,5 +376,72 @@ SettingsPageBase {
}
}
}
ColumnLayout{
width: parent.width
spacing: 9
Text {
text: JamiStrings.pushToTalk
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
}
ToggleSwitch {
id: pttToggle
labelText: JamiStrings.enablePTT
checked: UtilsAdapter.getAppValue(Settings.EnablePtt)
onSwitchToggled: {
UtilsAdapter.setAppValue(Settings.Key.EnablePtt, checked)
}
}
RowLayout {
visible: pttToggle.checked
Layout.preferredWidth: parent.width
Label {
color: JamiTheme.textColor
wrapMode: Text.WordWrap
text: JamiStrings.keyboardShortcut
font.pointSize: JamiTheme.settingsFontSize
font.kerning: true
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
Label {
id: keyLabel
color: JamiTheme.blackColor
wrapMode: Text.WordWrap
text: key
font.pointSize: JamiTheme.settingsFontSize
font.kerning: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
background: Rectangle {
id: backgroundRect
anchors.centerIn: parent
width: keyLabel.width + 2 * JamiTheme.preferredMarginSize
height: keyLabel.height + JamiTheme.preferredMarginSize
color: JamiTheme.lightGrey_
border.color: JamiTheme.darkGreyColor
radius: 4
}
}
MaterialButton {
Layout.alignment: Qt.AlignRight
buttontextHeightMargin: JamiTheme.buttontextHeightMargin
primary: true
toolTipText: JamiStrings.changeKeyboardShortcut
text: JamiStrings.change
onClicked: {
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/ChangePttKeyPopup.qml");
dlg.choiceMade.connect(function (chosenKey) {
keyLabel.text = pttListener.keyToString(chosenKey);
});
}
}
}
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (C) 2023 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 Qt5Compat.GraphicalEffects
import QtQuick.Layouts
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
Popup {
id: popup
width: textComponent.contentWidth + 40 < popup.maxWidth - 20 ? textComponent.contentWidth + 40 : popup.maxWidth - 20
height: textComponent.contentHeight + 40 < 350 ? textComponent.contentHeight + 40 : 350
property string text: ""
property int maxWidth: 0
x: -1 * (popup.width - 20)
Rectangle {
anchors.fill: parent
color: JamiTheme.transparentColor
Flickable {
anchors.fill: parent
contentHeight: textComponent.contentHeight + 10
contentWidth: textComponent.contentWidth + 20
clip: true
ScrollBar.vertical: ScrollBar {
active: contentHeight > height
}
ScrollBar.horizontal: ScrollBar {
active: contentWidth > width
}
contentX: 10
contentY: 10
Text {
id: textComponent
width: popup.maxWidth - 20
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
text: popup.text
}
}
}
}

View File

@ -0,0 +1,273 @@
/*
* Copyright (C) 2023 Savoir-faire Linux Inc.
* Author: Fadi Shehadeh <fadi.shehadeh@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Enums 1.1
import net.jami.Constants 1.1
import net.jami.Helpers 1.1
import "../../commoncomponents"
import "../../mainview/components"
import "../../mainview/js/contactpickercreation.js" as ContactPickerCreation
SettingsPageBase {
id: root
property int itemWidth: 188
title: JamiStrings.chatSettingsTitle
flickableContent: ColumnLayout {
id: callSettingsColumnLayout
anchors.topMargin: 10
width: contentFlickableWidth
spacing: 2 * JamiTheme.settingsCategorySpacing
anchors.left: parent.left
anchors.leftMargin: JamiTheme.preferredSettingsMarginSize
ColumnLayout {
id: generalSettings
width: parent.width
spacing: JamiTheme.settingsCategorySpacing
Text {
id: enableAccountTitle
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.view
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
}
ToggleSwitch {
id: enableTypingIndicatorCheckbox
Layout.fillWidth: true
checked: UtilsAdapter.getAppValue(Settings.EnableTypingIndicator)
labelText: JamiStrings.enableTypingIndicator
descText: JamiStrings.enableTypingIndicatorDescription
tooltipText: JamiStrings.enableTypingIndicator
onSwitchToggled: UtilsAdapter.setAppValue(Settings.Key.EnableTypingIndicator, checked)
}
ToggleSwitch {
id: displayImagesCheckbox
visible: WITH_WEBENGINE
Layout.fillWidth: true
checked: UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews)
labelText: JamiStrings.displayHyperlinkPreviews
descText: JamiStrings.displayHyperlinkPreviewsDescription
tooltipText: JamiStrings.displayHyperlinkPreviews
onSwitchToggled: {
UtilsAdapter.setAppValue(Settings.Key.DisplayHyperlinkPreviews, checked);
}
}
}
ColumnLayout {
id: textFormattingSettings
width: parent.width
spacing: JamiTheme.settingsCategorySpacing
Text {
id: textFormattingTitle
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.textFormatting
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
}
Text {
id: textFormattingDescription
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.textFormattingDescription
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
}
Flow {
Layout.preferredWidth: parent.width
Layout.preferredHeight: childrenRect.height
spacing: 10
ButtonGroup {
id: optionsB
}
MaterialRadioButton {
id: enterButton
width: 130
height: 40
backgroundColor: JamiTheme.chatSettingButtonBackgroundColor
textColor: JamiTheme.chatSettingButtonTextColor
checkedColor: JamiTheme.chatSettingButtonBorderColor
borderColor: JamiTheme.chatSettingButtonBorderColor
text: JamiStrings.enter
ButtonGroup.group: optionsB
onCheckedChanged: {
if (checked)
UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, true);
}
}
MaterialRadioButton {
id: shiftEnterButton
width: 210
height: 40
backgroundColor: JamiTheme.chatSettingButtonBackgroundColor
textColor: JamiTheme.chatSettingButtonTextColor
checkedColor: JamiTheme.chatSettingButtonBorderColor
borderColor: JamiTheme.chatSettingButtonBorderColor
text: JamiStrings.shiftEnter
ButtonGroup.group: optionsB
onCheckedChanged: {
if (checked)
UtilsAdapter.setAppValue(Settings.Key.ChatViewEnterIsNewLine, false);
}
}
Component.onCompleted: {
if (UtilsAdapter.getAppValue(Settings.Key.ChatViewEnterIsNewLine))
enterButton.checked = true;
else
shiftEnterButton.checked = true;
}
}
}
ColumnLayout {
id: fileTransferSettings
width: parent.width
spacing: JamiTheme.settingsCategorySpacing
Text {
id: fileTransferTitle
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.fileTransfer
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
}
ToggleSwitch {
id: autoAcceptFilesCheckbox
Layout.fillWidth: true
checked: CurrentAccount.autoTransferFromTrusted
labelText: JamiStrings.autoAcceptFiles
tooltipText: JamiStrings.autoAcceptFiles
onSwitchToggled: CurrentAccount.autoTransferFromTrusted = checked
}
SettingSpinBox {
id: acceptTransferBelowSpinBox
Layout.fillWidth: true
title: JamiStrings.acceptTransferBelow
tooltipText: JamiStrings.acceptTransferTooltip
itemWidth: root.itemWidth
bottomValue: 0
valueField: CurrentAccount.autoTransferSizeThreshold
onNewValue: CurrentAccount.autoTransferSizeThreshold = valueField
}
}
MaterialButton {
id: defaultSettings
Layout.topMargin: 20
TextMetrics {
id: defaultSettingsTextSize
font.weight: Font.Bold
font.pixelSize: JamiTheme.wizardViewButtonFontPixelSize
font.capitalization: Font.AllUppercase
text: defaultSettings.text
}
secondary: true
text: JamiStrings.defaultSettings
preferredWidth: defaultSettingsTextSize.width + 2 * JamiTheme.buttontextWizzardPadding
onClicked: {
autoAcceptFilesCheckbox.checked = UtilsAdapter.getDefault(Settings.Key.AutoAcceptFiles);
acceptTransferBelowSpinBox.valueField = UtilsAdapter.getDefault(Settings.Key.AcceptTransferBelow);
UtilsAdapter.setToDefault(Settings.Key.AutoAcceptFiles);
UtilsAdapter.setToDefault(Settings.Key.AcceptTransferBelow);
UtilsAdapter.setToDefault(Settings.Key.EnableTypingIndicator);
UtilsAdapter.setToDefault(Settings.Key.ChatViewEnterIsNewLine);
UtilsAdapter.setToDefault(Settings.Key.DisplayHyperlinkPreviews);
enableTypingIndicatorCheckbox.checked = UtilsAdapter.getAppValue(Settings.EnableTypingIndicator);
displayImagesCheckbox.checked = UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews);
if (UtilsAdapter.getAppValue(Settings.Key.ChatViewEnterIsNewLine))
enterButton.checked = true;
else
shiftEnterButton.checked = true;
}
}
}
}

View File

@ -0,0 +1,381 @@
/*
* Copyright (C) 2023 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 net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "../../commoncomponents"
import "../js/logviewwindowcreation.js" as LogViewWindowCreation
ListView {
id: listview
height: contentItem.childrenRect.height
anchors.top: parent.top
anchors.topMargin: 10
spacing: 5
cacheBuffer: 10
property int rota: 0
header: Rectangle {
height: 55
width: connectionMonitoringTable.width
Rectangle {
color: JamiTheme.connectionMonitoringHeaderColor
anchors.top: parent.top
height: 50
width: connectionMonitoringTable.width
RowLayout {
anchors.fill: parent
Rectangle {
id: profile
height: 50
Layout.leftMargin: 5
Layout.preferredWidth: 210
color: JamiTheme.transparentColor
Text {
id: textImage
anchors.leftMargin: 10
anchors.verticalCenter: parent.verticalCenter
text: JamiStrings.contact
}
}
Rectangle {
id: device
Layout.fillWidth: true
height: 50
color: JamiTheme.transparentColor
Text {
id: deviceText
anchors.verticalCenter: parent.verticalCenter
text: JamiStrings.device
}
}
Rectangle {
id: connection
width: 130
height: 50
radius: 5
color: JamiTheme.transparentColor
Text {
id: connectionText
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
text: JamiStrings.connection
}
}
Rectangle {
id: channel
height: 50
width: 70
color: JamiTheme.transparentColor
Text {
anchors.verticalCenter: parent.verticalCenter
text: JamiStrings.channels
}
}
}
}
}
model: ConnectionInfoListModel
Timer {
interval: 1000
running: root.visible
repeat: true
onTriggered: {
ContactAdapter.updateConnectionInfo();
listview.rota = listview.rota + 5;
}
}
delegate: Rectangle {
id: delegate
height: Count == 0 ? 0 : 10 + 40 * Count
width: connectionMonitoringTable.width
color: index % 2 === 0 ? JamiTheme.connectionMonitoringTableColor1 : JamiTheme.connectionMonitoringTableColor2
ListView {
id: listView2
height: 40 * Count
anchors.top: delegate.top
spacing: 0
model: Count
delegate: RowLayout {
id: rowLayoutDelegate
height: 40
width: connectionMonitoringTable.width
Rectangle {
id: profile
height: 50
Layout.leftMargin: 5
Layout.preferredWidth: 210
color: JamiTheme.transparentColor
Avatar {
id: avatar
visible: index == 0
anchors.left: parent.left
height: 40
width: 40
anchors.verticalCenter: parent.verticalCenter
imageId: PeerId
mode: Avatar.Mode.Contact
}
Rectangle {
id: usernameRect
anchors.left: avatar.right
anchors.verticalCenter: parent.verticalCenter
width: profile.width - 50
height: 40
color: JamiTheme.transparentColor
Rectangle {
id: usernameRect2
visible: index == 0
width: profile.width - 50
height: 20
anchors.leftMargin: 10
anchors.top: parent.top
anchors.left: parent.left
color: JamiTheme.transparentColor
Text {
id: usernameText
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, PeerId)
elide: Text.ElideRight
}
}
Rectangle {
width: profile.width - 50
height: 20
anchors.leftMargin: 10
anchors.top: usernameRect2.bottom
anchors.left: parent.left
visible: usernameRect2.visible && (UtilsAdapter.getBestIdForUri(CurrentAccount.id, PeerId) != UtilsAdapter.getBestNameForUri(CurrentAccount.id, PeerId))
color: JamiTheme.transparentColor
Text {
id: idText
anchors.fill: parent
text: UtilsAdapter.getBestIdForUri(CurrentAccount.id, PeerId)
font.pixelSize: 12
font.underline: usernameText.font.underline
elide: Text.ElideRight
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
usernameText.font.underline = true;
tooltipContact.text = JamiStrings.copyAllData;
}
onExited: {
usernameText.font.underline = false;
tooltipContact.text = JamiStrings.copyAllData;
}
ToolTip {
id: tooltipContact
visible: usernameText.font.underline
text: JamiStrings.copyAllData
}
onClicked: {
tooltipContact.text = JamiStrings.logsViewCopied;
UtilsAdapter.setClipboardText(ConnectionDatas);
}
}
}
}
Rectangle {
height: 40
Layout.fillWidth: true
color: delegate.color
Text {
id: delegateDeviceText
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
text: {
if (DeviceId[index] != undefined) {
return DeviceId[index];
} else {
return "";
}
}
elide: Text.ElideMiddle
width: parent.width - 10
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
delegateDeviceText.font.underline = true;
}
onExited: {
delegateDeviceText.font.underline = false;
tooltipDevice.text = delegateDeviceText.text;
}
ToolTip {
id: tooltipDevice
visible: delegateDeviceText.font.underline
text: delegateDeviceText.text
}
onClicked: {
tooltipDevice.text = delegateDeviceText.text + " (" + JamiStrings.logsViewCopied + ")";
UtilsAdapter.setClipboardText(delegateDeviceText.text);
}
}
}
}
Rectangle {
id: connectionRectangle
color: delegate.color
height: 40
Layout.preferredWidth: 130
property var status: Status[index]
ResponsiveImage {
id: connectionImage
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
rotation: connectionRectangle.status == 0 ? 0 : listview.rota
source: {
if (connectionRectangle.status == 0) {
return JamiResources.connected_black_24dp_svg;
} else {
return JamiResources.connecting_black_24dp_svg;
}
}
color: {
if (connectionRectangle.status == 0) {
return "#009c7f";
} else {
if (connectionRectangle.status == 4) {
return "red";
} else {
return "#ff8100";
}
}
}
}
Text {
id: connectionText
anchors.left: connectionImage.right
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 5
text: if (connectionRectangle.status == 0) {
return JamiStrings.connected;
} else {
if (connectionRectangle.status == 1) {
return JamiStrings.connectingTLS;
} else {
if (connectionRectangle.status == 2) {
return JamiStrings.connectingICE;
} else {
if (connectionRectangle.status == 3) {
return JamiStrings.connecting;
} else {
return JamiStrings.waiting;
}
}
}
}
color: connectionImage.color
property var tooltipText: JamiStrings.remote + RemoteAddress[index]
MouseArea {
anchors.fill: parent
hoverEnabled: true
onEntered: {
connectionText.font.underline = true;
}
onExited: {
connectionText.font.underline = false;
}
ToolTip {
visible: connectionText.font.underline
text: connectionText.tooltipText
}
}
}
}
Rectangle {
id: channelDelegateRectangle
height: 40
Layout.preferredWidth: 70
color: delegate.color
Text {
id: channelText
anchors.verticalCenter: parent.verticalCenter
anchors.leftMargin: 10
anchors.left: parent.left
text: {
if (Channels[index] != undefined) {
return Channels[index];
} else {
return "";
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
onExited: {
channelText.font.underline = false;
}
onEntered: {
channelText.font.underline = true;
}
onClicked: {
var output = "";
var channelMap = ChannelsMap[index];
for (var key in channelMap) {
var value = channelMap[key];
var keyHexa = parseInt(key, 16).toString();
output += keyHexa + " : " + value + "\n";
}
viewCoordinator.presentDialog(parent, "settingsview/components/ChannelsPopup.qml", {
"text": output,
"maxWidth": connectionMonitoringTable.width
});
}
}
}
}
}
}
}
}

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