Compare commits

...

70 Commits

Author SHA1 Message Date
c6f79f4132 misc: bump daemon
Change-Id: I1dc5b074a171311610fd884b6f9e2a26ad8a6395
2024-10-23 16:40:02 -04:00
6b9cb684ec call_notifications: fix editable state of call notifications
Text message notificaitons sent regarding the status of a call
(i.e. busy, call lasted xx:yy mins, etc) were editable due to being
a TextEdit and not a Text

Change-Id: I9ded20a9b4dbdbaee034b0de6ae42e1eca2c02a0
2024-10-23 09:53:55 -04:00
1d0fa772e2 UI : fix bi-colour message telling there was a call
setting message opacity to 1 to only have the messageInBgColor

Gitlab: #1799

Change-Id: I37d0a354412ec8f2e7127203a2d0adf185674cea
2024-10-23 09:52:38 -04:00
51c716d718 misc: bump daemon
Change-Id: I6fad7b305754f86b602a204977de1d8ed0add0ad
2024-10-22 16:00:39 -04:00
5e4556f786 snap: fix build error
GitLab: #1862
Change-Id: If7f13cc16c02d823dd98af84007b24a829579262
2024-10-22 13:35:30 -04:00
da667056fd About: fix binding loop
"anchors.centerIn: parent" caused a binding loop
with parent implicitHeight using contentHeight in Control.qml
Removing "anchors.centerIn: parent" fixed the warning while the
popup remains in the center of the page

Gitlab: #1508

Change-Id: I0d05597100e4c2b306180e83a7b88b6d5ee22f40
2024-10-22 12:10:22 -04:00
9d00c4f4e3 chatview: default view to chat instead of side-panel
When the application window or screen is too small and
the user opens the details side-panel, it will display
over the chat. This change makes it so that switching
conversation's defaults the view back to the chat and not
to the side-panel.

Change-Id: I3cffba24a7d23d7635937329c2078979722031c4
2024-10-22 11:35:11 -04:00
f5743da2d6 username: fix multiple usernames associated to one account
Added logic check to prevent disabled accounts from registering
multiple usernames after being restored from an archive.

https://git.jami.net/savoirfairelinux/jami-client-android/-/issues/1765

Change-Id: I58e3e018c85e335f043f232e391286e716201481
2024-10-21 15:13:19 -04:00
7152b51597 screenshare: fix issue where screenshare didnt close
When joining a callSwarm as a participant, your mediaList would
contain 3 medias if a stream and video were active. The logic
behind this function didn't take that into account. In the future
it would be good to re-write this for arbitrary amounts of
medias.

Change-Id: If128650c535ae8ba9b02ec4738e8ef103f4994df
2024-10-19 10:47:25 -04:00
4a53397561 misc: bump daemon
Change-Id: I8c3de76b2d8e77cd568e904dfd9fbacb3b1899dc
2024-10-19 09:06:54 -04:00
d86a90207a packaging: add Fedora 41
Change-Id: I2baeaecd66af8e4a9e64072e85b5e5ca35c240ad
2024-10-18 16:56:12 -04:00
7b298deee8 packaging: fix Qt build on Fedora 40
GitLab: #1858
Change-Id: Ib0cfa7a1c458faecdb9c82359c182d4debadc6ab
2024-10-18 16:56:02 -04:00
056cf14613 packaging: add Ubuntu 24.10
Change-Id: I8d176e7e2a72e8185442ea81c9c943e6ab5fb912
2024-10-17 10:00:13 -04:00
2e75dd8777 misc: bump daemon
Change-Id: I5e6ff040101d9662cbdbc8e37ccb17c9ed014bc3
2024-10-11 15:58:24 -04:00
8bda8da414 packaging: fix Docker build error
The libpcre3-dev package doesn't exist on Debian testing, which caused
an error when trying to build Dockerfile_debian_testing. Adding the
newer libpcre2-dev package as an alternative in the debian/control file
fixes the issue.

GitLab: #1856
Change-Id: I3f9068a67101597eb2ffe7cb5a358870e7284e5b
2024-10-10 22:13:53 -04:00
b7fb63ae40 versioning: use app/jamicore git SHAs as the version
Currently, the user-facing version number in the about dialog, is a
build-time timestamp that does help us isolate the project versions
accurately. Ultimately, we need to be able to reproduce issues
present in specific versions of Jami. This commit introduces a new
version number in the form: <client_sha>.<jamicore_sha>, allowing
us to reproduce builds more accurately.

Gitlab: #1820
Change-Id: Ie7e20b20da65284e33e745996c410f539b65080c
2024-10-08 16:19:20 -04:00
31bd0392da share message: add share feature
A share feature have been requested to share
to contacts pictures or text received from other contacts
you can access it by hovering the message you want to share

Gitlab: #1830
Change-Id: I2555433417867371161f927e9fc78bb47fec68d3
2024-10-08 14:41:30 -04:00
59f3aa7c44 i18n: automatic bump
Change-Id: Ib77c972963786716b5794baffbeedb5f6b0fd738
2024-10-07 16:46:35 -04:00
9aeb405644 doc: update documentation regarding the install path of libqt on certain os
Change-Id: I684ecb448479059be0a163c29ab8673f908f31a0
2024-10-02 14:51:44 -04:00
9e1d8e3e56 messagebar: move js into js file, simplify markdown editing
This will make the code easier to read/debug and get us closer to
adhering to the coding guidelines regarding QML file length.

Gitlab: #1639
Change-Id: I6d6e9604c4a54e9fe354c0d24ef66b41ebbbff2a
2024-10-02 13:44:51 -04:00
b65774add0 about: add special thanks & translation on credits
git.jami.net/savoirfairelinux/jami-client-android/-/issues/1607

Change-Id: I3e3029550d91adc36c620c80c1f9c8e1de24a74b
2024-10-01 12:00:23 -04:00
c55486988f misc: unify terminology
smart quotes {“,”,’}
remove spaces in keyboard shortcuts, eg Ctrl + F → Ctrl+F
add participant → invite member
A(n) [type] error occurred while [attempting to] {verb} {noun}.
avatar → profile picture
ban → block
join in… → join with…
mute camera → stop camera
plugin → extension
request → invitation
unmute camera → start camera

GitLab: #1730
Change-Id: Ied169aea3b15b341ff467bc838c70da6a3d5050f
2024-10-01 11:06:04 -04:00
39833924af i18n: automatic bump
Change-Id: Ibab0cadf2e8338c3c2e8cb5725c7e630cf37df47
2024-09-30 16:42:30 -04:00
a194e86d7a screenshare: fix bug on certain wayland systems
Fixed logic error which was causing screen sharing to stop working on certain Wayland environments.

GitLab: #1676

Change-Id: Idf3beb97a53d2eb88e082cee710be56c90c6df05
2024-09-26 21:34:39 -04:00
8cfd9bc3fc macos: use clang with c++17 standard
Change-Id: I0bcf97bc3cc338a1e6e182089638e0d62f2994af
2024-09-26 09:53:48 -04:00
bdec942d72 shortcuts: fix unintended menu behavior
Fixed small issue where the button to bring up the keyboard
shortcuts menu would not be brought up if it was previously
hidden or minimized.

Change-Id: I89b021ca7a00c67325c992fde9cd14fbb8b82cf3
2024-09-25 21:49:09 -04:00
35d5595401 searchbar: fix warnings for invalid regular expressions
Certain characters such as @ or < were being treated as invalid
regular expressions and caused warnings to be raised. Added check
for validity of expression.

GitLab: #1628

Change-Id: I8b66ebfcf029cd0568bccdcba96672d9005846a9
2024-09-23 13:29:31 -04:00
7330a87082 JamiSplitView: fix crash for right-to-left languages
GitLab: #1829
Change-Id: I273d23ae5a8cfb38862259ab413a0aa778ab0341
2024-08-23 15:02:15 -04:00
7243b10e81 interaction: move Info implementation to a cpp file
This fixes the no-libwrap build, which was broken by commit
96c00ff019 due to an additional header
file included in interaction.h

GitLab: #1828
Change-Id: Ic3490a64fdc1514e0b6533a380cb7115568ae9f1
2024-08-23 11:13:30 -04:00
964c8e0553 build.py : Added missing dependence pipewire to build.py
libpipewire-0.3-dev is used since commit Ia54dbc512aa87ae1cb1df7c1ffe71c153a4937a2

Change-Id: Ia1299ec938091a844581f8bea3c7c5486bd43f14
2024-08-23 09:30:32 -04:00
96c00ff019 interaction: set body and transferStatus of DATA_TRANSFER messages
This patch adds code in the interaction::Info::init function so that the
"body" and "transferStatus" fields are always set when an Info struct is
constructed for a message of type DATA_TRANSFER.

This removes some code duplication in conversationmodel.cpp, where these
fields were being set as an extra step after construction in three
different places.

It also fixes a bug in the ConversationModelPimpl::slotMessageUpdated
function, which did *not* set the "body" of DATA_TRANSFER messages. The
body was therefore empty instead of containing a file path, which is
what caused the image preview bug described in the following issue:
GitLab: #1671

The patch also reverts a change that was made in the
MessageListModel::update function by commit
d2eba1d91e. This change was a workaround
for the above bug, but it is no longer necessary (and it broke message
deletion, which relies on the body of the deleted message being set to
the empty string).
GitLab: #1825

Change-Id: I5848b93a12c1ef7b3735c5c6db6b32a9bbc4041d
2024-08-22 11:48:48 -04:00
c8716d1113 misc: unify terminology
Start audio call
Start video call
https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/1730#note_51880

GitLab: #1730

Change-Id: I976a6ca890c4b28501da9754cbbee012a2993d73
2024-08-21 15:06:15 -04:00
630e5e9fe4 Added a line to thanks volunteers in credits
I added "And the volunteers who contribute to this project!" at the bottom of the credits in the "about Jami" pop-up.
It's already on the jami-client-android version.

Issue #1689 on gitlab

Change-Id: I59967e5b9e1e7eac0519c9b4960692c14c80dab7
2024-08-20 09:58:25 -04:00
f447327c02 i18n: automatic bump
Change-Id: Ia68b3566b33d82ed31401345e397474499339cba
2024-08-13 14:27:22 -04:00
650f98636b misc: bump daemon
Change-Id: I93d6954cb0e30831b8a4cf036b5cc2c3eefa9196
2024-08-13 10:54:57 -04:00
b92cd902b9 packaging: fix Qt build on Debian testing/unstable
This commit adds four patches to fix various issues that were preventing
Qt 6.6.1 from building on Debian testing and Debian unstable. These
patches are backports of fixes that were applied in later versions of
Qt; links to the relevant commits are included in the description at the
top of each patch.

There are also two changes in the Dockerfiles for Debian testing and
Debian unstable:
1) CMake 3.21 is no longer installed via the install-cmake.sh script.
   This is not necessary anymore given that Debian testing and Debian
   unstable now both come with more recent versions of CMake by default
   (3.29 and 3.30 respectively).
2) The libre2-dev package (which is part of the dependencies in
   debian-qt/control) is removed from the Docker image in order to force
   Qt to build using the bundled version of the RE2 library. This is
   necessary because the system version of the library on testing and
   unstable (libre2-11) is not compatible with earlier versions due to
   an API change, c.f.
   https://codereview.qt-project.org/c/qt/qtwebengine/+/516094

GitLab: #1822
Change-Id: I763fb6692949052e2a846b3f4ce54619e6d98108
2024-08-13 10:40:20 -04:00
b99c2674b4 tests: fix account accumulation on Linux systems
On non-dockerized Linux systems, the accounts generated during tests are
only cleaned up occassionally. The test suite design implements
consistent account cleanup post test. Accumulation of these accounts
interfere with subsequent test runs, rendering the test suite ineffective.

The main test scripts incorrectly utilize a Jami Windows environment
variable for Linux systems. In adherence with the Jami client design,
this patch utilizes the correct environment variable for Linux systems.
Windows formatted paths were also modified to allow recogntion in Linux
enironments

GitLab: #1801
Change-Id: I633dbd168af1e6d20ccee53d1109cd179bd1a187
2024-08-08 11:48:31 -04:00
1524ba0177 i18n: automatic bump
Change-Id: Ic9bd89443178a6f899caea1383d1621c7cfc4aeb
2024-08-05 16:42:31 -04:00
5503769023 packaging: remove Ubuntu 23.04 (EOL)
Support for Ubuntu 23.04 ended in January 2024.

Change-Id: Ib4a7a045762a391552da69ace333e46f10afdfb9
2024-08-02 11:37:31 -04:00
89354a07e1 conversation model: split logic for SIP and Jami
GitLab: #1794
Change-Id: Ief688df6778fe2758882ff1538371def8ba75d64
2024-07-26 15:46:50 -04:00
69400bee2a misc: bump daemon submodule
Brings in some changes intended to correct/improve CI building
on Windows.

https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1027
Change-Id: I7047cd343b5711adaf4c992b99dc07097e9ff05b
2024-07-26 14:50:10 -04:00
0e07f9cee7 JamiIdentifier: fix binding for Jami ID
GitLab: #1805
Change-Id: Ic847bb61ccb2c75873d91a35cd851caaedaf518d
2024-07-23 11:20:52 -04:00
d2eba1d91e chatview: fix datatransfer messages not showing
99254f8d02 introduced 2 issues:
- transfer messages not notifying the UI
- some file URLs being erased after loading the conversation
This commit addresses both of them.

Gitlab: #1671
Change-Id: I67a003ea1149c27e749efffe496f4c9ce86615ea
2024-07-22 12:10:25 -04:00
78389d8c28 data transfer model: fix warning
Change-Id: Ia4fcc47c9f033a8f136d6f6de0fc4bb666a1cdfc
2024-07-18 14:52:28 -04:00
e6d820850a misc: bump daemon submodule
In addition to integrating the new UPnP code introduced into
dhtnet, this bump also includes numerous bug-fixes:
https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/1637
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1021
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1033
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1026
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/952
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1025

Change-Id: Ic7242e3dfe14550221d9d0de48ff84605b7fefd8
2024-07-16 14:09:50 -04:00
0a7f9349a9 smartlist: don't display misleading 'last interaction' date
If a conversation has no interactions (which shouldn't happen normally,
but sometimes occurs in practice), then its LastInteractionTimeStamp
will be zero, which causes the last interaction date in the smartlist to
be wrongly displayed as 31/12/1969 or 1/1/1970. This patch adds a check
to prevent this.

GitLab: #1794
Change-Id: I1384d6675c9fcaa1904bb6e1706589305b7618e9
2024-07-12 09:56:50 -04:00
99254f8d02 messagelistmodel: add support for file deletion
+ Add button to delete messages on file transfer
+ Show "Deleted media" on deleted files.
+ Update last interaction
+ Update icon for saving file, we're in 2024, no more floppy disk

Change-Id: I607b1a6beda443db85c60d8cf95a9aae29ce1f7c
GitLab: #1287
2024-07-10 16:00:39 -04:00
010a2c4eea linkdevicedialog: fix what seems to have been a copy-paste error
The "success" property of the wrong component was being set in the
"on-link-device" signal handler. This commit fixes that.

Gitlab: #1788
Change-Id: I99c9abbfa31ea9ea6e7828dbbed0a21081f8be19
2024-07-05 15:56:01 -04:00
61163037d4 misc: bump daemon submodule
This bump will include changes to fix failing builds on Windows.
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1022

Change-Id: Ic34a097fbcea5723c8fe44da9c5887368dce2258
2024-07-04 16:03:20 -04:00
3577982a93 testing: added account switcher box
Change-Id: I76b67b819cd8e028062406b96583a36ae6a6d509
2024-07-04 15:53:04 -04:00
3ad0b92dcd link-preview: use non-ASCII UTF-8 characters in a UTF-8 test
Non-ASCII characters in UTF-8 are encoded with multiple bytes. Testing with these characters ensures that the decoder correctly interprets multi-byte sequences.

Gitlab: #1536
Change-Id: I0a92ee91b6cd26d70daab1f9baef3a9577aee02e
2024-07-04 13:01:02 -04:00
91475c3a3f misc: bump daemon
This fixes a serious issue on version 6.9 of the Linux kernel that is
already impacting some users:
https://git.jami.net/savoirfairelinux/jami-daemon/-/issues/1006

Change-Id: Id78643d51f38799be448034236364f746dbdfb10
2024-06-27 10:59:02 -04:00
9379af23ec callmodel: don't send profile
profile was not saved at reception anymore, this was wasting bandwidth

Change-Id: I3cbc1f1683a1e5a4b14616404cde5e27e07623e5
2024-06-21 14:30:53 -04:00
406a251c85 accountmodel: improve handling for account list reordering
This update fixes an issue where a stale account list might be used
in AccountListModel by synchronizing list invalidation with a newly
introduced signal (accountsReordered). This change prevents a data race
that could occur due to the asynchronous nature of setting the account
order over D-Bus, or when queuing the signal handling for
accountsChanged, which is emitted only once the reordering is saved.

As a result, QAbstractItemModel mutations are now performed within AccountListModel instead of in the UI.

Gitlab: #1638 (Account list in popup is incorrect after selection)
Change-Id: I7ed6eeb45eb319f21e40554f3d023ad24e139a6f
2024-06-10 10:29:24 -04:00
20e2852e44 misc: bump daemon (fixes missing API on macOS)
Change-Id: I9a04c1a87875a15b2d465982ddf5c3fa143a2dc0
2024-06-07 10:20:44 -04:00
3225f90ce8 misc: deploy and use ringtones on macOS
Gitlab: #1619
Change-Id: I7c19dfa4556f4f9dae827a1d0c967c9ebce7cc86
2024-06-04 12:36:41 -04:00
df3e76a1cf interaction: split status and transferStatus
This allow to show the correct sending/sent/state for the interaction
separated from the status of the dataTransfer. Else, we see a sent
check for a file even if the peer didn't receive the file

Change-Id: I15b9f0abc6a26a2ffd007be26827e9a37e859bca
2024-05-31 14:38:26 -04:00
c5e15d26a0 contactmodel: cache profiles for non contacts profile
If we're a member of a group swarm, we will receive profiles from
non contact (the other members of a conversation).
This patch try to get from cache before calling getContact() to be
able to retrieve profiles from non contacts if stored by the daemon

Change-Id: I864f1d5dd9f65232751e170b930606d23241d283
2024-05-31 10:22:12 -04:00
77e019b02b accountmodel: re-add save profile for JAMS account
JAMS account still use AccountProfileReceived

Change-Id: I010d459564a9230b7f06f4be55de668ec3526abd
2024-05-31 10:22:03 -04:00
89bed2bf85 avatar: fix image cropping
Take into consideration the vertical margin when cropping the image.

Change-Id: I140c96f54d2c1ae732bd104fb21ad04d66d97e9a
2024-05-30 15:09:55 -04:00
519871e458 DataTransferMessageDelegate: fix Url not defined
GitLab: #1563
Change-Id: Ie4ec46bbd7adb0fb0abf9da29224d7b87bcf0aa7
2024-05-30 11:45:53 -04:00
0a842042b0 ci/docker: add cppunit
Change-Id: I3abcdfa8d6a32eedbfd99ab0302d18b5bad6dae6
2024-05-30 10:55:55 -04:00
9aeb2377dc packaging: macos: simplify macdeployqt execution
Don't use a post build step, as it's only needed for packaging.

Change-Id: I1be4e7ac8042e1f211b4eeb15bc869e16eda1682
2024-05-29 12:45:41 -04:00
6ad5f4b850 snap: fix wayland scroll
GitLab: #1629
Change-Id: I74a651728c6d2d9c55b39772a11090d60231b3d5
2024-05-29 09:11:51 -05:00
f5c63d24fb packaging: fix opensuse leap 15.5
Change-Id: I555d6722fae688ba25c4eb2266088aeec0240528
2024-05-29 10:10:40 -04:00
5cb34bd31c misc: bump daemon
Change-Id: Id4f6d28423104965827d6b130533412dd918d536
2024-05-29 10:09:30 -04:00
e56a966de1 contactmodel: fix account avatar on link device
We do not need to write an empty profile since the daemon fully
manages the profile. Just update it from cache when new profile
is detected

GitLab: #1627
Change-Id: I31035f0666925d13f339f387e614f148b0eece8b
2024-05-29 10:08:10 -04:00
acc0c97234 contactmodel: fix contact initialization when linking a new device
getContacts() is called before sync is finished. This should be
done like conversations, after first initializing.
This fix the presence showing after sync.

GitLab: #1627
Change-Id: I4ec9b7e34b5bd93b9ae4437e6c6719dbc3b78a98
2024-05-29 10:08:10 -04:00
665af7c0c3 i18n: automatic bump
Change-Id: I1a004c1d7b2ad51eb3e59951f9e7158bc312c313
2024-05-27 16:42:57 -04:00
fa51e042e5 misc: update release name to Astarte
Change-Id: I64e7b601bbadc9055da912a7d6fe2304aa7a5169
2024-05-27 14:29:23 -04:00
146 changed files with 9678 additions and 3950 deletions

View File

@ -29,7 +29,8 @@ else()
project(jami)
endif()
include(${PROJECT_SOURCE_DIR}/extras/build/cmake/extra_tools.cmake)
set(CMAKE_SCRIPTS_DIR ${PROJECT_SOURCE_DIR}/extras/build/cmake)
include(${CMAKE_SCRIPTS_DIR}/extra_tools.cmake)
option(WITH_DAEMON_SUBMODULE "Build with daemon submodule" ON)
option(JAMICORE_AS_SUBDIR "Build Jami-core as a subdir dependency" OFF)
@ -117,6 +118,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
# src
set(LIBCLIENT_SRC_DIR ${PROJECT_SOURCE_DIR}/src/libclient)
set(APP_SRC_DIR ${PROJECT_SOURCE_DIR}/src/app)
set(VERSION_INFO_DIR ${PROJECT_SOURCE_DIR}/src/version_info)
# doc
set(DOC_DIR ${PROJECT_SOURCE_DIR}/doc)
# extras
@ -210,6 +212,23 @@ include(FindPython3)
find_package(Python3 3.6 REQUIRED COMPONENTS Interpreter)
set(PYTHON_EXEC ${Python3_EXECUTABLE})
# Versioning and build ID generation
set(VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/version_info.cpp)
# Touch the file to make sure it exists at configure time as
# we add it to the target_sources below.
file(TOUCH ${VERSION_FILE})
add_custom_target(
generate_version_info ALL
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
COMMAND ${CMAKE_COMMAND}
-DAPP_SOURCE_DIR=${CMAKE_SOURCE_DIR}
-DAPP_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
-DCORE_SOURCE_DIR=${DAEMON_DIR}
-DCPP_INT_FILE=${VERSION_INFO_DIR}/version_info.cpp.in
-P ${CMAKE_SCRIPTS_DIR}/generate_version_info.cmake
)
list(APPEND CLIENT_INCLUDE_DIRS ${VERSION_INFO_DIR})
# Resource auto-gen
# QML and related code files
# Check files in the app's src directory and force a reconfigure if it
@ -247,6 +266,7 @@ set(QML_IMPORT_PATH ${QML_DIRS}
add_definitions(-DQT_NO_KEYWORDS)
set(COMMON_SOURCES
${VERSION_FILE}
${APP_SRC_DIR}/bannedlistmodel.cpp
${APP_SRC_DIR}/accountlistmodel.cpp
${APP_SRC_DIR}/networkmanager.cpp
@ -626,6 +646,9 @@ qt_add_executable(
${QML_RESOURCES_QML}
${SFPM_OBJECTS})
# Make sure we can find the generated version file
add_dependencies(${PROJECT_NAME} generate_version_info)
foreach(MODULE ${QT_MODULES})
list(APPEND QT_LIBS "Qt::${MODULE}")
endforeach()
@ -819,12 +842,20 @@ else()
"-framework Security"
compression
resolv
)
)
set(APP_CONTAINER "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents")
# ringtones. Copy the entire directory to the app bundle.
# daemon/ringtones -> Jami.app/Contents/Resources/ringtones
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_directory
${DAEMON_DIR}/ringtones
${APP_CONTAINER}/Resources/ringtones
)
# translations
if(Qt${QT_VERSION_MAJOR}LinguistTools_FOUND)
set(APP_CONTAINER
"${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app/Contents")
file(GLOB TS_FILES ${PROJECT_SOURCE_DIR}/translations/*.ts)
# Generate lproj folders.
@ -852,26 +883,26 @@ else()
MACOSX_BUNDLE_SHORT_VERSION_STRING "${JAMI_VERSION}"
MACOSX_BUNDLE_BUNDLE_VERSION "${JAMI_BUILD}"
MACOSX_BUNDLE_COPYRIGHT "${PROJ_COPYRIGHT}")
if(APPSTORE)
message(STATUS "app store version")
set_target_properties(${PROJECT_NAME} PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/appstore/Jami.entitlements")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES
SPARKLE_URL "${SPARKLE_URL}"
SPARKLE_PUBLIC_KEY "${SPARKLE_PUBLIC_KEY}"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/Jami.entitlements"
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE)
endif()
if(DEPLOY)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -DQML_SRC_DIR=${SRC_DIR}
-DMAC_DEPLOY_QT_PATH=${CMAKE_PREFIX_PATH}/bin
-DEXE_NAME="${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app"
-DSPARKLE_PATH=${SPARKLE_FRAMEWORK}
-DENABLE_SPARKLE=${ENABLE_SPARKLE}
-P ${EXTRAS_DIR}/build/cmake/macos_qt_deploy.cmake)
endif()
if(APPSTORE)
message(STATUS "app store version")
set_target_properties(${PROJECT_NAME} PROPERTIES
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/appstore/Jami.entitlements")
else()
set_target_properties(${PROJECT_NAME} PROPERTIES
SPARKLE_URL "${SPARKLE_URL}"
SPARKLE_PUBLIC_KEY "${SPARKLE_PUBLIC_KEY}"
XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/resources/entitlements/Jami.entitlements"
XCODE_ATTRIBUTE_ENABLE_HARDENED_RUNTIME TRUE)
endif()
if(DEPLOY)
execute_process(COMMAND
"${CMAKE_PREFIX_PATH}/bin/macdeployqt"
"${CMAKE_BINARY_DIR}/${PROJECT_NAME}.app"
-qmldir=${QML_SRC_DIR})
if(${ENABLE_SPARKLE} MATCHES true)
file(COPY ${SPARKLE_FRAMEWORK} DESTINATION ${EXE_NAME}/Contents/Frameworks/)
endif()
endif()
endif()
target_include_directories(${PROJECT_NAME} PRIVATE ${CLIENT_INCLUDE_DIRS})

View File

@ -14,7 +14,7 @@ So, you will need to get Qt 6.6 first. For this, there is 3 methods:
### Qt from our repo (recommended)
If your distribution is supported, we provide a Qt package (libqt-jami) on our repo.
The files will be installed in `/usr/lib/libqt-jami`.
The files will be installed to `/usr/lib/libqt-jami` on Debian-like distributions. For RPM based distributions the files will be installed to `/usr/lib64/qt-jami`.
#### Install libqt-jami, Ubuntu based

View File

@ -100,7 +100,7 @@ ZYPPER_DEPENDENCIES = [
'speexdsp-devel', 'speex-devel', 'libdbus-c++-devel', 'jsoncpp-devel', 'yaml-cpp-devel',
'yasm', 'libuuid-devel', 'libnettle-devel', 'libopus-devel', 'libexpat-devel',
'libgnutls-devel', 'msgpack-c-devel', 'msgpack-cxx-devel', 'libavcodec-devel', 'libavdevice-devel', 'pcre-devel',
'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel',
'alsa-devel', 'libpulse-devel', 'libudev-devel', 'libva-devel', 'libvdpau-devel', 'pipewire-devel',
'libopenssl-devel', 'libavutil-devel',
]
@ -130,7 +130,7 @@ DNF_DEPENDENCIES = [
'gcc-c++', 'which', 'alsa-lib-devel', 'systemd-devel', 'libuuid-devel',
'uuid-devel', 'gnutls-devel', 'nettle-devel', 'opus-devel', 'speexdsp-devel',
'yaml-cpp-devel', 'swig', 'jsoncpp-devel',
'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'msgpack-devel',
'patch', 'libva-devel', 'openssl-devel', 'libvdpau-devel', 'pipewire-devel', 'msgpack-devel',
'sqlite-devel', 'openssl-static', 'pandoc', 'nasm',
'bzip2'
]
@ -154,7 +154,7 @@ APT_DEPENDENCIES = [
'libopus-dev', 'libpcre3-dev', 'libpulse-dev', 'libssl-dev',
'libspeex-dev', 'libspeexdsp-dev', 'libswscale-dev', 'libtool',
'libudev-dev', 'libyaml-cpp-dev', 'sip-tester', 'swig',
'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libmsgpack-dev',
'uuid-dev', 'yasm', 'libjsoncpp-dev', 'libva-dev', 'libvdpau-dev', 'libpipewire-0.3-dev', 'libmsgpack-dev',
'pandoc', 'nasm', 'dpkg-dev', 'libsystemd-dev'
]

2
daemon

Submodule daemon updated: fd2f281544...f379421e8a

View File

@ -0,0 +1,34 @@
find_package(Git QUIET REQUIRED)
message(STATUS "Generating version information...")
function(configure_version_string SOURCE_DIR VERSION_STRING_OUT)
# Get short git SHA
execute_process(
COMMAND "${GIT_EXECUTABLE}" rev-parse --short HEAD
WORKING_DIRECTORY "${SOURCE_DIR}"
OUTPUT_VARIABLE _GIT_SHA
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# Output the VERSION_STRING_OUT to the caller
set(${VERSION_STRING_OUT} "${_GIT_SHA}" PARENT_SCOPE)
endfunction()
# These need to be set to the parent scripts values for configure_file to work,
# as it prepends CMAKE_CURRENT_SOURCE_DIR to the <input> and CMAKE_CURRENT_BINARY_DIR
# to <output>.
set(CMAKE_CURRENT_SOURCE_DIR ${APP_SOURCE_DIR})
set(CMAKE_CURRENT_BINARY_DIR ${APP_BINARY_DIR})
# Generate the version string for the application and core
configure_version_string(${APP_SOURCE_DIR} APP_VERSION_STRING)
configure_version_string(${CORE_SOURCE_DIR} CORE_VERSION_STRING)
# Get output file names with the .in extension removed
get_filename_component(VERSION_CPP_FILENAME ${CPP_INT_FILE} NAME_WE)
set(VERSION_CPP_FILE "${CMAKE_CURRENT_BINARY_DIR}/${VERSION_CPP_FILENAME}.cpp")
message(STATUS "infiles: ${CPP_INT_FILE}")
message(STATUS "outfiles: ${VERSION_CPP_FILE}")
configure_file(${CPP_INT_FILE} ${VERSION_CPP_FILE})

View File

@ -1,7 +0,0 @@
message("Qt deploying in dir " ${QML_SRC_DIR})
execute_process(COMMAND "${MAC_DEPLOY_QT_PATH}/macdeployqt"
${EXE_NAME}
-qmldir=${QML_SRC_DIR})
if(${ENABLE_SPARKLE} MATCHES true)
file(COPY ${SPARKLE_PATH} DESTINATION ${EXE_NAME}/Contents/Frameworks/)
endif()

View File

@ -66,6 +66,7 @@ RUN apt-get install -y -o Acquire::Retries=10 \
libvdpau-dev \
libssl-dev
RUN apt-get install -y pandoc \
libcppunit-dev \
googletest \
libgtest-dev \
wget

View File

@ -49,7 +49,7 @@ QT_MAJOR := 6
QT_MINOR := 6
QT_PATCH := 1
QT_TARBALL_CHECKSUM := dd3668f65645fe270bc615d748bd4dc048bd17b9dc297025106e6ecc419ab95d
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-0
DEBIAN_QT_VERSION := $(QT_MAJOR).$(QT_MINOR).$(QT_PATCH)-1
DEBIAN_QT_DSC_FILENAME := libqt-jami_$(DEBIAN_QT_VERSION).dsc
QT_JAMI_PREFIX := /usr/lib/libqt-jami
@ -166,13 +166,14 @@ DISTRIBUTIONS := \
debian_unstable \
ubuntu_20.04 \
ubuntu_22.04 \
ubuntu_23.04 \
ubuntu_23.10 \
ubuntu_24.04 \
ubuntu_24.10 \
fedora_37 \
fedora_38 \
fedora_39 \
fedora_40 \
fedora_41 \
alma_9 \
opensuse-leap_15.4 \
opensuse-leap_15.5 \

View File

@ -27,9 +27,7 @@ RUN /opt/prebuild-package-debian.sh qt-deps
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
RUN /opt/prebuild-package-debian.sh jami-deps
# Install CMake 3.21 for Qt 6
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
RUN /opt/install-cmake.sh
RUN apt-get remove -y libre2-dev libre2-11
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
CMD ["/opt/build-package-debian.sh"]

View File

@ -27,9 +27,7 @@ RUN /opt/prebuild-package-debian.sh qt-deps
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
RUN /opt/prebuild-package-debian.sh jami-deps
# Install CMake 3.21 for Qt 6
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh
RUN /opt/install-cmake.sh
RUN apt-get remove -y libre2-dev libre2-11
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
CMD ["/opt/build-package-debian.sh"]

View File

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

View File

@ -1,6 +1,6 @@
FROM opensuse/leap:15.5
RUN zypper refresh
RUN zypper --gpg-auto-import-keys refresh
RUN zypper --non-interactive install -y \
dnf \

View File

@ -1,4 +1,4 @@
FROM ubuntu:23.04
FROM ubuntu:24.10
ENV DEBIAN_FRONTEND=noninteractive
@ -18,5 +18,12 @@ RUN /opt/prebuild-package-debian.sh qt-deps
COPY extras/packaging/gnu-linux/rules/debian/control /tmp/builddeps/debian/control
RUN /opt/prebuild-package-debian.sh jami-deps
# Remove the libre2-dev package in order to force Qt to build using the bundled
# version of the RE2 library. This is necessary because the system version of the
# library on Ubuntu 24.10 (libre2-11) is not compatible with the one used in
# Qt 6.6.1 due to an API change:
# https://codereview.qt-project.org/c/qt/qtwebengine/+/516094
RUN apt-get remove -y libre2-dev libre2-11
ADD extras/packaging/gnu-linux/scripts/build-package-debian.sh /opt/build-package-debian.sh
CMD ["/opt/build-package-debian.sh"]

View File

@ -1,10 +1,18 @@
From deeacfdb5a6d1d300d4ba991df76aa12e5dbaa42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
<sebastien.blin@savoirfairelinux.com>
Date: Tue, 16 Apr 2024 09:54:32 -0400
Subject: [PATCH] fix imp->importlib
From 24fb774485f719df1e84dda31605d3f69202d69f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Thu, 8 Aug 2024 14:59:17 -0400
Subject: [PATCH] qtwebengine: enable building with Python 3.12
Replace the deprecated imp module by importlib:
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/524014
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/534568
Update six to fix html5lib import failure:
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/535605
https://issues.chromium.org/issues/40286977
---
.../protobufs/binary_proto_generator.py | 8 ++++++--
.../mojo/public/tools/mojom/mojom/fileutil.py | 1 -
.../tools/mojom/mojom/fileutil_unittest.py | 5 +----
.../mojom/mojom/generate/generator_unittest.py | 7 ++-----
@ -14,11 +22,37 @@ Subject: [PATCH] fix imp->importlib
.../mojo/public/tools/mojom/mojom/parse/lexer.py | 1 -
.../tools/mojom/mojom/parse/lexer_unittest.py | 7 ++-----
.../tools/mojom/mojom/parse/parser_unittest.py | 5 -----
.../3rdparty/chromium/third_party/six/src/six.py | 16 ++++++++++++++++
10 files changed, 23 insertions(+), 37 deletions(-)
.../third_party/catapult/third_party/six/six.py | 16 ++++++++++++++++
11 files changed, 29 insertions(+), 39 deletions(-)
diff --git a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
index 2a1802dccdc..8b9de65ed0b 100755
--- a/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
+++ b/qtwebengine/src/3rdparty/chromium/components/resources/protobufs/binary_proto_generator.py
@@ -9,7 +9,7 @@
"""
from __future__ import print_function
import abc
-import imp
+from importlib import util as imp_util
import optparse
import os
import re
@@ -68,7 +68,11 @@ class GoogleProtobufModuleImporter:
raise ImportError(fullname)
filepath = self._fullname_to_filepath(fullname)
- return imp.load_source(fullname, filepath)
+ spec = imp_util.spec_from_file_location(fullname, filepath)
+ loaded = imp_util.module_from_spec(spec)
+ spec.loader.exec_module(loaded)
+
+ return loaded
class BinaryProtoGenerator:
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
index 29daec367c..124f12c134 100644
index 29daec367c5..124f12c134b 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil.py
@@ -3,7 +3,6 @@
@ -30,7 +64,7 @@ index 29daec367c..124f12c134 100644
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 48eaf4eca9..c93d22898d 100644
index 48eaf4eca94..c93d22898d2 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/fileutil_unittest.py
@@ -2,19 +2,16 @@
@ -55,7 +89,7 @@ index 48eaf4eca9..c93d22898d 100644
temp_dir = tempfile.mkdtemp()
try:
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
index 76cda3981f..7143e07c4d 100644
index 76cda3981f3..7143e07c4d7 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/generator_unittest.py
@@ -2,12 +2,11 @@
@ -94,7 +128,7 @@ index 76cda3981f..7143e07c4d 100644
if __name__ == "__main__":
unittest.main()
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
index 4259374513..558e71e119 100644
index 4259374513f..558e71e1193 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/generate/translate_unittest.py
@@ -2,16 +2,12 @@
@ -115,7 +149,7 @@ index 4259374513..558e71e119 100644
"""Tests |parser.Parse()|."""
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
index c36376712e..b289f7b11f 100644
index c36376712e7..b289f7b11f6 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/ast_unittest.py
@@ -2,14 +2,10 @@
@ -148,7 +182,7 @@ index c36376712e..b289f7b11f 100644
"""Tests various AST classes."""
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
index 5fc582025e..2fa5d2be6a 100644
index 5fc582025ee..2fa5d2be6ab 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/conditional_features_unittest.py
@@ -2,12 +2,11 @@
@ -192,7 +226,7 @@ index 5fc582025e..2fa5d2be6a 100644
if __name__ == '__main__':
unittest.main()
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
index 73ca15df94..1083a1af7b 100644
index 73ca15df94c..1083a1af7bb 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer.py
@@ -2,7 +2,6 @@
@ -204,7 +238,7 @@ index 73ca15df94..1083a1af7b 100644
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 ce376da66e..bc9f835431 100644
index ce376da66e0..bc9f8354316 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/lexer_unittest.py
@@ -2,12 +2,11 @@
@ -241,7 +275,7 @@ index ce376da66e..bc9f835431 100644
# we'll do it anyway. (I'm pretty sure ply's lexer never cares about comparing
# for object identity.)
diff --git a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
index 0513343ec7..0a26307b1a 100644
index 0513343ec7e..0a26307b1a3 100644
--- a/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
+++ b/qtwebengine/src/3rdparty/chromium/mojo/public/tools/mojom/mojom/parse/parser_unittest.py
@@ -2,16 +2,12 @@
@ -268,10 +302,10 @@ index 0513343ec7..0a26307b1a 100644
-
if __name__ == "__main__":
unittest.main()
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/six/src/six.py b/qtwebengine/src/3rdparty/chromium/third_party/six/src/six.py
index 5fe9f8e141..96b06f8ce7 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/six/src/six.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/six/src/six.py
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py b/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
index 83f69783d1a..5e7f0ce4437 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
+++ b/qtwebengine/src/3rdparty/chromium/third_party/catapult/third_party/six/six.py
@@ -71,6 +71,11 @@ else:
MAXSIZE = int((1 << 63) - 1)
del X
@ -310,5 +344,5 @@ index 5fe9f8e141..96b06f8ce7 100644
--
2.43.0
2.34.1

View File

@ -0,0 +1,26 @@
From cf208d11dc8a9a02160a57283596ec8bab964a09 Mon Sep 17 00:00:00 2001
From: Sebastien Blin <sebastien.blin@savoirfairelinux.com>
Date: Mon, 27 May 2024 16:01:21 -0400
Subject: [PATCH] qtwayland: downgrade wl-seat to avoid high-resolution
scrolling events
---
qtwayland/src/client/qwaylandinputdevice.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qtwayland/src/client/qwaylandinputdevice.cpp b/qtwayland/src/client/qwaylandinputdevice.cpp
index a4f8757e3c..ad0aa7941c 100644
--- a/qtwayland/src/client/qwaylandinputdevice.cpp
+++ b/qtwayland/src/client/qwaylandinputdevice.cpp
@@ -383,7 +383,7 @@ QWaylandInputDevice::Touch::~Touch()
}
QWaylandInputDevice::QWaylandInputDevice(QWaylandDisplay *display, int version, uint32_t id)
- : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 9))
+ : QtWayland::wl_seat(display->wl_registry(), id, qMin(version, 7))
, mQDisplay(display)
, mDisplay(display->wl_display())
{
--
2.45.0

View File

@ -0,0 +1,40 @@
From 420b3e5ac2e91b7a99488ac34577e2798a84a68c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Tue, 6 Aug 2024 17:35:56 -0400
Subject: [PATCH] qtbase: fix CMake error
For more information, see:
https://github.com/qt/qtbase/commit/3411f2984a5325a35e3bed1f961e5973d8a565b9
---
qtbase/configure.cmake | 1 +
qtbase/src/corelib/CMakeLists.txt | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/qtbase/configure.cmake b/qtbase/configure.cmake
index 43de2aa026..37a82dcdb6 100644
--- a/qtbase/configure.cmake
+++ b/qtbase/configure.cmake
@@ -18,6 +18,7 @@ if(TARGET ZLIB::ZLIB)
set_property(TARGET ZLIB::ZLIB PROPERTY IMPORTED_GLOBAL TRUE)
endif()
+qt_find_package(Threads PROVIDED_TARGETS Threads::Threads)
qt_find_package(WrapOpenSSLHeaders PROVIDED_TARGETS WrapOpenSSLHeaders::WrapOpenSSLHeaders MODULE_NAME core)
# openssl_headers
# OPENSSL_VERSION_MAJOR is not defined for OpenSSL 1.1.1
diff --git a/qtbase/src/corelib/CMakeLists.txt b/qtbase/src/corelib/CMakeLists.txt
index 31b81734e8..b62e2f763b 100644
--- a/qtbase/src/corelib/CMakeLists.txt
+++ b/qtbase/src/corelib/CMakeLists.txt
@@ -1,7 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-qt_find_package(Threads PROVIDED_TARGETS Threads::Threads)
qt_find_package(WrapPCRE2 PROVIDED_TARGETS WrapPCRE2::WrapPCRE2)
qt_find_package(WrapZLIB PROVIDED_TARGETS WrapZLIB::WrapZLIB)
--
2.34.1

View File

@ -0,0 +1,40 @@
From 4c7360faeb0fb7f1dfd995619fb8c596b4e15606 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Thu, 8 Aug 2024 10:29:43 -0400
Subject: [PATCH] qtwebengine: add missing chromium dependencies
For more information, see:
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/555586
---
chromium/content/public/browser/BUILD.gn | 1 +
chromium/extensions/browser/api/declarative_net_request/BUILD.gn | 1 +
2 files changed, 2 insertions(+)
diff --git a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
index b25bf5764e7..dfbfb2ec77b 100644
--- a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
+++ b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
@@ -515,6 +515,7 @@ jumbo_source_set("browser_sources") {
"//cc",
"//components/services/storage/public/cpp",
"//components/viz/host",
+ "//components/spellcheck:buildflags",
"//content/browser", # Must not be public_deps!
"//device/fido",
"//gpu",
diff --git a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
index 1fc492f5a0c..13a266e22f1 100644
--- a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -23,6 +23,7 @@ source_set("declarative_net_request") {
"//extensions/common",
"//extensions/common/api",
"//services/preferences/public/cpp",
+ "//components/web_cache/browser",
]
public_deps = [ "//extensions/browser:browser_sources" ]
--
2.34.1

View File

@ -0,0 +1,49 @@
From ab6d5bebaf68a9f4d00440b2adbaffe0e5b2ae6c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Thu, 8 Aug 2024 10:55:08 -0400
Subject: [PATCH] qtwebengine: fix libxml2 build error
Version 2.12 of libxml2 introduced a change that broke chromium's build,
see: https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/523633
---
.../third_party/blink/renderer/core/xml/xslt_processor.h | 5 +++++
.../blink/renderer/core/xml/xslt_processor_libxslt.cc | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
index d53835e9675..72536e4fd7d 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor.h
@@ -77,7 +77,12 @@ class XSLTProcessor final : public ScriptWrappable {
void reset();
+#if LIBXML_VERSION >= 21200
+ static void ParseErrorFunc(void* user_data, const xmlError*);
+#else
static void ParseErrorFunc(void* user_data, xmlError*);
+#endif
+
static void GenericErrorFunc(void* user_data, const char* msg, ...);
// Only for libXSLT callbacks
diff --git a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
index 133e0b3355d..e8e6a09f485 100644
--- a/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
+++ b/qtwebengine/src/3rdparty/chromium/third_party/blink/renderer/core/xml/xslt_processor_libxslt.cc
@@ -66,7 +66,11 @@ void XSLTProcessor::GenericErrorFunc(void*, const char*, ...) {
// It would be nice to do something with this error message.
}
+#if LIBXML_VERSION >= 21200
+void XSLTProcessor::ParseErrorFunc(void* user_data, const xmlError* error) {
+#else
void XSLTProcessor::ParseErrorFunc(void* user_data, xmlError* error) {
+#endif
FrameConsole* console = static_cast<FrameConsole*>(user_data);
if (!console)
return;
--
2.34.1

View File

@ -0,0 +1,34 @@
From 6e0848a1c51c6494e3b7410c5fe38941d48fcb36 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Wed, 16 Oct 2024 22:32:12 -0400
Subject: [PATCH] qtwebengine: fix v8 build error
In file included from ../../../3rdparty/chromium/v8/src/heap/cppgc/sweeper.h:14,
from ./../../../3rdparty/chromium/v8/src/heap/cppgc/sweeper.cc:5,
from gen/v8/cppgc_base_jumbo_7.cc:5:
../../../3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h: In member function 'void cppgc::internal::StatsCollector::ForAllAllocationObservers(Callback)':
../../../3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h:401:48: error: cannot convert 'std::vector&lt;cppgc::internal::StatsCollector::AllocationObserver*&gt;::iterator' to 'const char*'
401 | std::remove(allocation_observers_.begin(), allocation_observers_.end(),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
| |
| std::vector&lt;cppgc::internal::StatsCollector::AllocationObserver*&gt;::iterator
---
.../src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
index 2cf728489d..d8414ae3c6 100644
--- a/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
+++ b/qtwebengine/src/3rdparty/chromium/v8/src/heap/cppgc/stats-collector.h
@@ -8,6 +8,7 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
#include <atomic>
#include <vector>
--
2.47.0

View File

@ -1,2 +1,7 @@
0001-replace_imp_by_importlib.patch
0002-fix-binary-tokenizer.patch
0001-qtwebengine-enable-building-with-Python-3.12.patch
0002-fix-binary-tokenizer.patch
0003-qtwayland-downgrade-wl-seat-to-avoid-high-resolution.patch
0004-qtbase-fix-CMake-error.patch
0005-qtwebengine-add-missing-chromium-dependencies.patch
0006-qtwebengine-fix-libxml2-build-error.patch
0007-qtwebengine-fix-v8-build-error.patch

View File

@ -22,7 +22,7 @@ Build-Depends: debhelper (>= 9),
libpulse-dev,
libasound2-dev,
libexpat1-dev,
libpcre3-dev,
libpcre3-dev | libpcre2-dev,
libyaml-cpp-dev,
libboost-dev,
libxext-dev,

View File

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

View File

@ -30,6 +30,7 @@ Vendor: Savoir-faire Linux Inc.
URL: https://jami.net/
Source: jami-libqt-%{version}.tar.xz
Patch0: 0001-fix-gcc14.patch
Patch1: 0002-qtwebengine-add-missing-chromium-dependencies.patch
%global gst 0.10
%if 0%{?fedora} || 0%{?rhel} > 7
@ -65,7 +66,8 @@ This package contains Qt libraries for Jami.
%prep
%setup -n qt-everywhere-src-%{version}
%patch0 -p1
%patch -P 0 -p1
%patch -P 1 -p1
%build
echo "Building Qt using %{job_count} parallel jobs"

View File

@ -0,0 +1,40 @@
From 04778c7f54c8a1a0e7fced75c5ef39ced82cece1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Sat, 12 Oct 2024 16:21:35 -0400
Subject: [PATCH] qtwebengine: add missing chromium dependencies
For more information, see:
https://codereview.qt-project.org/c/qt/qtwebengine-chromium/+/555586
---
chromium/content/public/browser/BUILD.gn | 1 +
chromium/extensions/browser/api/declarative_net_request/BUILD.gn | 1 +
2 files changed, 2 insertions(+)
diff --git a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
index b25bf5764e7..dfbfb2ec77b 100644
--- a/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
+++ b/qtwebengine/src/3rdparty/chromium/content/public/browser/BUILD.gn
@@ -515,6 +515,7 @@ jumbo_source_set("browser_sources") {
"//cc",
"//components/services/storage/public/cpp",
"//components/viz/host",
+ "//components/spellcheck:buildflags",
"//content/browser", # Must not be public_deps!
"//device/fido",
"//gpu",
diff --git a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
index 1fc492f5a0c..13a266e22f1 100644
--- a/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
+++ b/qtwebengine/src/3rdparty/chromium/extensions/browser/api/declarative_net_request/BUILD.gn
@@ -23,6 +23,7 @@ source_set("declarative_net_request") {
"//extensions/common",
"//extensions/common/api",
"//services/preferences/public/cpp",
+ "//components/web_cache/browser",
]
public_deps = [ "//extensions/browser:browser_sources" ]
--
2.47.0

View File

@ -172,7 +172,7 @@ package-repositories:
components: [main]
suites: [jami]
key-id: A295D773307D25A33AE72F2F64CD5FA175348F84
url: https://dl.jami.net/nightly/ubuntu_20.04/
url: https://dl.jami.net/internal/ubuntu_20.04/
parts:
desktop-launch:
@ -325,6 +325,12 @@ parts:
- libgnutls28-dev # TLS
- gnutls-bin
- libssl-dev
- git # PipeWire build dependencies
- libasound2-dev #
- libdbus-1-dev # These packages are needed by the
- libglib2.0-dev # install-pipewire-from-source.sh
- ninja-build # script in order to build PipeWire
- pkg-config # from source.
stage-packages:
- libgnutls30
- libavutil56

View File

@ -114,6 +114,8 @@ if [ ! -f "${RPM_PATH}" ]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc39.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_40" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc40.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_41" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc41.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "alma_9" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el9.x86_64.rpm "${RPM_PATH}"
else

View File

@ -8,9 +8,6 @@ set -e
OLD_WD=$(pwd)
cd /tmp
# Install PipeWire's build dependencies
apt-get install --yes gcc git libasound2-dev libdbus-1-dev libglib2.0-dev ninja-build pkg-config
# Get a version of Meson that's recent enough to build PipeWire 1.0.5 (the one available via apt is too old)
wget -q https://github.com/mesonbuild/meson/releases/download/0.61.1/meson-0.61.1.tar.gz
echo "feb2cefb325b437dbf36146df7c6b87688ddff0b0205caa31dc64055c6da410c meson-0.61.1.tar.gz" | sha256sum --check

View File

@ -99,6 +99,12 @@ for ARCH in "${ARCHS[@]}"; do
echo "$ARCH"
cd "$DAEMON"
HOST="${ARCH}-apple-darwin"
SDKROOT=$(xcrun --sdk macosx --show-sdk-path)
CC="xcrun -sdk macosx clang"
CXX="xcrun -sdk macosx clang++"
CFLAGS="-arch $ARCH -isysroot $SDKROOT"
CXXFLAGS="-std=c++17 $CFLAGS"
CONFIGURE_FLAGS=" --without-dbus --host=${HOST} -with-contrib=$DAEMON/contrib/${ARCH}-apple-darwin${OS_VER} --prefix=${INSTALL}/daemon/$ARCH"
if [ "${debug}" = "true" ]; then
@ -113,7 +119,11 @@ for ARCH in "${ARCHS[@]}"; do
mkdir -p "build-macos-${ARCH}"
cd "build-macos-${ARCH}"
"$DAEMON"/configure $CONFIGURE_FLAGS ARCH="$ARCH" || exit 1
"$DAEMON"/configure $CONFIGURE_FLAGS ARCH="$ARCH" \
CC="$CC $CFLAGS" \
CXX="$CXX $CXXFLAGS" \
CFLAGS="$CFLAGS" \
CXXFLAGS="$CXXFLAGS" || exit 1
echo "$CONFIGURE_FLAGS"

View File

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="48" width="48"><path d="M42 13.85V39q0 1.2-.9 2.1-.9.9-2.1.9H9q-1.2 0-2.1-.9Q6 40.2 6 39V9q0-1.2.9-2.1Q7.8 6 9 6h25.15Zm-3 1.35L32.8 9H9v30h30ZM24 35.75q2.15 0 3.675-1.525T29.2 30.55q0-2.15-1.525-3.675T24 25.35q-2.15 0-3.675 1.525T18.8 30.55q0 2.15 1.525 3.675T24 35.75ZM11.65 18.8h17.9v-7.15h-17.9ZM9 15.2V39 9Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" height="48px" viewBox="0 -960 960 960" width="48px" fill="#e8eaed"><path d="M480-313 287-506l43-43 120 120v-371h60v371l120-120 43 43-193 193ZM220-160q-24 0-42-18t-18-42v-143h60v143h520v-143h60v143q0 24-18 42t-42 18H220Z"/></svg>

Before

Width:  |  Height:  |  Size: 369 B

After

Width:  |  Height:  |  Size: 268 B

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<path d="M17.1,15.7c-0.8,0-1.5,0.3-2.1,0.8l-5.3-3.3C9.9,12.8,10,12.4,10,12c0-0.4-0.1-0.8-0.3-1.2l5.3-3.3c0.6,0.5,1.3,0.8,2.1,0.8
c1.7,0,3.1-1.4,3.1-3.1S18.9,2,17.1,2C15.4,2,14,3.4,14,5.1c0,0.4,0.1,0.8,0.3,1.2L8.9,9.6C8.3,9.1,7.6,8.9,6.9,8.9
c-1.7,0-3.1,1.4-3.1,3.1s1.4,3.1,3.1,3.1c0.8,0,1.5-0.3,2.1-0.8l5.3,3.3C14.1,18,14,18.4,14,18.9c0,1.7,1.4,3.1,3.1,3.1
c1.7,0,3.1-1.4,3.1-3.1S18.9,15.7,17.1,15.7z M17.1,20.6c-1,0-1.8-0.8-1.8-1.8s0.8-1.8,1.8-1.8c1,0,1.8,0.8,1.8,1.8
S18.1,20.6,17.1,20.6z M17.1,3.4c1,0,1.8,0.8,1.8,1.8s-0.8,1.8-1.8,1.8c-1,0-1.8-0.8-1.8-1.8S16.2,3.4,17.1,3.4z M6.9,13.8
c-1,0-1.8-0.8-1.8-1.8s0.8-1.8,1.8-1.8S8.6,11,8.6,12S7.8,13.8,6.9,13.8z"/>
</svg>

After

Width:  |  Height:  |  Size: 1019 B

View File

@ -1,11 +1,13 @@
<h4 align="left"><span style="font-weight:600"> Created by</span></h4>
<p>%1</p>
<h4 align="left"><span style="font-weight:600">%2</span></h4>
<p>Abhishek Ojha<br>
Adrien Béraud<br>
Albert Babí<br>
Alexandre Lision<br>
Alexandr Sergheev<br>
Alexandre Viau<br>
Alexander Lussier-Cullen<br>
Alexandr Sergheev<br>
Alexandre Eberhardt<br>
Alexandre Lision<br>
Alexandre Viau<br>
Aline Bonnet<br>
Aline Gondim Santos<br>
Alireza Toghiani<br>
@ -18,7 +20,6 @@ Brando Tovar<br>
Capucine Berthet<br>
Charles-Francis Damedey<br>
Cyrille Béraud<br>
Dorina Mosku<br>
Eden Abitbol<br>
Édric Milaret<br>
Éloi Bail<br>
@ -33,11 +34,16 @@ Guillaume Roguez<br>
Hadrien De Sousa<br>
Hugo Lefeuvre<br>
Julien Grossholtz<br>
Julien Robert<br>
Kateryna Kostiuk<br>
Kessler DuPont-Teevin<br>
Léo Banno-Cloutier<br>
Léopold Chappuis<br>
Liam Courdoson<br>
Loïc Siret<br>
Louis Maillard<br>
Mathéo Joseph<br>
Michel Schmit<br>
Mingrui Zhang<br>
Mohamed Chibani<br>
Mohamed Amine Younes Bouacida<br>
@ -57,6 +63,7 @@ Rayan Osseiran<br>
Romain Bertozzi<br>
Saher Azer<br>
Sébastien Blin<br>
Seva Ivanov<br>
Silbino Gonçalves Matado<br>
Simon Désaulniers<br>
Simon Zeni<br>
@ -64,9 +71,21 @@ Stepan Salenikovich<br>
Thibault Wittemberg<br>
Thomas Ballasi<br>
Trevor Tabah<br>
Vitalii Nikitchyn<br>
Vsevolod Ivanov<br>
Xavier Jouslin de Noray<br>
Yang Wang<br></p>
<h4 align="left"><span style="font-weight:600"> Artwork by</span></h4>
Yang Wang<br>
</p>
<h4 align="left"><span style="font-weight:600"> %3</span></h4>
<p>Charlotte Hoffmann<br>
Marianne Forget<br></p>
<h4 align="left"><span style="font-weight:600"> %4</span></h4>
<p>Dorina Mosku<br>
Cabrel Tambue<br>
Loïc Bogino<br></p>
<h4 align="left"><span style="font-weight:600"> %5</span></h4>
<p>Anna<br>
Elys<br>
VeroJeanLuc<br>
</p>
<p>%6</p>

View File

@ -145,6 +145,16 @@ ApplicationWindow {
LRCInstance.selectConversation(convUid);
}
}
ListElement {
label: "Account ID"
type: "combobox"
getDataModel: () => AccountListModel
displayRole: AccountList.Username
onIndexChanged: function(model, index) {
const accountId = JamiQmlUtils.getModelData(model, index, AccountList.ID);
LRCInstance.currentAccountId = accountId;
}
}
ListElement {
label: "Force local preview"
type: "checkbox"

View File

@ -29,6 +29,35 @@ AccountListModel::AccountListModel(LRCInstance* instance, QObject* parent)
: AbstractListModelBase(parent)
{
lrcInstance_ = instance;
// Avoid resetting/redrawing the model when the account status changes.
QObject::connect(&lrcInstance_->accountModel(),
&AccountModel::accountStatusChanged,
this,
[&](const QString& accountId) {
auto accountList = lrcInstance_->accountModel().getAccountList();
auto index = accountList.indexOf(accountId);
if (index != -1) {
QModelIndex modelIndex = QAbstractListModel::index(index, 0);
Q_EMIT dataChanged(modelIndex, modelIndex /*, ALL ROLES */);
}
});
// If there's a reorder, it's reasonable to reset the model for simplicity, instead
// of computing the difference. The same goes for accounts being added and removed.
// These operations will only occur when the list is hidden, unless dbus is used while
// the list is visible.
QObject::connect(&lrcInstance_->accountModel(),
&AccountModel::accountsReordered,
this,
&AccountListModel::reset);
QObject::connect(&lrcInstance_->accountModel(),
&AccountModel::accountAdded,
this,
&AccountListModel::reset);
QObject::connect(&lrcInstance_->accountModel(),
&AccountModel::accountRemoved,
this,
&AccountListModel::reset);
}
int
@ -91,6 +120,7 @@ AccountListModel::roleNames() const
void
AccountListModel::reset()
{
// Used to invalidate proxy models.
beginResetModel();
endResetModel();
}

View File

@ -57,7 +57,6 @@ Popup {
id: container
property color color: JamiTheme.secondaryBackgroundColor
anchors.centerIn: parent
leftPadding: popupMargins
bottomPadding: action1.visible || action2.visible ? 10 :popupMargins

View File

@ -51,7 +51,7 @@ SBSMessageBase {
bubble.border.color: CurrentConversation.color
bubble.border.width: root.isActive ? 1.5 : 0
bubble.color: JamiTheme.messageInBgColor
bubble.opacity: 0.6
bubble.opacity: 1
Connections {
target: CurrentConversation
@ -113,7 +113,7 @@ SBSMessageBase {
}
TextEdit {
Text {
id: callLabel
objectName: "callLabel"
@ -141,19 +141,19 @@ SBSMessageBase {
}
JoinCallButton {
id: joinCallInAudio
objectName: "joinCallInAudio"
id: joinCallWithAudio
objectName: "joinCallWithAudio"
Layout.topMargin: 4
Layout.bottomMargin: 4
text: JamiStrings.joinInAudio
text: JamiStrings.joinWithAudio
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId, true)
}
JoinCallButton {
id: joinCallInVideo
objectName: "joinCallInVideo"
text: JamiStrings.joinInVideo
id: joinCallWithVideo
objectName: "joinCallWithVideo"
text: JamiStrings.joinWithVideo
Layout.topMargin: 4
Layout.bottomMargin: 4

View File

@ -40,9 +40,18 @@ Loader {
property int seq: MsgSeq.single
property string author: Author
property string body: Body
property int transferStatus: Status
property var tid: TID
property int transferStatus: TransferStatus
onTidChanged: {
if (tid === "") {
sourceComponent = deletedMsgComp
}
}
onTransferStatusChanged: {
if (transferStatus === Interaction.Status.TRANSFER_FINISHED) {
if (tid === "") {
sourceComponent = deletedMsgComp
return;
} else if (transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED) {
mediaInfo = MessagesAdapter.getMediaInfo(root.body);
if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE) {
sourceComponent = localMediaMsgComp;
@ -58,6 +67,54 @@ Loader {
Behavior on opacity { NumberAnimation { duration: 100 } }
onLoaded: opacity = 1
Component {
id: deletedMsgComp
SBSMessageBase {
id: deletedItem
isOutgoing: Author === CurrentAccount.uri
showTime: root.showTime
seq: root.seq
author: Author
readers: Readers
timestamp: root.timestamp
formattedTime: root.formattedTime
formattedDay: root.formattedTime
extraHeight: 0
textContentWidth: textEditId.width
textContentHeight: textEditId.height
innerContent.children: [
TextEdit {
id: textEditId
anchors.right: isOutgoing ? parent.right : undefined
anchors.rightMargin: isOutgoing ? timeWidth : 0
bottomPadding: 6
topPadding: 6
leftPadding: 10
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMedia ;
horizontalAlignment: Text.AlignLeft
width: Math.min((2 / 3) * parent.width, implicitWidth + 18, innerContent.width - senderMargin + 18)
font.pointSize: JamiTheme.smallFontSize
font.hintingPreference: Font.PreferNoHinting
renderType: Text.NativeRendering
textFormat: Text.RichText
clip: true
readOnly: true
color: getBaseColor()
opacity: 0.5
function getBaseColor() {
bubble.isDeleted = true
return UtilsAdapter.luma(bubble.color) ? "white" : "dark"
}
}
]
}
}
Component {
id: dataTransferMsgComp
@ -66,7 +123,7 @@ Loader {
transferId: Id
property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
property bool canOpen: root.transferStatus === Interaction.Status.TRANSFER_FINISHED || isOutgoing
property bool canOpen: root.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
property real maxMsgWidth: root.width - senderMargin -
2 * hPadding - avatarBlockWidth
- buttonsLoader.width - 24 - 6 - 24
@ -112,18 +169,18 @@ Loader {
sourceComponent: {
switch (root.transferStatus) {
case Interaction.Status.TRANSFER_CREATED:
case Interaction.Status.TRANSFER_FINISHED:
case Interaction.TransferStatus.TRANSFER_CREATED:
case Interaction.TransferStatus.TRANSFER_FINISHED:
iconSource = JamiResources.link_black_24dp_svg
return terminatedComp
case Interaction.Status.TRANSFER_CANCELED:
case Interaction.Status.TRANSFER_ERROR:
case Interaction.Status.TRANSFER_UNJOINABLE_PEER:
case Interaction.Status.TRANSFER_TIMEOUT_EXPIRED:
case Interaction.Status.TRANSFER_AWAITING_HOST:
case Interaction.TransferStatus.TRANSFER_CANCELED:
case Interaction.TransferStatus.TRANSFER_ERROR:
case Interaction.TransferStatus.TRANSFER_UNJOINABLE_PEER:
case Interaction.TransferStatus.TRANSFER_TIMEOUT_EXPIRED:
case Interaction.TransferStatus.TRANSFER_AWAITING_HOST:
iconSource = JamiResources.download_black_24dp_svg
return optionsComp
case Interaction.Status.TRANSFER_ONGOING:
case Interaction.TransferStatus.TRANSFER_ONGOING:
iconSource = JamiResources.close_black_24dp_svg
return optionsComp
default:
@ -158,7 +215,7 @@ Loader {
normalColor: JamiTheme.chatviewBgColor
imageColor: JamiTheme.chatviewButtonColor
onClicked: {
if (root.transferStatus === Interaction.Status.TRANSFER_ONGOING) {
if (root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
return MessagesAdapter.cancelFile(transferId)
} else {
return MessagesAdapter.acceptFile(transferId)
@ -191,7 +248,7 @@ Loader {
onClicked: function (mouse) {
if (canOpen) {
dataTransferItem.hoveredLink = UtilsAdapter.urlFromLocalPath(location)
Qt.openUrlExternally(new Url(dataTransferItem.hoveredLink))
Qt.openUrlExternally(new URL(dataTransferItem.hoveredLink))
} else {
dataTransferItem.hoveredLink = ""
}
@ -223,11 +280,11 @@ Loader {
: JamiTheme.chatviewTextColorDark
}
}
}
,ProgressBar {
},
ProgressBar {
id: progressBar
visible: root.transferStatus === Interaction.Status.TRANSFER_ONGOING
visible: root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
height: visible * implicitHeight
value: transferStats.progress / transferStats.totalSize
width: transferItem.width

View File

@ -73,7 +73,7 @@ BaseModalDialog {
Layout.bottomMargin: 5
color: JamiTheme.textColor
text: JamiStrings.confirmDeleteQuestion
text: JamiStrings.confirmDeleteAccount
font.pointSize: JamiTheme.textFontSize
font.kerning: true

View File

@ -121,10 +121,7 @@ Item {
font.pixelSize : text.length > 16 ? JamiTheme.jamiIdSmallFontSize : JamiTheme.bigFontSize
property string registeredName: CurrentAccount.registeredName
property string infohash: CurrentAccount.uri
text: registeredName ? registeredName : infohash
onRegisteredNameChanged: {
text = registeredName ? registeredName : infohash
}
text: (btnId.clicked && registeredName) ? registeredName : infohash
}
}
}
@ -154,7 +151,7 @@ Item {
JamiIdControlButton {
id: btnEdit
anchors.leftMargin: JamiTheme.pushButtonMargins
visible: CurrentAccount.registeredName === ""
visible: CurrentAccount.registeredName === "" && CurrentAccount.enabled
imageColor: enabled ? JamiTheme.tintedBlue : JamiTheme.buttonTintedBlack
border.color: usernameTextEdit.editMode ? jamiId.contentColor : "transparent"
enabled: {
@ -231,11 +228,9 @@ Item {
toolTipText: JamiStrings.identifierURI
onClicked: {
if (clicked) {
usernameLabel.text = Qt.binding(function() {return CurrentAccount.uri} );
usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.uri} );
btnId.toolTipText = JamiStrings.identifierRegisterName;
} else {
usernameLabel.text = Qt.binding(function() {return CurrentAccount.registeredName} );
usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.registeredName} );
btnId.toolTipText = JamiStrings.identifierURI;
}

View File

@ -86,7 +86,7 @@ SplitView {
// size (4 pixels). This is done to make it easier to grab small scroll-view handles that are
// adjacent to the SplitView handle. Note: vertically oriented handles are not offset.
readonly property real extraHandleSize: 4
readonly property real handleXPosition: !isRTL ? 0 : -extraHandleSize
readonly property real handleXPosition: !UtilsAdapter.isRTL ? 0 : -extraHandleSize
readonly property real handleSize: handleRoot.defaultSize + extraHandleSize
x: control.orientation === Qt.Horizontal ? handleXPosition : 0

View File

@ -164,7 +164,7 @@ BaseModalDialog {
appWindow,
"commoncomponents/JamiFileDialog.qml",
{
title: JamiStrings.selectAvatarImage,
title: JamiStrings.selectProfilePicture,
fileMode: JamiFileDialog.OpenFile,
folder: StandardPaths.writableLocation(
StandardPaths.PicturesLocation),

View File

@ -278,7 +278,7 @@ Control {
anchors.right: isOutgoing ? bubble.left : undefined
anchors.left: !isOutgoing ? bubble.right : undefined
width: JamiTheme.emojiPushButtonSize * 2
width: JamiTheme.emojiPushButtonSize * 4
height: JamiTheme.emojiPushButtonSize
anchors.verticalCenter: bubble.verticalCenter
@ -299,24 +299,24 @@ Control {
anchors.verticalCenter: parent.verticalCenter
anchors.right: isOutgoing ? optionButtonItem.right : undefined
anchors.left: !isOutgoing ? optionButtonItem.left : undefined
visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered)
visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || share.hovered || bgHandler.hovered)
source: JamiResources.more_vert_24dp_svg
width: optionButtonItem.width / 2
width: optionButtonItem.width / 4
height: optionButtonItem.height
circled: false
property bool isOpen: false
property var obj: undefined
function bind() {
function setBindings() {
more.isOpen = false;
visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || bgHandler.hovered));
visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || share.hovered || bgHandler.hovered));
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
}
onClicked: {
if (more.isOpen) {
more.bind();
more.setBindings();
obj.close();
} else {
var component = Qt.createComponent("qrc:/commoncomponents/ShowMoreMenu.qml");
@ -332,7 +332,7 @@ Control {
});
obj.open();
more.isOpen = true;
visible = true;
visible = true; // the button stay visible as long the popup is open even if it's not hovered
imageColor = JamiTheme.chatViewFooterImgHoverColor;
normalColor = JamiTheme.hoveredButtonColor;
}
@ -348,19 +348,75 @@ Control {
normalColor: JamiTheme.primaryBackgroundColor
toolTipText: JamiStrings.reply
source: JamiResources.reply_black_24dp_svg
width: optionButtonItem.width / 2
width: optionButtonItem.width / 4
height: optionButtonItem.height
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 5
anchors.right: isOutgoing ? more.left : undefined
anchors.left: !isOutgoing ? more.right : undefined
visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || bgHandler.hovered)
visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || share.hovered || bgHandler.hovered)
onClicked: {
MessagesAdapter.editId = "";
MessagesAdapter.replyToId = Id;
}
}
PushButton {
id: share
objectName: "share"
circled: false
imageColor: hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor
normalColor: JamiTheme.primaryBackgroundColor
toolTipText: JamiStrings.share
source: JamiResources.share_black_24dp_svg
width: optionButtonItem.width / 4
height: optionButtonItem.height
anchors.verticalCenter: parent.verticalCenter
anchors.rightMargin: 5
anchors.right: isOutgoing ? reply.left : undefined
anchors.left: !isOutgoing ? reply.right : undefined
visible: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || more.hovered || bgHandler.hovered)
property bool isOpen: false
property var obj: undefined
function setBindings() { // when the popup is closed, setBindings is called to reset the icon's visual settings
share.isOpen = false;
visible = Qt.binding(() => CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || reply.hovered || more.hovered || bgHandler.hovered));
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
}
onClicked: {
if (share.isOpen) {
share.setBindings();
obj.close();
} else {
if (root.type === 2 || root.type === 5) {
// 2=TEXT and 5=DATA_TRANSFER (any kind of file) defined in interaction.h
var component = Qt.createComponent("qrc:/commoncomponents/ShareMessageMenu.qml");
obj = component.createObject(share, {
"isOutgoing": isOutgoing,
"msgId": Id,
"msgBody": Body,
"type": root.type,
"transferName": TransferName,
"msgBubble": bubble,
"listView": listView,
"author": UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author),
"formattedTime": formattedTime
});
obj.open();
share.isOpen = true;
visible = true; // the PushButton stay visible as long the popup is open even if it's not hovered
imageColor = JamiTheme.chatViewFooterImgHoverColor;
normalColor = JamiTheme.hoveredButtonColor;
}
}
}
}
}
MessageBubble {
@ -382,7 +438,7 @@ Control {
property bool bubbleHovered
property string imgSource
width: (root.type === Interaction.Type.TEXT ? root.textContentWidth + (IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth) : innerContent.childrenRect.width)
width: (root.type === Interaction.Type.TEXT || isDeleted ? root.textContentWidth + (IsEmojiOnly || root.bigMsg ? 0 : root.timeWidth + root.editedWidth) : innerContent.childrenRect.width)
height: innerContent.childrenRect.height + (visible ? root.extraHeight : 0) + (root.bigMsg ? 15 : 0)
HoverHandler {
@ -466,6 +522,11 @@ Control {
MessagesAdapter.openUrl(root.hoveredLink);
}
}
onDoubleClicked: {
MessagesAdapter.editId = "";
MessagesAdapter.replyToId = Id;
}
property bool bubbleHovered: containsMouse || textHovered
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
}

View File

@ -0,0 +1,264 @@
/*
* Copyright (C) 2024 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import net.jami.Constants 1.1
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import SortFilterProxyModel 0.2
import "contextmenu"
import "../commoncomponents"
import "../mainview/components"
BaseContextMenu {
id: mainMenu
height: 330 + Math.min(messageInput.height, textareaMaxHeight)
width: 400
required property string msgId
required property string msgBody
required property bool isOutgoing
required property int type
required property string transferName
required property Item msgBubble
required property ListView listView
required property string author
required property string formattedTime
property var selectedUids: []
property string shareToId: msgId
property string fileLink: msgBody
property int textareaMaxHeight: 350
function xPosition(width) {
// Use the width at function scope to retrigger property evaluation.
const listViewWidth = listView.width;
const parentX = parent.x;
if (isOutgoing) {
return parentX - width - 20;
} else {
return parentX + 20;
}
}
x: xPosition(width)
y: parent.y
function xPositionProvider(width) {
// Use the width at function scope to retrigger property evaluation.
const listViewWidth = listView.width;
if (isOutgoing) {
return -5 - width;
} else {
const rightMargin = listViewWidth - (msgBubble.x + width);
return width > rightMargin + 35 ? -5 - width : 35;
}
}
function yPositionProvider(height) {
const topOffset = msgBubble.mapToItem(listView, 0, 0).y;
const listViewHeight = listView.height;
const bottomMargin = listViewHeight - height - topOffset;
if (bottomMargin < 0 || (topOffset < 0 && topOffset + height > 0)) {
return 30 - height;
} else {
return 0;
}
}
SortFilterProxyModel {
id: shareConvProxyModel
sourceModel: ConversationsAdapter.convListProxyModel
filterCaseSensitivity: Qt.CaseInsensitive
}
Rectangle {
id: header
width: parent.width
height: 0
}
Rectangle {
id: sendButton
height: JamiTheme.chatViewFooterButtonSize
anchors.right: parent.right
anchors.rightMargin: 10
anchors.topMargin: 10
anchors.top: header.bottom
color: JamiTheme.transparentColor
PushButton {
id: shareMessageButton
height: JamiTheme.chatViewFooterButtonSize
width: scale * JamiTheme.chatViewFooterButtonSize
anchors.right: parent.right
visible: true
radius: JamiTheme.chatViewFooterButtonRadius
preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
imageContainerWidth: 25
imageContainerHeight: 25
toolTipText: JamiStrings.share
mirror: UtilsAdapter.isRTL
source: JamiResources.send_black_24dp_svg
hoverEnabled: enabled
normalColor: enabled ? JamiTheme.chatViewFooterSendButtonColor : JamiTheme.chatViewFooterSendButtonDisableColor
imageColor: enabled ? JamiTheme.chatViewFooterSendButtonImgColor : JamiTheme.chatViewFooterSendButtonImgColorDisable
hoveredColor: JamiTheme.buttonTintedBlueHovered
pressedColor: hoveredColor
opacity: 1
scale: opacity
MouseArea {
anchors.fill: parent
onClicked: {
var selectedContacts = mainMenu.selectedUids;
var hasText = messageInput.text && selectedContacts.length > 0;
function sendMessageOrFile(uid) {
if (Type === 2) {
// 2=TEXT and 5=DATA_TRANSFER (any kind of file) defined in interaction.h
MessagesAdapter.sendMessageToUid(msgBody, uid);
} else {
MessagesAdapter.sendFileToUid(fileLink, uid);
}
}
for (var i = 0; i < selectedContacts.length; i++) {
var uid = selectedContacts[i];
sendMessageOrFile(uid);
if (hasText) {
MessagesAdapter.sendMessageToUid(messageInput.text, uid);
}
}
messageInput.text = "";
mainMenu.destroy();
}
}
}
}
Rectangle {
id: searchConv
height: 300
width: parent.width
anchors.top: header.bottom
anchors.topMargin: 10
property int type: ContactList.CONVERSATION
color: JamiTheme.transparentColor
ColumnLayout {
id: contactPickerPopupRectColumnLayout
anchors.fill: parent
Searchbar {
id: contactPickerContactSearchBar
width: parent.width - 20 - JamiTheme.chatViewFooterButtonSize
anchors.leftMargin: 10
Layout.preferredHeight: 35
placeHolderText: "Share to..."
onSearchBarTextChanged: function (text) {
shareConvProxyModel.filterRole = shareConvProxyModel.roleForName("Title");
shareConvProxyModel.filterPattern = text;
}
}
JamiListView {
id: contactPickerListView
Layout.alignment: Qt.AlignCenter
Layout.fillWidth: true
Layout.preferredHeight: 255
Layout.bottomMargin: JamiTheme.preferredMarginSize
Layout.topMargin: 5
model: shareConvProxyModel
delegate: ConversationPickerItemDelegate {
id: conversationDelegate
}
}
}
}
Flickable {
id: messageInputContainer
height: Math.min(contentHeight, mainMenu.textareaMaxHeight)
width: parent.width - 20
contentHeight: messageInput.height
anchors.left: parent.left
anchors.leftMargin: 10
anchors.rightMargin: 10
anchors.topMargin: 10
anchors.top: searchConv.bottom
flickableDirection: Flickable.VerticalFlick
clip: true
ScrollBar.vertical: JamiScrollBar {
policy: ScrollBar.AsNeeded
}
onContentHeightChanged: {
if (contentHeight > height) {
contentY = contentHeight - height;
}
}
TextArea {
id: messageInput
height: contentHeight + 12
width: parent.width
placeholderText: "Add a comment"
placeholderTextColor: JamiTheme.messageBarPlaceholderTextColor
font.pointSize: JamiTheme.textFontSize + 2
color: JamiTheme.textColor
wrapMode: Text.WordWrap
background: Rectangle {
color: JamiTheme.transparentColor
radius: 5
border.color: JamiTheme.chatViewFooterRectangleBorderColor
border.width: 2
}
}
}
// destroy() and setBindings() are needed to unselect the share icon from SBSMessageBase
onAboutToHide: {
mainMenu.destroy();
}
Component.onDestruction: {
parent.setBindings();
}
}

View File

@ -153,7 +153,7 @@ BaseContextMenu {
GeneralMenuItem {
id: removeLocally
canTrigger: type === Interaction.Type.DATA_TRANSFER && Status === Interaction.Status.TRANSFER_FINISHED
canTrigger: type === Interaction.Type.DATA_TRANSFER && TransferStatus === Interaction.TransferStatus.TRANSFER_FINISHED
iconSource: JamiResources.trash_black_24dp_svg
itemName: JamiStrings.removeLocally
onClicked: {
@ -175,7 +175,7 @@ BaseContextMenu {
GeneralMenuItem {
id: deleteMessage
canTrigger: root.isOutgoing && type === Interaction.Type.TEXT
canTrigger: root.isOutgoing && (type === Interaction.Type.TEXT || type === Interaction.Type.DATA_TRANSFER)
iconSource: JamiResources.delete_svg
itemName: JamiStrings.deleteMessage
onClicked: {
@ -198,11 +198,13 @@ BaseContextMenu {
root.loadMenuItems(menuItems);
}
// destroy() and setBindings() are needed to unselect the share icon from SBSMessageBase
onAboutToHide: {
root.destroy();
}
Component.onDestruction: {
parent.bind();
parent.setBindings();
}
}

View File

@ -143,7 +143,7 @@ ConversationListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex& s
}
} else {
Q_FOREACH (const auto& filter, toFilter)
if (rx.match(filter).hasMatch()) {
if (rx.isValid() && rx.match(filter).hasMatch()) {
match = true;
break;
}

View File

@ -125,7 +125,11 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
if (interaction.type == interaction::Type::UPDATE_PROFILE) {
lastInteractionBody = interaction::getProfileUpdatedString();
} else if (interaction.type == interaction::Type::DATA_TRANSFER) {
lastInteractionBody = interaction.commit.value("displayName");
if (interaction.commit.value("tid").isEmpty()) {
lastInteractionBody = tr("Deleted media");
} else {
lastInteractionBody = interaction.commit.value("displayName");
}
} else if (interaction.type == lrc::api::interaction::Type::CALL) {
const auto isOutgoing = interaction.authorUri == accInfo.profileInfo.uri;
lastInteractionBody = interaction::getCallInteractionString(isOutgoing, interaction);

2
src/app/js/.clang-format Normal file
View File

@ -0,0 +1,2 @@
Language: JavaScript
BasedOnStyle: Google

View File

@ -0,0 +1,279 @@
/*
* Copyright (C) 2020-2024 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// This file contains the functions that allow the user to format the text in
// the message bar by adding bold, italic, underline, strikethrough, ordered
// list, and unordered list styles.
function isStyle(ta, text, char1, char2) {
const start = ta.selectionStart;
const end = ta.selectionEnd;
if (char1 === '**') {
return isStarStyle(ta, text, 'bold');
}
if (char1 === '*') {
return isStarStyle(ta, text, 'italic');
}
const selectedText = text.substring(start - char1.length, end + char2.length);
return (selectedText.startsWith(char1) && selectedText.endsWith(char2));
}
function isStarStyle(ta, text, type) {
const selectionStart = ta.selectionStart;
const selectionEnd = ta.selectionEnd;
let start = selectionStart;
while (start > 0 && text[start - 1] === '*') {
start--;
}
let end = selectionEnd;
while (end < text.length && text[end] === '*') {
end++;
}
const starCount = Math.min(selectionStart - start, end - selectionEnd);
if (type === 'italic') {
return starCount === 1 || starCount === 3;
}
return starCount === 2 || starCount === 3;
}
function addStyle(ta, text, char1, char2) {
const start = ta.selectionStart;
const end = ta.selectionEnd;
// Get the selected text with markdown effect
var selectedText = text.substring(start - char1.length, end + char2.length);
// If the selected text is already formatted with the given characters, remove
// them
if (isStyle(ta, text, char1, char2)) {
selectedText = text.substring(start, end);
ta.text = text.substring(0, start - char1.length) + selectedText +
text.substring(end + char2.length);
ta.selectText(start - char1.length, end - char1.length);
return;
}
// Otherwise, add the formatting characters to the selected text
ta.text = text.substring(0, start) + char1 + text.substring(start, end) +
char2 + text.substring(end);
ta.selectText(start + char1.length, end + char1.length);
}
function isPrefixSyle(ta, message, delimiter, isOrderedList) {
const selectionStart = ta.selectionStart;
const selectionEnd = ta.selectionEnd;
// Represents all the selected lines
var multilineSelection;
var newPrefix;
var newSuffix;
var newStartPos;
var newEndPos;
function nextIndexOf(text, char1, startPos) {
return text.indexOf(char1, startPos + 1);
}
// Get the previous index of the multilineSelection text
if (message[selectionStart] === '\n')
newStartPos = message.lastIndexOf('\n', selectionStart - 1);
else
newStartPos = message.lastIndexOf('\n', selectionStart);
// Get the next index of the multilineSelection text
if (message[selectionEnd] === '\n' || message[selectionEnd] === undefined)
newEndPos = selectionEnd;
else
newEndPos = nextIndexOf(message, '\n', selectionEnd);
// If the text is empty
if (newStartPos === -1) newStartPos = 0;
newPrefix = message.slice(0, newStartPos);
multilineSelection = message.slice(newStartPos, newEndPos);
newSuffix = message.slice(newEndPos);
var isFirstLineSelected =
!multilineSelection.startsWith('\n') || newPrefix === '';
var getDelimiter_counter = 1;
function getDelimiter() {
return `${getDelimiter_counter++}. `;
}
function getHasCurrentMarkdown() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity =
(multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) ||
[]).length;
if (newLinesWithDelimitersQuantity === linesQuantity &&
!isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity &&
multilineSelection.startsWith(delimiter);
}
function getHasCurrentMarkdownBullet() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity =
(multilineSelection.match(/\n\d+\. /g) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity &&
!isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity &&
(/^\d\. /).test(multilineSelection);
}
var newValue;
var newStart;
var newEnd;
var count;
var startPos;
var multilineSelectionLength;
if (!isOrderedList) {
return getHasCurrentMarkdown();
} else {
return getHasCurrentMarkdownBullet();
}
}
function addPrefixStyle(ta, message, delimiter, isOrderedList) {
const selectionStart = ta.selectionStart;
const selectionEnd = ta.selectionEnd;
// Represents all the selected lines
var multilineSelection;
var newPrefix;
var newSuffix;
var newStartPos;
var newEndPos;
function nextIndexOf(text, char1, startPos) {
return text.indexOf(char1, startPos + 1);
}
// Get the previous index of the multilineSelection text
if (message[selectionStart] === '\n')
newStartPos = message.lastIndexOf('\n', selectionStart - 1);
else
newStartPos = message.lastIndexOf('\n', selectionStart);
// Get the next index of the multilineSelection text
if (message[selectionEnd] === '\n' || message[selectionEnd] === undefined)
newEndPos = selectionEnd;
else
newEndPos = nextIndexOf(message, '\n', selectionEnd);
// If the text is empty
if (newStartPos === -1) newStartPos = 0;
newPrefix = message.slice(0, newStartPos);
multilineSelection = message.slice(newStartPos, newEndPos);
newSuffix = message.slice(newEndPos);
var isFirstLineSelected =
!multilineSelection.startsWith('\n') || newPrefix === '';
var getDelimiter_counter = 1;
function getDelimiter() {
return `${getDelimiter_counter++}. `;
}
function getHasCurrentMarkdown() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity =
(multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) ||
[]).length;
if (newLinesWithDelimitersQuantity === linesQuantity &&
!isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity &&
multilineSelection.startsWith(delimiter);
}
function getHasCurrentMarkdownBullet() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity =
(multilineSelection.match(/\n\d+\. /g) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity &&
!isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity &&
(/^\d\. /).test(multilineSelection);
}
var newValue;
var newStart;
var newEnd;
var count;
var startPos;
var multilineSelectionLength;
if (!isOrderedList) {
if (getHasCurrentMarkdown()) {
// Clear first line from delimiter
if (isFirstLineSelected)
multilineSelection = multilineSelection.slice(delimiter.length);
newValue = newPrefix +
multilineSelection.replace(new RegExp(`\n${delimiter}`, 'g'), '\n') +
newSuffix;
count = 0;
if (isFirstLineSelected) count++;
count += (multilineSelection.match(/\n/g) || []).length;
newStart = Math.max(selectionStart - delimiter.length, 0);
newEnd = Math.max(selectionEnd - (delimiter.length * count), 0);
} else {
newValue = newPrefix +
multilineSelection.replace(/\n/g, `\n${delimiter}`) + newSuffix;
count = 0;
if (isFirstLineSelected) {
newValue = delimiter + newValue;
count++;
}
count += (multilineSelection.match(new RegExp('\\n', 'g')) || []).length;
newStart = selectionStart + delimiter.length;
newEnd = selectionEnd + (delimiter.length * count);
}
} else if (getHasCurrentMarkdownBullet()) {
if (message[selectionStart] === '\n')
startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
else
startPos = message.lastIndexOf('\n', selectionStart) + 1;
newStart = startPos;
multilineSelection = multilineSelection.replace(/^\d+\.\s/gm, '');
newValue = newPrefix + multilineSelection + newSuffix;
multilineSelectionLength = multilineSelection.length;
// If the first line is not selected, we need to remove the first "\n" of
// multilineSelection
if (newStart) multilineSelectionLength = multilineSelection.length - 1;
newEnd = Math.max(newStart + multilineSelectionLength, 0);
} else {
if (message[selectionStart] === '\n')
startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
else
startPos = message.lastIndexOf('\n', selectionStart) + 1;
newStart = startPos;
// If no text is selected
if (selectionStart === selectionEnd) newStart = newStart + 3;
if (isFirstLineSelected)
multilineSelection = getDelimiter() + multilineSelection;
const selectionArr = Array.from(multilineSelection);
for (var i = 0; i < selectionArr.length; i++) {
if (selectionArr[i] === '\n') selectionArr[i] = `\n${getDelimiter()}`;
}
multilineSelection = selectionArr.join('');
newValue = newPrefix + multilineSelection + newSuffix;
multilineSelectionLength = multilineSelection.length;
// If the first line is not selected, we meed to remove the first "\n" of
// multilineSelection
if (startPos) multilineSelectionLength = multilineSelection.length - 1;
newEnd = Math.max(startPos + multilineSelectionLength, 0);
}
ta.text = newValue;
ta.selectText(newStart, newEnd);
}

View File

@ -43,9 +43,8 @@ LRCInstance::LRCInstance(const QString& updateUrl,
muteDaemon_ = muteDaemon;
threadPool_->setMaxThreadCount(1);
connect(this, &LRCInstance::currentAccountIdChanged, [this] {
// save to config, editing the accountlistmodel's underlying data
accountModel().setTopAccount(currentAccountId_);
// Update the current account when the account list changes.
connect(&accountModel(), &AccountModel::accountsReordered, this, [this] {
Q_EMIT accountListChanged();
profile::Info profileInfo;
@ -62,6 +61,11 @@ LRCInstance::LRCInstance(const QString& updateUrl,
set_currentAccountAvatarSet(!profileInfo.avatar.isEmpty());
});
connect(this, &LRCInstance::currentAccountIdChanged, [this] {
// This will trigger `AccountModel::accountsReordered`.
accountModel().setTopAccount(currentAccountId_);
});
connect(&accountModel(), &AccountModel::profileUpdated, this, [this](const QString& id) {
if (id != currentAccountId_)
return;

View File

@ -22,6 +22,7 @@ import Qt5Compat.GraphicalEffects
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Helpers 1.1
import "../../commoncomponents"
BaseModalDialog {
@ -63,23 +64,21 @@ BaseModalDialog {
source: JamiTheme.darkTheme ? JamiResources.logo_jami_standard_coul_white_svg : JamiResources.logo_jami_standard_coul_svg
}
Rectangle {
color: JamiTheme.backgroundRectangleColor
Control {
Layout.fillHeight: true
Layout.fillWidth: true
radius: 5
ColumnLayout {
id: sloganLayout
anchors.verticalCenter: parent.verticalCenter
background: Rectangle {
color: JamiTheme.backgroundRectangleColor
radius: 5
}
padding: 10
contentItem: ColumnLayout {
spacing: 4
TextEdit {
id: jamiSlogansText
Layout.alignment: Qt.AlignLeft
Layout.margins: 10
Layout.bottomMargin: 0
wrapMode: Text.WordWrap
font.pixelSize: JamiTheme.menuFontSize
@ -100,23 +99,18 @@ BaseModalDialog {
}
}
TextEdit {
id: jamiVersionText
Layout.alignment: Qt.AlignLeft
Layout.margins: 10
Layout.topMargin: 0
Layout.maximumWidth: JamiTheme.preferredDialogWidth - 2*JamiTheme.preferredMarginSize
font.pixelSize: JamiTheme.textFontSize
padding: 0
text: JamiStrings.version + ": " + UtilsAdapter.getVersionStr()
readonly property bool isBeta: AppVersionManager.isCurrentVersionBeta()
text: JamiStrings.buildID + ": " + UtilsAdapter.getBuildIDStr() + "\n" +
JamiStrings.version + ": " + (isBeta ? "(Beta) " : "") + UtilsAdapter.getVersionStr()
selectByMouse: true
readOnly: true
color: JamiTheme.faddedFontColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
}

View File

@ -34,24 +34,6 @@ Label {
property bool inSettings: viewCoordinator.currentViewName === "SettingsView"
// TODO: remove these refresh hacks use QAbstractItemModels correctly
Connections {
target: AccountAdapter
function onAccountStatusChanged(accountId) {
AccountListModel.reset();
}
}
Connections {
target: LRCInstance
function onAccountListChanged() {
root.update();
AccountListModel.reset();
}
}
function togglePopup() {
if (root.popup.opened) {
root.popup.close();

View File

@ -60,23 +60,6 @@ Popup {
property bool inSettings: viewCoordinator.currentViewName === "SettingsView"
// TODO: remove these refresh hacks use QAbstractItemModels correctly
Connections {
target: AccountAdapter
function onAccountStatusChanged(accountId) {
AccountListModel.reset();
}
}
Connections {
target: LRCInstance
function onAccountListChanged() {
AccountListModel.reset();
}
}
RowLayout {
id: mainLayout
anchors.fill: parent
@ -257,11 +240,6 @@ Popup {
color: JamiTheme.smartListHoveredColor
}
// fake footer item as workaround for Qt 5.15 bug
// https://bugreports.qt.io/browse/QTBUG-85302
// don't use the clip trick and footer item overlay
// explained here https://stackoverflow.com/a/64625149
// as it causes other complexities in handling the drop shadow
ItemDelegate {
id: addAccountItem

View File

@ -42,7 +42,7 @@ Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 35
placeHolderText: JamiStrings.addParticipant
placeHolderText: JamiStrings.inviteMember
onSearchBarTextChanged: function(text){
ContactAdapter.setSearchFilter(text);

View File

@ -315,7 +315,7 @@ Control {
checkable: true
icon.source: checked ? JamiResources.videocam_off_24dp_svg : JamiResources.videocam_24dp_svg
icon.color: checked ? "red" : "white"
text: !checked ? JamiStrings.muteCamera : JamiStrings.unmuteCamera
text: !checked ? JamiStrings.stopCamera : JamiStrings.startCamera
checked: !CurrentCall.isCapturing
property var menuAction: videoInputMenuAction
enabled: CurrentAccount.videoEnabled_Video
@ -339,7 +339,7 @@ Control {
onTriggered: root.addToConferenceClicked()
icon.source: JamiResources.add_people_black_24dp_svg
icon.color: "white"
text: JamiStrings.addParticipants
text: JamiStrings.inviteMembers
enabled: CurrentCall.isModerator && !CurrentCall.isSIP
onEnabledChanged: CallOverlayModel.setEnabled(this, addPersonAction.enabled)
},
@ -437,7 +437,7 @@ Control {
onTriggered: root.pluginsClicked()
icon.source: JamiResources.plugins_24dp_svg
icon.color: "white"
text: JamiStrings.viewPlugin
text: JamiStrings.viewExtension
enabled: PluginAdapter.callMediaHandlersListCount
onEnabledChanged: CallOverlayModel.setEnabled(this, pluginsAction.enabled)
},

View File

@ -133,6 +133,10 @@ Rectangle {
target: CurrentConversation
function onIdChanged() {
console.log(CurrentConversation.id);
if (width < JamiTheme.mainViewMinWidth + extrasPanel.width) {
extrasPanel.visible = false;
}
if (!chatViewHeader.interactionButtonsVisibility)
extrasPanel.closePanel();
}

View File

@ -88,7 +88,7 @@ Rectangle {
mirror: UtilsAdapter.isRTL
source: JamiResources.back_24dp_svg
toolTipText: CurrentConversation.inCall ? JamiStrings.backCall : JamiStrings.hideChat
toolTipText: CurrentConversation.inCall ? JamiStrings.returnToCall : JamiStrings.hideChat
onClicked: root.backClicked()
}
@ -147,7 +147,7 @@ Rectangle {
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: startAAudioCallButton
id: startAudioCallButton
visible: interactionButtonsVisibility &&
(!addMemberVisibility || UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
@ -158,7 +158,7 @@ Rectangle {
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: startAVideoCallButton
id: startVideoCallButton
visible: interactionButtonsVisibility &&
CurrentAccount.videoEnabled_Video &&
@ -170,23 +170,23 @@ Rectangle {
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: addParticipantsButton
id: inviteMembersButton
checkable: true
checked: extrasPanel.isOpen(ChatView.AddMemberPanel)
visible: interactionButtonsVisibility && addMemberVisibility
source: JamiResources.add_people_24dp_svg
toolTipText: JamiStrings.addParticipants
toolTipText: JamiStrings.inviteMembers
onClicked: extrasPanel.switchToPanel(ChatView.AddMemberPanel)
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: selectPluginButton
id: selectExtensionsButton
visible: PluginAdapter.chatHandlersListCount && interactionButtonsVisibility
source: JamiResources.plugins_24dp_svg
toolTipText: JamiStrings.showPlugins
toolTipText: JamiStrings.showExtensions
onClicked: pluginSelector()
}

View File

@ -54,7 +54,7 @@ BaseModalDialog {
Layout.fillWidth: true
Layout.preferredHeight: 35
placeHolderText: type === ContactList.TRANSFER ? JamiStrings.transferTo : JamiStrings.addParticipant
placeHolderText: type === ContactList.TRANSFER ? JamiStrings.transferTo : JamiStrings.inviteMember
onSearchBarTextChanged: function(text){
ContactAdapter.setSearchFilter(text);

View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2024 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "../../commoncomponents"
ItemDelegate {
id: root
width: ListView.view.width
height: JamiTheme.smartListItemHeight
RowLayout {
anchors.fill: parent
anchors.leftMargin: 15
anchors.rightMargin: 15
spacing: 10
ConversationAvatar {
id: avatar
objectName: "smartlistItemDelegateAvatar"
imageId: UID
presenceStatus: Presence
showPresenceIndicator: Presence !== undefined ? Presence : false
Layout.preferredWidth: JamiTheme.smartListAvatarSize
Layout.preferredHeight: JamiTheme.smartListAvatarSize
Rectangle {
id: overlayHighlighted
visible: highlighted
anchors.fill: parent
color: Qt.rgba(0, 0, 0, 0.5)
radius: JamiTheme.smartListAvatarSize / 2
Image {
id: highlightedImage
width: JamiTheme.smartListAvatarSize / 2
height: JamiTheme.smartListAvatarSize / 2
anchors.centerIn: parent
layer {
enabled: true
effect: ColorOverlay {
color: "white"
}
}
source: JamiResources.check_black_24dp_svg
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 0
// best name
Text {
Layout.fillWidth: true
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignVCenter
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
elide: Text.ElideMiddle
text: Title === undefined ? "" : Title
textFormat: TextEdit.PlainText
font.pointSize: JamiTheme.mediumFontSize
font.weight: UnreadMessagesCount ? Font.Bold : Font.Normal
color: JamiTheme.textColor
}
Text {
Layout.fillWidth: true
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignVCenter
text: JamiStrings.blocked
textFormat: TextEdit.PlainText
visible: IsBanned
font.pointSize: JamiTheme.mediumFontSize
font.weight: Font.Bold
color: JamiTheme.textColor
}
}
Accessible.role: Accessible.Button
Accessible.name: Title === undefined ? "" : Title
}
background: Rectangle {
color: {
if (root.pressed || root.highlighted)
return JamiTheme.smartListSelectedColor;
else if (root.hovered)
return JamiTheme.smartListHoveredColor;
else
return "transparent";
}
}
highlighted: {
return mainMenu.selectedUids.includes(UID);
}
onClicked: {
const currentSelectedUids = mainMenu.selectedUids;
if (currentSelectedUids.includes(UID)) {
mainMenu.selectedUids = currentSelectedUids.filter(uid => uid !== UID);
} else {
mainMenu.selectedUids = currentSelectedUids.concat(UID);
}
return;
}
}

View File

@ -43,7 +43,7 @@ ContextMenuAutoLoader {
property list<GeneralMenuItem> menuItems: [
GeneralMenuItem {
id: startVideoCallItem
id: startVideoCall
canTrigger: CurrentAccount.videoEnabled_Video && !hasCall && !readOnly
itemName: JamiStrings.startVideoCall

View File

@ -60,7 +60,7 @@ JamiListView {
property var messageListModel: MessagesAdapter.mediaMessageListModel
readonly property int documentType: Interaction.Type.DATA_TRANSFER
readonly property int transferFinishedType: Interaction.Status.TRANSFER_FINISHED
readonly property int transferFinishedType: Interaction.TransferStatus.TRANSFER_FINISHED
readonly property int transferSuccesType: Interaction.Status.SUCCESS
onMessageListModelChanged: sourceModel = root.visible && messageListModel ? messageListModel : null

View File

@ -37,27 +37,27 @@ Window {
id: keyboardGeneralShortcutsModel
ListElement {
shortcut: "Ctrl + J"
shortcut: "Ctrl+J"
description: qsTr("Open account list")
}
ListElement {
shortcut: "Ctrl + L"
shortcut: "Ctrl+L"
description: qsTr("Focus conversations list")
}
ListElement {
shortcut: "Ctrl + R"
shortcut: "Ctrl+R"
description: qsTr("Requests list")
}
ListElement {
shortcut: "Ctrl + ↑"
shortcut: "Ctrl+↑"
description: qsTr("Previous conversation")
}
ListElement {
shortcut: "Ctrl + ↓"
shortcut: "Ctrl+↓"
description: qsTr("Next conversation")
}
ListElement {
shortcut: "Ctrl + F"
shortcut: "Ctrl+F"
description: qsTr("Search bar")
}
ListElement {
@ -65,15 +65,15 @@ Window {
description: qsTr("Full screen")
}
ListElement {
shortcut: "Ctrl + +"
shortcut: "Ctrl++"
description: qsTr("Increase font size")
}
ListElement {
shortcut: "Ctrl + -"
shortcut: "Ctrl+-"
description: qsTr("Decrease font size")
}
ListElement {
shortcut: "Ctrl + 0"
shortcut: "Ctrl+0"
description: qsTr("Reset font size")
}
},
@ -81,33 +81,13 @@ Window {
id: keyboardConversationShortcutsModel
ListElement {
shortcut: "Ctrl + Shift + C"
description: qsTr("Start an audio call")
}
ListElement {
shortcut: "Ctrl + Shift + X"
description: qsTr("Start a video call")
}
ListElement {
shortcut: "Ctrl + Shift + L"
description: qsTr("Clear history")
}
ListElement {
shortcut: "Ctrl + Shift + F"
description: qsTr("Search messages/files")
}
ListElement {
shortcut: "Ctrl + Shift + B"
description: qsTr("Block contact")
}
ListElement {
shortcut: "Ctrl + Shift + Delete"
description: qsTr("Remove conversation")
}
ListElement {
shortcut: "Ctrl + Shift + A"
shortcut: "Ctrl+Shift+A"
description: qsTr("Accept contact request")
}
ListElement {
shortcut: "Ctrl+Shift+F"
description: qsTr("Search messages/files")
}
ListElement {
shortcut: "↑"
description: qsTr("Edit last message")
@ -116,50 +96,41 @@ Window {
shortcut: "Esc"
description: qsTr("Cancel message edition")
}
},
ListModel {
id: keyboardSettingsShortcutsModel
ListElement {
shortcut: "Ctrl + M"
description: qsTr("Media settings")
shortcut: "Ctrl+Shift+L"
description: qsTr("Clear history")
}
ListElement {
shortcut: "Ctrl + G"
description: qsTr("General settings")
shortcut: "Ctrl+Shift+B"
description: qsTr("Block contact")
}
ListElement {
shortcut: "Ctrl + Alt + I"
description: qsTr("Account settings")
}
ListElement {
shortcut: "Ctrl + P"
description: qsTr("Plugin settings")
}
ListElement {
shortcut: "Ctrl + Shift + N"
description: qsTr("Open account creation wizard")
}
ListElement {
shortcut: "F10"
shortcut2: ""
description: qsTr("Open keyboard shortcut table")
shortcut: "Ctrl+Shift+Delete"
description: qsTr("Leave conversation")
}
},
ListModel {
id: keyboardCallsShortcutsModel
ListElement {
shortcut: "Ctrl + Y"
description: qsTr("Answer an incoming call")
shortcut: "Ctrl+Shift+C"
description: qsTr("Start audio call")
}
ListElement {
shortcut: "Ctrl + D"
shortcut: "Ctrl+Shift+X"
description: qsTr("Start video call")
}
ListElement {
shortcut: "Ctrl+Y"
description: qsTr("Answer incoming call")
}
ListElement {
shortcut: "Ctrl+D"
description: qsTr("End call")
}
ListElement {
shortcut: "Ctrl + Shift + D"
description: qsTr("Decline the call request")
shortcut: "Ctrl+Shift+D"
description: qsTr("Decline call request")
}
ListElement {
shortcut: "M"
@ -170,7 +141,7 @@ Window {
description: qsTr("Stop camera")
}
ListElement {
shortcut: "Ctrl + Mouse middle click"
shortcut: "Ctrl+Mouse middle click"
description: qsTr("Take tile screenshot")
}
},
@ -178,48 +149,77 @@ Window {
id: keyboardMarkdownShortcutsModel
ListElement {
shortcut: "Ctrl + B"
shortcut: "Ctrl+B"
description: qsTr("Bold")
}
ListElement {
shortcut: "Ctrl + I"
shortcut: "Ctrl+I"
description: qsTr("Italic")
}
ListElement {
shortcut: "Shift + Alt + X"
shortcut: "Shift+Alt+X"
description: qsTr("Strikethrough")
}
ListElement {
shortcut: "Ctrl + Alt + H"
shortcut: "Ctrl+Alt+H"
description: qsTr("Heading")
}
ListElement {
shortcut: "Ctrl + Alt + K"
shortcut: "Ctrl+Alt+K"
description: qsTr("Link")
}
ListElement {
shortcut: "Ctrl + Alt + C"
shortcut: "Ctrl+Alt+C"
description: qsTr("Code")
}
ListElement {
shortcut: "Shift + Alt + 9"
shortcut: "Shift+Alt+9"
description: qsTr("Quote")
}
ListElement {
shortcut: "Shift + Alt + 8"
shortcut: "Shift+Alt+8"
description: qsTr("Unordered list")
}
ListElement {
shortcut: "Shift + Alt + 7"
shortcut: "Shift+Alt+7"
description: qsTr("Ordered list")
}
ListElement {
shortcut: "Shift + Alt + T"
description: qsTr("Show formatting")
shortcut: "Shift+Alt+T"
description: qsTr("Show/hide formatting")
}
ListElement {
shortcut: "Shift + Alt + P"
description: qsTr("Show preview")
shortcut: "Shift+Alt+P"
description: qsTr("Show preview/Continue editing")
}
},
ListModel {
id: keyboardSettingsShortcutsModel
ListElement {
shortcut: "Ctrl+Alt+I"
description: qsTr("Open account settings")
}
ListElement {
shortcut: "Ctrl+G"
description: qsTr("Open general settings")
}
ListElement {
shortcut: "Ctrl+M"
description: qsTr("Open media settings")
}
ListElement {
shortcut: "Ctrl+E"
description: qsTr("Open extensions settings")
}
ListElement {
shortcut: "Ctrl+Shift+N"
description: qsTr("Open account creation wizard")
}
ListElement {
shortcut: "F10"
shortcut2: ""
description: qsTr("View keyboard shortcuts")
}
}
]
@ -302,7 +302,7 @@ Window {
focus: true
Repeater {
model: [JamiStrings.generalSettingsTitle, JamiStrings.conversationKeyboardShortcuts, JamiStrings.callKeyboardShortcuts, JamiStrings.settings, JamiStrings.markdownKeyboardShortcuts]
model: [JamiStrings.generalSettingsTitle, JamiStrings.conversationKeyboardShortcuts, JamiStrings.callKeyboardShortcuts, JamiStrings.markdownKeyboardShortcuts, JamiStrings.settings]
TabButton {
id: tabButton

View File

@ -25,6 +25,8 @@ import net.jami.Enums 1.1
import net.jami.Constants 1.1
import "../../commoncomponents"
import "qrc:/js/markdownedition.js" as MDE
RowLayout {
id: root
@ -358,231 +360,6 @@ RowLayout {
id: listViewTypo
height: JamiTheme.chatViewFooterButtonSize
function isStyle(text, start, end, char1, char2, regex) {
if (char1 === "**") {
return isStarStyle(text, start, end, "bold");
}
if (char1 === "*") {
return isStarStyle(text, start, end, "italic");
}
var selectedText = text.substring(start - char1.length, end + char2.length);
return (selectedText.startsWith(char1) && selectedText.endsWith(char2));
}
function isStarStyle(text, selectionStart, selectionEnd, type) {
let start = selectionStart;
while (start > 0 && text[start - 1] === "*") {
start--;
}
let end = selectionEnd;
while (end < text.length && text[end] === "*") {
end++;
}
const starCount = Math.min(selectionStart - start, end - selectionEnd);
if (type === "italic") {
return starCount === 1 || starCount === 3;
}
return starCount === 2 || starCount === 3;
}
function addStyle(text, start, end, char1, char2, regex) {
// get the selected text with markdown effect
var selectedText = text.substring(start - char1.length, end + char2.length);
if (isStyle(text, start, end, char1, char2, regex)) {
// If the selected text is already formatted with the given characters, remove them
selectedText = text.substring(start, end);
root.text = text.substring(0, start - char1.length) + selectedText + text.substring(end + char2.length);
messageBarTextArea.selectText(start - char1.length, end - char1.length);
} else {
// Otherwise, add the formatting characters to the selected text
root.text = text.substring(0, start) + char1 + text.substring(start, end) + char2 + text.substring(end);
messageBarTextArea.selectText(start + char1.length, end + char1.length);
}
}
function isPrefixSyle(message, selectionStart, selectionEnd, delimiter, isOrderedList) {
//represents all the selected lines
var multilineSelection;
var newPrefix;
var newSuffix;
var newStartPos;
var newEndPos;
function nextIndexOf(text, char1, startPos) {
return text.indexOf(char1, startPos + 1);
}
//get the previous index of the multilineSelection text
if (message[selectionStart] === "\n")
newStartPos = message.lastIndexOf('\n', selectionStart - 1);
else
newStartPos = message.lastIndexOf('\n', selectionStart);
//get the next index of the multilineSelection text
if (message[selectionEnd] === "\n" || message[selectionEnd] === undefined)
newEndPos = selectionEnd;
else
newEndPos = nextIndexOf(message, "\n", selectionEnd);
//if the text is empty
if (newStartPos === -1)
newStartPos = 0;
newPrefix = message.slice(0, newStartPos);
multilineSelection = message.slice(newStartPos, newEndPos);
newSuffix = message.slice(newEndPos);
var isFirstLineSelected = !multilineSelection.startsWith('\n') || newPrefix === "";
var getDelimiter_counter = 1;
function getDelimiter() {
return `${getDelimiter_counter++}. `;
}
function getHasCurrentMarkdown() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity = (multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity && multilineSelection.startsWith(delimiter);
}
function getHasCurrentMarkdownBullet() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity = (multilineSelection.match(/\n\d+\. /g) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity && (/^\d\. /).test(multilineSelection);
}
var newValue;
var newStart;
var newEnd;
var count;
var startPos;
var multilineSelectionLength;
if (!isOrderedList) {
return getHasCurrentMarkdown();
} else {
return getHasCurrentMarkdownBullet();
}
}
function addPrefixStyle(message, selectionStart, selectionEnd, delimiter, isOrderedList) {
//represents all the selected lines
var multilineSelection;
var newPrefix;
var newSuffix;
var newStartPos;
var newEndPos;
function nextIndexOf(text, char1, startPos) {
return text.indexOf(char1, startPos + 1);
}
//get the previous index of the multilineSelection text
if (message[selectionStart] === "\n")
newStartPos = message.lastIndexOf('\n', selectionStart - 1);
else
newStartPos = message.lastIndexOf('\n', selectionStart);
//get the next index of the multilineSelection text
if (message[selectionEnd] === "\n" || message[selectionEnd] === undefined)
newEndPos = selectionEnd;
else
newEndPos = nextIndexOf(message, "\n", selectionEnd);
//if the text is empty
if (newStartPos === -1)
newStartPos = 0;
newPrefix = message.slice(0, newStartPos);
multilineSelection = message.slice(newStartPos, newEndPos);
newSuffix = message.slice(newEndPos);
var isFirstLineSelected = !multilineSelection.startsWith('\n') || newPrefix === "";
var getDelimiter_counter = 1;
function getDelimiter() {
return `${getDelimiter_counter++}. `;
}
function getHasCurrentMarkdown() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity = (multilineSelection.match(new RegExp(`\n${delimiter}`, 'g')) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity && multilineSelection.startsWith(delimiter);
}
function getHasCurrentMarkdownBullet() {
const linesQuantity = (multilineSelection.match(/\n/g) || []).length;
const newLinesWithDelimitersQuantity = (multilineSelection.match(/\n\d+\. /g) || []).length;
if (newLinesWithDelimitersQuantity === linesQuantity && !isFirstLineSelected)
return true;
return linesQuantity === newLinesWithDelimitersQuantity && (/^\d\. /).test(multilineSelection);
}
var newValue;
var newStart;
var newEnd;
var count;
var startPos;
var multilineSelectionLength;
if (!isOrderedList) {
if (getHasCurrentMarkdown()) {
// clear first line from delimiter
if (isFirstLineSelected)
multilineSelection = multilineSelection.slice(delimiter.length);
newValue = newPrefix + multilineSelection.replace(new RegExp(`\n${delimiter}`, 'g'), '\n') + newSuffix;
count = 0;
if (isFirstLineSelected)
count++;
count += (multilineSelection.match(/\n/g) || []).length;
newStart = Math.max(selectionStart - delimiter.length, 0);
newEnd = Math.max(selectionEnd - (delimiter.length * count), 0);
} else {
newValue = newPrefix + multilineSelection.replace(/\n/g, `\n${delimiter}`) + newSuffix;
count = 0;
if (isFirstLineSelected) {
newValue = delimiter + newValue;
count++;
}
count += (multilineSelection.match(new RegExp('\\n', 'g')) || []).length;
newStart = selectionStart + delimiter.length;
newEnd = selectionEnd + (delimiter.length * count);
}
} else if (getHasCurrentMarkdownBullet()) {
if (message[selectionStart] === "\n")
startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
else
startPos = message.lastIndexOf('\n', selectionStart) + 1;
newStart = startPos;
multilineSelection = multilineSelection.replace(/^\d+\.\s/gm, '');
newValue = newPrefix + multilineSelection + newSuffix;
multilineSelectionLength = multilineSelection.length;
//if the first line is not selected, we need to remove the first "\n" of multilineSelection
if (newStart)
multilineSelectionLength = multilineSelection.length - 1;
newEnd = Math.max(newStart + multilineSelectionLength, 0);
} else {
if (message[selectionStart] === "\n")
startPos = message.lastIndexOf('\n', selectionStart - 1) + 1;
else
startPos = message.lastIndexOf('\n', selectionStart) + 1;
newStart = startPos;
// if no text is selected
if (selectionStart === selectionEnd)
newStart = newStart + 3;
if (isFirstLineSelected)
multilineSelection = getDelimiter() + multilineSelection;
const selectionArr = Array.from(multilineSelection);
for (var i = 0; i < selectionArr.length; i++) {
if (selectionArr[i] === '\n')
selectionArr[i] = `\n${getDelimiter()}`;
}
multilineSelection = selectionArr.join('');
newValue = newPrefix + multilineSelection + newSuffix;
multilineSelectionLength = multilineSelection.length;
//if the first line is not selected, we meed to remove the first "\n" of multilineSelection
if (startPos)
multilineSelectionLength = multilineSelection.length - 1;
newEnd = Math.max(startPos + multilineSelectionLength, 0);
}
root.text = newValue;
messageBarTextArea.selectText(newStart, newEnd);
}
ListView {
id: listViewTypoFirst
@ -600,70 +377,56 @@ RowLayout {
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
leftMargin: 5
rightMargin: 5
spacing: 5
property list<Action> menuTypoActionsFirst: [
Action {
id: boldAction
property var iconSrc: JamiResources.bold_black_24dp_svg
property var shortcutText: JamiStrings.bold
property string iconSrc: JamiResources.bold_black_24dp_svg
property string shortcutText: JamiStrings.bold
property string shortcutKey: "Ctrl+B"
property bool isStyle: listViewTypo.isStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "**", "**", /\\*\*.+\\*\*/)
onTriggered: function clickAction() {
listViewTypo.addStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "**", "**", /\\*\*.+\\*\*/);
}
property bool isStyle: MDE.isStyle(messageBarTextArea, root.text, "**", "**")
onTriggered: MDE.addStyle(messageBarTextArea, root.text, "**", "**")
},
Action {
id: italicAction
property var iconSrc: JamiResources.italic_black_24dp_svg
property var shortcutText: JamiStrings.italic
property string iconSrc: JamiResources.italic_black_24dp_svg
property string shortcutText: JamiStrings.italic
property string shortcutKey: "Ctrl+I"
property bool isStyle: listViewTypo.isStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "*", "*", /(?:\*.+\*|\*\*\*.+\*\*\*)/)
onTriggered: function clickAction() {
listViewTypo.addStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "*", "*", /(?:\*.+\*|\*\*\*.+\*\*\*)/);
}
property bool isStyle: MDE.isStyle(messageBarTextArea, root.text, "*", "*")
onTriggered: MDE.addStyle(messageBarTextArea, root.text, "*", "*")
},
Action {
id: strikethroughAction
property var iconSrc: JamiResources.s_barre_black_24dp_svg
property var shortcutText: JamiStrings.strikethrough
property string iconSrc: JamiResources.s_barre_black_24dp_svg
property string shortcutText: JamiStrings.strikethrough
property string shortcutKey: "Shift+Alt+X"
property bool isStyle: listViewTypo.isStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "~~", "~~", /\~\~.+\~\~/)
onTriggered: function clickAction() {
listViewTypo.addStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "~~", "~~", /\~\~.+\~\~/);
}
property bool isStyle: MDE.isStyle(messageBarTextArea, root.text, "~~", "~~")
onTriggered: MDE.addStyle(messageBarTextArea, root.text, "~~", "~~")
},
Action {
id: titleAction
property var iconSrc: JamiResources.title_black_24dp_svg
property var shortcutText: JamiStrings.heading
property string iconSrc: JamiResources.title_black_24dp_svg
property string shortcutText: JamiStrings.heading
property string shortcutKey: "Ctrl+Alt+H"
property bool isStyle: listViewTypo.isPrefixSyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "### ", false)
onTriggered: function clickAction() {
listViewTypo.addPrefixStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "### ", false);
}
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, root.text, "### ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, root.text, "### ", false)
},
Action {
id: linkAction
property var iconSrc: JamiResources.link_web_black_24dp_svg
property var shortcutText: JamiStrings.link
property string iconSrc: JamiResources.link_web_black_24dp_svg
property string shortcutText: JamiStrings.link
property string shortcutKey: "Ctrl+Alt+K"
property bool isStyle: listViewTypo.isStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "[", "](url)", /\[.+\]\(.+\)/)
onTriggered: function clickAction() {
listViewTypo.addStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "[", "](url)", /\[.+\]\(.+\)/);
}
property bool isStyle: MDE.isStyle(messageBarTextArea, root.text, "[", "](url)")
onTriggered: MDE.addStyle(messageBarTextArea, root.text, "[", "](url)")
},
Action {
id: codeAction
property var iconSrc: JamiResources.code_black_24dp_svg
property var shortcutText: JamiStrings.code
property string iconSrc: JamiResources.code_black_24dp_svg
property string shortcutText: JamiStrings.code
property string shortcutKey: "Ctrl+Alt+C"
property bool isStyle: listViewTypo.isStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "```", "```", /\`\`\`.+\`\`\`/)
onTriggered: function clickAction() {
listViewTypo.addStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "```", "```", /\`\`\`.+\`\`\`/);
}
property bool isStyle: MDE.isStyle(messageBarTextArea, root.text, "```", "```")
onTriggered: MDE.addStyle(messageBarTextArea, root.text, "```", "```")
}
]
@ -795,8 +558,6 @@ RowLayout {
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
leftMargin: 10
rightMargin: 10
spacing: 10
Rectangle {
@ -808,33 +569,27 @@ RowLayout {
property list<Action> menuTypoActionsSecond: [
Action {
id: quoteAction
property var iconSrc: JamiResources.quote_black_24dp_svg
property var shortcutText: JamiStrings.quote
property string iconSrc: JamiResources.quote_black_24dp_svg
property string shortcutText: JamiStrings.quote
property string shortcutKey: "Shift+Alt+9"
property bool isStyle: listViewTypo.isPrefixSyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "> ", false)
onTriggered: function clickAction() {
listViewTypo.addPrefixStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "> ", false);
}
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, root.text, "> ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, root.text, "> ", false)
},
Action {
id: unorderedListAction
property var iconSrc: JamiResources.bullet_point_black_24dp_svg
property var shortcutText: JamiStrings.unorderedList
property string iconSrc: JamiResources.bullet_point_black_24dp_svg
property string shortcutText: JamiStrings.unorderedList
property string shortcutKey: "Shift+Alt+8"
property bool isStyle: listViewTypo.isPrefixSyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "- ", false)
onTriggered: function clickAction() {
listViewTypo.addPrefixStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "- ", false);
}
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, root.text, "- ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, root.text, "- ", false)
},
Action {
id: orderedListAction
property var iconSrc: JamiResources.bullet_number_black_24dp_svg
property var shortcutText: JamiStrings.orderedList
property string iconSrc: JamiResources.bullet_number_black_24dp_svg
property string shortcutText: JamiStrings.orderedList
property string shortcutKey: "Shift+Alt+7"
property bool isStyle: listViewTypo.isPrefixSyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "", true)
onTriggered: function clickAction() {
listViewTypo.addPrefixStyle(root.text, messageBarTextArea.selectionStart, messageBarTextArea.selectionEnd, "", true);
}
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, root.text, "", true)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, root.text, "", true)
}
]
@ -945,8 +700,8 @@ RowLayout {
property list<Action> menuActions: [
Action {
id: sendFile
property var iconSrc: JamiResources.link_black_24dp_svg
property var toolTip: JamiStrings.sendFile
property string iconSrc: JamiResources.link_black_24dp_svg
property string toolTip: JamiStrings.sendFile
property bool show: true
property bool needWebEngine: false
property bool needVideoDevice: false
@ -958,8 +713,8 @@ RowLayout {
},
Action {
id: addEmoji
property var iconSrc: JamiResources.emoji_black_24dp_svg
property var toolTip: JamiStrings.addEmoji
property string iconSrc: JamiResources.emoji_black_24dp_svg
property string toolTip: JamiStrings.addEmoji
property bool show: true
property bool needWebEngine: true
property bool needVideoDevice: false
@ -1047,8 +802,8 @@ RowLayout {
property list<Action> menuMoreButton: [
Action {
id: leaveAudioMessage
property var iconSrc: JamiResources.message_audio_black_24dp_svg
property var toolTip: JamiStrings.leaveAudioMessage
property string iconSrc: JamiResources.message_audio_black_24dp_svg
property string toolTip: JamiStrings.leaveAudioMessage
property bool show: false
property bool needWebEngine: false
property bool needVideoDevice: false
@ -1059,8 +814,8 @@ RowLayout {
},
Action {
id: leaveVideoMessage
property var iconSrc: JamiResources.message_video_black_24dp_svg
property var toolTip: JamiStrings.leaveVideoMessage
property string iconSrc: JamiResources.message_video_black_24dp_svg
property string toolTip: JamiStrings.leaveVideoMessage
property bool show: false
property bool needWebEngine: false
property bool needVideoDevice: true
@ -1071,8 +826,8 @@ RowLayout {
},
Action {
id: shareLocation
property var iconSrc: JamiResources.localisation_sharing_send_pin_svg
property var toolTip: JamiStrings.shareLocation
property string iconSrc: JamiResources.localisation_sharing_send_pin_svg
property string toolTip: JamiStrings.shareLocation
property bool show: false
property bool needWebEngine: true
property bool needVideoDevice: false

View File

@ -174,7 +174,7 @@ DualPaneView {
Layout.preferredWidth: JamiTheme.preferredFieldWidth
staticText: ""
placeholderText: JamiStrings.addADescription
placeholderText: JamiStrings.addDescription
textColor: {
if (UtilsAdapter.luma(root.color)) {
@ -205,7 +205,7 @@ DualPaneView {
preferredWidth: textSize.width + 2 * JamiTheme.buttontextWizzardPadding
primary: true
text: JamiStrings.createTheSwarm
text: JamiStrings.createSwarm
onClicked: createSwarmClicked(title.dynamicText, description.dynamicText, UtilsAdapter.tempCreationImage())
}

View File

@ -51,7 +51,7 @@ Rectangle {
}
PushButton {
id: joinCallInAudio
id: joinCallWithAudio
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: JamiTheme.preferredMarginSize
@ -68,7 +68,7 @@ Rectangle {
}
PushButton {
id: joinCallInVideo
id: joinCallWithVideo
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
Layout.rightMargin: JamiTheme.preferredMarginSize
@ -98,7 +98,7 @@ Rectangle {
}
}
Behavior on opacity {
Behavior on opacity {
NumberAnimation {
from: 0
duration: JamiTheme.shortFadeDuration

View File

@ -95,7 +95,7 @@ Popup {
verticalAlignment: Text.AlignVCenter
color: JamiTheme.textColor
text: JamiStrings.choosePlugin
text: JamiStrings.chooseExtension
}
PushButton {
@ -176,7 +176,7 @@ Popup {
Layout.leftMargin: 5
Layout.topMargin: 5
toolTipText: JamiStrings.goBackToPluginsList
toolTipText: JamiStrings.goBackToExtensionsList
onClicked: {
stack.pop(null, StackView.Immediate);
@ -195,7 +195,7 @@ Popup {
verticalAlignment: Text.AlignVCenter
color: JamiTheme.textColor
text: JamiStrings.pluginPreferences
text: JamiStrings.extensionPreferences
}
PushButton {

View File

@ -38,9 +38,9 @@ ItemDelegate {
highlighted: ListView.isCurrentItem
property bool interactive: true
property string lastInteractionDate: LastInteractionTimeStamp === undefined ? "" : LastInteractionTimeStamp
property string lastInteractionFormattedDate: MessagesAdapter.getBestFormattedDate(lastInteractionDate)
property int lastInteractionTimeStamp: LastInteractionTimeStamp
property string lastInteractionFormattedDate: MessagesAdapter.getBestFormattedDate(lastInteractionTimeStamp)
property bool showSharePositionIndicator: PositionManager.isPositionSharedToConv(accountId, UID)
property bool showSharedPositionIndicator: PositionManager.isConvSharingPosition(accountId, UID)
@ -58,7 +58,7 @@ ItemDelegate {
Connections {
target: MessagesAdapter
function onTimestampUpdated() {
lastInteractionFormattedDate = MessagesAdapter.getBestFormattedDate(lastInteractionDate);
lastInteractionFormattedDate = MessagesAdapter.getBestFormattedDate(lastInteractionTimeStamp);
}
}
@ -130,7 +130,7 @@ ItemDelegate {
color: JamiTheme.textColor
}
RowLayout {
visible: ContactType !== Profile.Type.TEMPORARY && !IsBanned && lastInteractionFormattedDate !== undefined && interactive
visible: ContactType !== Profile.Type.TEMPORARY && !IsBanned && lastInteractionTimeStamp > 0 && interactive
Layout.fillWidth: true
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignTop
@ -138,7 +138,7 @@ ItemDelegate {
// last Interaction date
Text {
Layout.alignment: Qt.AlignVCenter
text: lastInteractionFormattedDate === undefined ? "" : lastInteractionFormattedDate
text: lastInteractionFormattedDate
textFormat: TextEdit.PlainText
font.pointSize: JamiTheme.smallFontSize
font.weight: UnreadMessagesCount ? Font.DemiBold : Font.Normal
@ -164,7 +164,7 @@ ItemDelegate {
Layout.fillWidth: true
Layout.minimumHeight: 20
Layout.alignment: Qt.AlignVCenter
text: JamiStrings.banned
text: JamiStrings.blocked
textFormat: TextEdit.PlainText
visible: IsBanned
font.pointSize: JamiTheme.mediumFontSize

View File

@ -139,7 +139,7 @@ Rectangle {
Layout.rightMargin: 2 * JamiTheme.settingsMarginSize
staticText: CurrentConversation.description
placeholderText: JamiStrings.addADescription
placeholderText: JamiStrings.addDescription
elidedText: descriptionLineButtonTextSize.elidedText
textColor: root.textColor
@ -156,7 +156,7 @@ Rectangle {
descriptionLineButton.editMode = activeFocus;
}
infoTipLineText: JamiStrings.addADescription
infoTipLineText: JamiStrings.addDescription
}
}
}
@ -663,7 +663,7 @@ Rectangle {
if (MemberRole === Member.Role.INVITED)
return JamiStrings.invited;
if (MemberRole === Member.Role.BANNED)
return JamiStrings.banned;
return JamiStrings.blocked;
return "";
}
maxWidth: JamiTheme.preferredFieldWidth

View File

@ -30,7 +30,7 @@ ContextMenuAutoLoader {
property list<GeneralMenuItem> menuItems: [
GeneralMenuItem {
id: startVideoCallItem
id: startVideoCall
itemName: JamiStrings.startVideoCall
canTrigger: ConversationsAdapter.dialogId(participantUri) !== ""
iconSource: JamiResources.videocam_24dp_svg

View File

@ -46,7 +46,6 @@ function finishCreation() {
}
function showKeyboardShortcutTableWindow() {
keyboardShortcutTableWindowObject.show()
var centerX = mainWindow.x + mainWindow.width / 2
var centerY = mainWindow.y + mainWindow.height / 2
@ -54,6 +53,11 @@ function showKeyboardShortcutTableWindow() {
keyboardShortcutTableWindowObject.height = 0.75 * appWindow.height
keyboardShortcutTableWindowObject.x = centerX - keyboardShortcutTableWindowObject.width / 2
keyboardShortcutTableWindowObject.y = centerY - keyboardShortcutTableWindowObject.height / 2
keyboardShortcutTableWindowObject.visible = true
keyboardShortcutTableWindowObject.show()
keyboardShortcutTableWindowObject.raise()
keyboardShortcutTableWindowObject.requestActivate()
}
// Destroy and reset selectScreenWindowObject when window is closed.

View File

@ -165,6 +165,16 @@ MessagesAdapter::sendMessage(const QString& message)
}
}
void
MessagesAdapter::sendMessageToUid(const QString& message, const QString& convUid)
{
try {
lrcInstance_->getCurrentConversationModel()->sendMessage(convUid, message, replyToId_);
} catch (...) {
qDebug() << "Exception during sendMessage:" << message;
}
}
void
MessagesAdapter::editMessage(const QString& convId, const QString& newBody, const QString& messageId)
{
@ -221,6 +231,21 @@ MessagesAdapter::sendFile(const QString& message)
}
}
void
MessagesAdapter::sendFileToUid(const QString& message, const QString& convUid)
{
QFileInfo fi(message);
QString fileName = fi.fileName();
try {
lrcInstance_->getCurrentConversationModel()->sendFile(convUid,
message,
fileName,
replyToId_);
} catch (...) {
qDebug() << "Exception during sendFile";
}
}
void
MessagesAdapter::joinCall(const QString& uri,
const QString& deviceId,
@ -312,8 +337,7 @@ MessagesAdapter::onPaste()
QString path = QDir::temp().filePath(fileName);
if (!pixmap.save(path, "PNG")) {
qDebug().noquote() << "Errors during QPixmap save"
<< "\n";
qDebug().noquote() << "Errors during QPixmap save" << "\n";
return;
}
@ -335,40 +359,6 @@ MessagesAdapter::onPaste()
}
}
QString
MessagesAdapter::getStatusString(int status)
{
switch (static_cast<interaction::Status>(status)) {
case interaction::Status::SENDING:
return QObject::tr("Sending");
case interaction::Status::FAILURE:
return QObject::tr("Failure");
case interaction::Status::SUCCESS:
return QObject::tr("Sent");
case interaction::Status::TRANSFER_CREATED:
return QObject::tr("Connecting");
case interaction::Status::TRANSFER_ACCEPTED:
return QObject::tr("Accept");
case interaction::Status::TRANSFER_CANCELED:
return QObject::tr("Canceled");
case interaction::Status::TRANSFER_ERROR:
case interaction::Status::TRANSFER_UNJOINABLE_PEER:
return QObject::tr("Unable to make contact");
case interaction::Status::TRANSFER_ONGOING:
return QObject::tr("Ongoing");
case interaction::Status::TRANSFER_AWAITING_PEER:
return QObject::tr("Waiting for contact");
case interaction::Status::TRANSFER_AWAITING_HOST:
return QObject::tr("Incoming transfer");
case interaction::Status::TRANSFER_TIMEOUT_EXPIRED:
return QObject::tr("Timed out waiting for contact");
case interaction::Status::TRANSFER_FINISHED:
return QObject::tr("Finished");
default:
return {};
}
}
QVariantMap
MessagesAdapter::getTransferStats(const QString& msgId, int status)
{

View File

@ -126,6 +126,7 @@ public:
Q_INVOKABLE void unbanContact(int index);
Q_INVOKABLE void unbanConversation(const QString& convUid);
Q_INVOKABLE void sendMessage(const QString& message);
Q_INVOKABLE void sendMessageToUid(const QString& message, const QString& convUid);
Q_INVOKABLE void editMessage(const QString& convId,
const QString& newBody,
const QString& messageId = "");
@ -136,6 +137,7 @@ public:
const QString& emoji,
const QString& messageId);
Q_INVOKABLE void sendFile(const QString& message);
Q_INVOKABLE void sendFileToUid(const QString& message, const QString& convUid);
Q_INVOKABLE void acceptFile(const QString& arg);
Q_INVOKABLE void cancelFile(const QString& arg);
Q_INVOKABLE void openUrl(const QString& url);
@ -159,7 +161,6 @@ public:
const QColor& linkColor = QColor(0x06, 0x45, 0xad),
const QColor& backgroundColor = QColor(0x0, 0x0, 0x0));
Q_INVOKABLE void onPaste();
Q_INVOKABLE QString getStatusString(int status);
Q_INVOKABLE QVariantMap getTransferStats(const QString& messageId, int);
Q_INVOKABLE QVariant dataForInteraction(const QString& interactionId,
int role = Qt::DisplayRole) const;

View File

@ -34,7 +34,6 @@ Item {
property string incomingAudioCallFrom: qsTr("Incoming audio call from {}")
property string incomingVideoCallFrom: qsTr("Incoming video call from {}")
property string startSwarm: qsTr("Start swarm")
property string createSwarm: qsTr("Create swarm")
property string invitations: qsTr("Invitations")
property string description: qsTr("Jami is a universal communication platform, with privacy as its foundation, that relies on a free distributed network for everyone.")
property string updateToSwarm: qsTr("Migrating to the Swarm technology will enable synchronizing this conversation across multiple devices and improve reliability. The legacy conversation history will be cleared in the process.")
@ -45,9 +44,11 @@ Item {
property string reconnectTry: qsTr("Trying to reconnect to the Jami daemon (jamid)…")
// AboutPopUp
property string version: qsTr("Version") + (AppVersionManager.isCurrentVersionBeta() ? " (Beta)" : "")
property string buildID: qsTr("Build ID")
property string version: qsTr("Version")
property string declarationYear: "© 2015-2024"
property string slogan: "Eleutheria"
property string slogan: "Astarte"
property string declaration: qsTr('Jami, a GNU package, is software for universal and distributed peer-to-peer communication that respects the freedom and privacy of its users. Visit <a href="https://jami.net" style="color: ' + JamiTheme.buttonTintedBlue + '">jami.net</a>' + ' to learn more.')
property string noWarranty: qsTr('This program comes with absolutely no warranty. See the <a href="https://www.gnu.org/licenses/gpl-3.0.html" style="color: ' + JamiTheme.buttonTintedBlue + '">GNU General Public License</a>, version 3 or later for details.')
property string contribute: qsTr('Contribute')
@ -73,7 +74,7 @@ Item {
property string authenticate: qsTr("Authenticate")
property string deleteAccount: qsTr("Delete account")
property string inProgress: qsTr("In progress…")
property string authenticationFailed: qsTr("Authentication failed")
property string authenticationFailed: qsTr("An error occurred while authenticating account.")
property string password: qsTr("Password")
property string username: qsTr("Username")
property string alias: qsTr("Alias")
@ -85,8 +86,8 @@ Item {
property string enableCustomRingtone: qsTr("Enable custom ringtone")
property string selectCustomRingtone: qsTr("Select custom ringtone")
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 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")
@ -117,11 +118,11 @@ Item {
property string verifyCertificatesClient: qsTr("Verify server TLS certificates")
property string tlsRequireConnections: qsTr("Require certificate for incoming TLS connections")
property string disableSecureDlgCheck: qsTr("Disable secure dialog check for incoming TLS data")
property string selectPrivateKey: qsTr("Select a private key")
property string selectUserCert: qsTr("Select a user certificate")
property string selectCACert: qsTr("Select a CA certificate")
property string selectPrivateKey: qsTr("Select private key")
property string selectUserCert: qsTr("Select user certificate")
property string selectCACert: qsTr("Select CA certificate")
property string selectCACertDefault: qsTr("Select")
property string keyFile: qsTr("Key File (*.key)")
property string keyFile: qsTr("Key file (*.key)")
// AdvancedConnectivitySettings
property string connectivity: qsTr("Connectivity")
@ -133,7 +134,7 @@ Item {
property string turnAdress: qsTr("TURN address")
property string turnUsername: qsTr("TURN username")
property string turnPassword: qsTr("TURN password")
property string turnRealm: qsTr("TURN Realm")
property string turnRealm: qsTr("TURN realm")
property string useSTUN: qsTr("Use STUN")
property string stunAdress: qsTr("STUN address")
@ -174,14 +175,14 @@ Item {
property string back: qsTr("Back")
property string accountSettingsMenuTitle: qsTr("Account")
property string generalSettingsTitle: qsTr("General")
property string pluginSettingsTitle: qsTr("Extensions")
property string extensionSettingsTitle: qsTr("Extensions")
property string enableAccountSettingsTitle: qsTr("Enable account")
property string manageAccountSettingsTitle: qsTr("Manage account")
property string linkedDevicesSettingsTitle: qsTr("Linked devices")
property string callSettingsTitle: qsTr("Call settings")
property string chatSettingsTitle: qsTr("Chat")
property string advancedSettingsTitle: qsTr("Advanced settings")
property string audioVideoSettingsTitle: qsTr("Audio and Video")
property string mediaSettingsTitle: qsTr("Media")
// AudioSettings
property string audio: qsTr("Audio")
@ -206,7 +207,7 @@ Item {
property string mirrorLocalVideo: qsTr("Mirror local video")
property string screenSharing: qsTr("Screen sharing")
property string selectScreenSharingFPS: qsTr("Select screen sharing frame rate (frames per second)")
property string noVideo: qsTr("no video")
property string noCamera: qsTr("No camera available")
// BackupKeyPage
property string whyBackupAccount: qsTr("Why should I back-up this account?")
@ -218,8 +219,7 @@ Item {
property string jamiArchiveFiles: qsTr("Jami archive files (*.gz)")
property string allFiles: qsTr("All files (*)")
// BannedItemDelegate
property string reinstateContact: qsTr("Reinstate as contact")
// ContactItemDelegate
property string name: qsTr("name")
property string identifier: qsTr("Identifier")
@ -230,10 +230,10 @@ Item {
property string unmute: qsTr("Unmute")
property string pauseCall: qsTr("Pause call")
property string resumeCall: qsTr("Resume call")
property string muteCamera: qsTr("Mute camera")
property string unmuteCamera: qsTr("Unmute camera")
property string addParticipant: qsTr("Add participant")
property string addParticipants: qsTr("Add participants")
property string stopCamera: qsTr("Stop camera")
property string startCamera: qsTr("Start camera")
property string inviteMember: qsTr("Invite member")
property string inviteMembers: qsTr("Invite members")
property string details: qsTr("Details")
property string chat: qsTr("Chat")
property string moreOptions: qsTr("More options")
@ -259,20 +259,20 @@ Item {
property string paste: qsTr("Paste")
// ConversationContextMenu
property string startVideoCall: qsTr("Start video call")
property string startAudioCall: qsTr("Start audio call")
property string startVideoCall: qsTr("Start video call")
property string clearConversation: qsTr("Clear conversation")
property string confirmAction: qsTr("Confirm action")
property string removeConversation: qsTr("Remove conversation")
property string confirmRmConversation: qsTr("Would you really like to remove this conversation?")
property string confirmBlockConversation: qsTr("Would you really like to block this conversation?")
property string removeConversation: qsTr("Leave conversation")
property string confirmRmConversation: qsTr("Do you really want to leave this conversation?")
property string confirmBlockConversation: qsTr("Do you really want to block this conversation?")
property string removeContact: qsTr("Remove contact")
property string blockContact: qsTr("Block contact")
property string convDetails: qsTr("Conversation details")
property string contactDetails: qsTr("Contact details")
// CallViewContextMenu
property string sipInputPanel: qsTr("Sip input panel")
property string sipInputPanel: qsTr("DTMF input panel")
property string transferCall: qsTr("Transfer call")
property string stopRec: qsTr("Stop recording")
property string startRec: qsTr("Start recording")
@ -283,7 +283,7 @@ Item {
property string shareScreenArea: qsTr("Share screen area")
property string shareFile: qsTr("Share file")
property string selectShareMethod: qsTr("Select sharing method")
property string viewPlugin: qsTr("View plugin")
property string viewExtension: qsTr("View extension")
property string advancedInformation: qsTr("Advanced information")
property string noVideoDevice: qsTr("No video device")
property string notAvailable: qsTr("Unavailable")
@ -294,7 +294,7 @@ Item {
property string screenshotTaken: qsTr("Screenshot saved to %1")
property string fileSaved: qsTr("File saved to %1")
//advanced information
// Advanced information
property string renderersInformation: qsTr("Renderers information")
property string callInformation: qsTr("Call information")
property string peerNumber: qsTr("Peer number")
@ -310,8 +310,8 @@ Item {
// Share location/position
property string shareLocation: qsTr("Share location")
property string stopSharingLocation: qsTr("Stop sharing")
property string locationServicesError: qsTr("Your precise location could not be determined.\nIn Device Settings, please turn on \"Location Services\".\nOther participants' location can still be received.")
property string locationServicesClosedError: qsTr("Your precise location could not be determined. Please check your Internet connection.")
property string locationServicesError: qsTr("An error occurred while sharing device location.\nEnable “Location Services” in device settings in order to use this feature.\nThe location of other members can still be received.")
property string locationServicesClosedError: qsTr("An error occurred while sharing device location. Please check your Internet connection and try again.")
property string stopAllSharings: qsTr("Turn off location sharing")
property string shortStopAllSharings: qsTr("Turn off sharing")
property string stopConvSharing: qsTr("Stop location sharing in this conversation (%1)")
@ -338,17 +338,18 @@ Item {
// Chatview header
property string hideChat: qsTr("Hide chat")
property string placeAudioCall: qsTr("Place audio call")
property string placeVideoCall: qsTr("Place video call")
property string showPlugins: qsTr("Show available plugins")
property string placeAudioCall: qsTr("Start audio call")
property string placeVideoCall: qsTr("Start video call")
property string showExtensions: qsTr("Show available extensions")
property string addToConversations: qsTr("Add to conversations")
property string backendError: qsTr("This is the error from the backend: %0")
property string backendError: qsTr("A backend system error occurred: %0")
property string disabledAccount: qsTr("The account is disabled")
property string noNetworkConnectivity: qsTr("No network connectivity")
property string deletedMessage: qsTr("deleted a message")
property string backCall: qsTr("Back to Call")
property string deletedMedia: qsTr("deleted a media")
property string returnToCall: qsTr("Return to call")
//MessagesResearch
// MessagesResearch
property string jumpTo: qsTr("Jump to")
property string messages: qsTr("Messages")
property string files: qsTr("Files")
@ -379,7 +380,7 @@ Item {
property string invalidUsername: qsTr("Invalid username")
property string nameAlreadyTaken: qsTr("Name already taken")
property string usernameAlreadyTaken: qsTr("Username already taken")
property string joinJamiNoPassword: qsTr("Are you sure you would like to join Jami without a username?\nIf yes, only a randomly generated 40-character identifier will be assigned to this account.")
property string joinJamiNoPassword: qsTr("Do you really want to join Jami without a username?\nIf yes, only a randomly generated 40-character identifier will be assigned to this account.")
property string usernameToolTip: qsTr("- 32 characters maximum\n- Alphabetical characters (A to Z and a to z)\n- Numeric characters (0 to 9)\n- Special characters allowed: dash (-)")
// Good to know
@ -395,12 +396,12 @@ Item {
property string sipAccount: qsTr("SIP account")
property string proxy: qsTr("Proxy")
property string server: qsTr("Server")
property string configureExistingSIP: qsTr("Configure an existing SIP account")
property string configureExistingSIP: qsTr("Configure existing SIP account")
property string personalizeAccount: qsTr("Personalize account")
property string addSip: qsTr("Add SIP account")
property string tls: qsTr("TLS")
property string udp: qsTr("UDP")
property string displayName: qsTr("Display Name")
property string displayName: qsTr("Display name")
// accountSettingsPages
property string customizeAccountDescription: qsTr("Your profile is only shared with your contacts.\nYour picture and your nickname can be changed at all time in the settings of your account.")
@ -416,11 +417,11 @@ Item {
// CurrentAccountSettings && AdvancedSettings
property string backupSuccessful: qsTr("Backup successful")
property string backupFailed: qsTr("Backup failed")
property string backupFailed: qsTr("An error occurred while backing up account.")
property string changePasswordSuccess: qsTr("Password changed successfully")
property string changePasswordFailed: qsTr("Password change failed")
property string changePasswordFailed: qsTr("An error occurred while changing account password.")
property string setPasswordSuccess: qsTr("Password set successfully")
property string setPasswordFailed: qsTr("Password set failed")
property string setPasswordFailed: qsTr("An error occurred while setting account password.")
property string changePassword: qsTr("Change password")
property string setPassword: qsTr("Encrypt account")
property string setAPassword: qsTr("Set a password")
@ -431,8 +432,8 @@ Item {
property string advancedAccountSettings: qsTr("Advanced account settings")
property string encryptAccount: qsTr("Encrypt account with password")
property string customizeProfile: qsTr("Customize profile")
property string customizeProfileDescription: qsTr("This profile is only shared with this account's contacts.\nThe profile can be changed at all times from the account's settings.")
property string encryptTitle: qsTr("Encrypt account with a password")
property string customizeProfileDescription: qsTr("This profile is only shared with account contacts.\nThe profile can be changed in account settings.")
property string encryptTitle: qsTr("Encrypt account with password")
property string encryptDescription: qsTr("A Jami account is created and stored locally only on this device, as an archive containing your account keys. Access to this archive can optionally be protected by a password.")
property string encryptWarning: qsTr("Please note that if you lose your password, it CANNOT be recovered!")
property string enterNickname: qsTr("Enter a nickname, surname…")
@ -450,17 +451,18 @@ Item {
// LinkedDevices
property string tipLinkNewDevice: qsTr("Link a new device to this 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:")
property string linkDeviceNetWorkError: qsTr("Error connecting to the network.\nPlease try again later.")
property string removeDevice: qsTr("Remove device")
property string confirmRemoveDevice: qsTr("Do you really want to unlink selected device? To continue, enter account password and click Unlink.")
property string yourPinIs: qsTr("Account PIN code is:")
property string linkDeviceNetWorkError: qsTr("A network error occurred while linking device.\nPlease try again later.")
// BannedContacts
property string banned: qsTr("Banned")
property string bannedContacts: qsTr("Banned contacts")
property string reinstateContact: qsTr("Reinstate as contact")
property string blocked: qsTr("Blocked")
property string blockedContacts: qsTr("Blocked contacts")
// DeleteAccountDialog
property string confirmDeleteQuestion: qsTr("Would you really like to delete this account?")
property string confirmDeleteAccount: qsTr("Do you really want to delete this account? To continue, click Delete.")
property string deleteAccountInfos: qsTr("If your account has not been backed up or added to another device, your account and registered username will be IRREVOCABLY LOST.")
// DeviceItemDelegate
@ -498,14 +500,14 @@ Item {
// File transfer settings
property string fileTransfer: qsTr("File transfer")
property string autoAcceptFiles: qsTr("Automatically accept incoming files")
property string acceptTransferBelow: qsTr("Accept transfer limit (in Mb)")
property string acceptTransferTooltip: qsTr("in MB, 0 = unlimited")
property string acceptTransferBelow: qsTr("Accept transfer limit (Mb)")
property string acceptTransferTooltip: qsTr("MB, 0 = unlimited")
// JamiUserIdentity settings
property string register: qsTr("Register")
property string incorrectPassword: qsTr("Incorrect password")
property string networkError: qsTr("Network error")
property string somethingWentWrong: qsTr("Something went wrong")
property string incorrectPassword: qsTr("Incorrect password.")
property string networkError: qsTr("A network error occurred.")
property string somethingWentWrong: qsTr("An unexpected error occurred.")
// Context Menu
property string saveFile: qsTr("Save file")
@ -518,20 +520,20 @@ Item {
property string enableAutoUpdates: qsTr("Enable/Disable automatic updates")
property string updatesTitle: qsTr("Updates")
property string updateDialogTitle: qsTr("Update")
property string updateFound: qsTr("A new version of Jami was found\nWould you like to update now?")
property string updateFound: qsTr("A new version of Jami was found.\nDo you want to update Jami now?\nTo continue, click Update.")
property string updateNotFound: qsTr("No new version of Jami was found")
property string updateCheckError: qsTr("An error occured when checking for a new version")
property string updateNetworkError: qsTr("Network error")
property string updateSSLError: qsTr("SSL error")
property string updateDownloadCanceled: qsTr("Installer download canceled")
property string updateCheckError: qsTr("An error occurred while checking for a new version.")
property string updateNetworkError: qsTr("A network error occurred.")
property string updateSSLError: qsTr("An SSL error occurred.")
property string updateDownloadCanceled: qsTr("Installer download was canceled by user.")
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 confirmBeta: qsTr("This will replace the Release version with the Beta version on this device. The latest Release version can always be downloaded from the Jami 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")
property string accessError: qsTr("An error occurred while accessing contents.")
property string contentNotFoundError: qsTr("Content not found.")
property string genericError: qsTr("An unexpected error occurred.")
//Troubleshoot Settings
// Troubleshoot Settings
property string troubleshootTitle: qsTr("Troubleshoot")
property string troubleshootButton: qsTr("Open logs")
property string troubleshootText: qsTr("Get logs")
@ -546,9 +548,9 @@ Item {
property string callRecording: qsTr("Call recording")
property string alwaysRecordCalls: qsTr("Always record calls")
// KeyboardShortCutTable
property string keyboardShortcutTableWindowTitle: qsTr("Keyboard Shortcut Table")
property string keyboardShortcuts: qsTr("Keyboard Shortcuts")
// Keyboard shortcuts
property string keyboardShortcutTableWindowTitle: qsTr("Keyboard shortcuts")
property string keyboardShortcuts: qsTr("Keyboard shortcuts")
property string conversationKeyboardShortcuts: qsTr("Conversation")
property string callKeyboardShortcuts: qsTr("Call")
property string settings: qsTr("Settings")
@ -557,11 +559,11 @@ Item {
// View Logs
property string logsViewTitle: qsTr("Debug")
property string logsViewCopy: qsTr("Copy")
property string logsViewReport: qsTr("Report Bug")
property string logsViewReport: qsTr("Submit issue")
property string logsViewClear: qsTr("Clear")
property string cancel: qsTr("Cancel")
property string logsViewCopied: qsTr("Copied to clipboard!")
property string logsViewDisplay: qsTr("Receive Logs")
property string logsViewDisplay: qsTr("View logs")
// ImportFromBackupPage
property string archive: qsTr("Archive")
@ -577,29 +579,29 @@ Item {
// ImportFromDevicePage
property string importButton: qsTr("Import")
property string pin: qsTr("Enter the PIN code")
property string importFromDeviceDescription: qsTr("A PIN is required to use an existing Jami account on this device.")
property string importStep1: qsTr("Step 01")
property string importStep2: qsTr("Step 02")
property string importStep3: qsTr("Step 03")
property string importStep4: qsTr("Step 04")
property string importStep1Desc: qsTr("Go to the account management settings of a previous device")
property string importStep2Desc: qsTr("Choose the account to link")
property string importStep3Desc: qsTr("Select \"Link another device\"")
property string importStep4Desc: qsTr("The PIN code will be available for 10 minutes")
property string importFromDeviceDescription: qsTr("A PIN code is required to use an existing Jami account on this device.")
property string importStep1: qsTr("Step 1")
property string importStep2: qsTr("Step 2")
property string importStep3: qsTr("Step 3")
property string importStep4: qsTr("Step 4")
property string importStep1Desc: qsTr("Go to the account management settings of a previous device.")
property string importStep2Desc: qsTr("Choose the account to link.")
property string importStep3Desc: qsTr("Select Link another device.”")
property string importStep4Desc: qsTr("The PIN code will expire in 10 minutes.")
property string importPasswordDesc: qsTr("Fill if the account is password-encrypted.")
// LinkDevicesDialog
property string pinTimerInfos: qsTr("The PIN and the account password should be entered in your device within 10 minutes.")
property string pinTimerInfos: qsTr("The PIN code and the account password should be entered in your device within 10 minutes.")
property string close: qsTr("Close")
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 pinExpired: qsTr("PIN code has 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 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: ")
property string linkingInstructions: qsTr("In Jami, scan QR code or manually enter PIN code.")
property string pinValidity: qsTr("The PIN code will expire in: ")
// PasswordDialog
property string enterPassword: qsTr("Enter password")
@ -611,14 +613,14 @@ Item {
property string exportAccount: qsTr("Export")
// PhotoBoothView
property string selectAvatarImage: qsTr("Select image as avatar")
property string selectImage: qsTr("Select image")
property string importFromFile: qsTr("Import avatar from image file")
property string removeImage: qsTr("Remove image")
property string selectProfilePicture: qsTr("Select image as profile picture")
property string selectImage: qsTr("How do you want to set the profile picture?")
property string importFromFile: qsTr("Import profile picture from image file")
property string removeImage: qsTr("Remove profile picture")
property string takePhoto: qsTr("Take photo")
property string imageFiles: qsTr("Image Files (*.jpeg *.jpg *.png *.JPEG* .JPG *.PNG)")
property string imageFiles: qsTr("Image files (*.jpeg *.jpg *.png *.JPEG* .JPG *.PNG)")
// Plugins
// Extensions
property string autoUpdate: qsTr("Auto update")
property string disableAll: qsTr("Disable all")
property string installed: qsTr("Installed")
@ -626,33 +628,34 @@ Item {
property string installing: qsTr("Installing")
property string installManually: qsTr("Install manually")
property string installMannuallyDescription: qsTr("Install an extension directly from your device.")
property string pluginStoreTitle: qsTr("Available")
property string pluginStoreNotAvailable: qsTr("Plugins store is not available")
property string storeNotSupportedPlatform: qsTr("The Jami Extension Store currently has no extension available for the platform in use. Check again later!")
property string pluginPreferences: qsTr("Preferences")
property string installationFailed: qsTr("Installation failed")
property string pluginInstallationFailed: qsTr("The installation of the plugin failed")
property string extensionStoreTitle: qsTr("Available")
property string extensionStoreNotAvailable: qsTr("The Jami Extension Store is not currently available. Please try again later.")
property string storeNotSupportedPlatform: qsTr("There are no extensions currently available in the Jami Extension Store for the platform in use. Please check again later.")
property string extensionPreferences: qsTr("Preferences")
property string installationFailed: qsTr("Installation error")
property string extensionInstallationFailed: qsTr("An error occurred while installing the extension.")
property string reset: qsTr("Reset")
property string uninstall: qsTr("Uninstall")
property string resetPreferences: qsTr("Reset Preferences")
property string selectPluginInstall: qsTr("Select a plugin to install")
property string uninstallPlugin: qsTr("Uninstall plugin")
property string pluginResetConfirmation: qsTr("Are you sure you wish to reset %1 preferences?")
property string pluginUninstallConfirmation: qsTr("Are you sure you wish to uninstall %1?")
property string goBackToPluginsList: qsTr("Go back to plugins list")
property string selectFile: qsTr("Select a file")
property string selectExtensionInstall: qsTr("Select extension to install")
property string uninstallExtension: qsTr("Uninstall extension")
property string confirmExtensionReset: qsTr("Do you really want to reset the preferences for the %1 extension?")
property string confirmExtensionUninstall: qsTr("Do you really want to uninstall the %1 extension?")
property string goBackToExtensionsList: qsTr("Go back to extensions list")
property string selectFile: qsTr("Select file")
property string select: qsTr("Select")
property string chooseImageFile: qsTr("Choose image file")
property string pluginFiles: qsTr("Plugin Files (*.jpl)")
property string extensionFiles: qsTr("Extension files (*.jpl)")
property string loadUnload: qsTr("Load/Unload")
property string selectAnImage: qsTr("Select An Image to %1")
property string editPreference: qsTr("Edit preference")
property string onOff: qsTr("On/Off")
property string choosePlugin: qsTr("Choose Plugin")
property string versionPlugin: qsTr("Version %1")
property string chooseExtension: qsTr("Choose extension")
property string versionExtension: qsTr("Version %1")
property string lastUpdate: qsTr("Last update %1")
property string by: qsTr("By %1")
property string proposedBy: qsTr("Proposed by %1")
// ProfilePage
property string information: qsTr("Information")
property string moreInformation: qsTr("More information")
@ -662,9 +665,9 @@ Item {
property string confirmRemovalRequest: qsTr("Enter the account password to confirm the removal of this device")
// SelectScreen
property string selectScreen: qsTr("Select a screen to share")
property string selectWindow: qsTr("Select a window to share")
property string allScreens: qsTr("All Screens")
property string selectScreen: qsTr("Select screen to share")
property string selectWindow: qsTr("Select window to share")
property string allScreens: qsTr("All screens")
property string screens: qsTr("Screens")
property string windows: qsTr("Windows")
property string screen: qsTr("Screen %1")
@ -682,7 +685,7 @@ Item {
property string connectJAMSServer: qsTr("Connect to a JAMS server")
property string createFromJAMS: qsTr("Create account from Jami Account Management Server (JAMS)")
property string addSIPAccount: qsTr("Configure a SIP account")
property string errorCreateAccount: qsTr("Error while creating your account. Check your credentials.")
property string errorCreateAccount: qsTr("An error occurred while creating the account. Check credentials and try again.")
property string createNewRV: qsTr("Create a rendezvous point")
property string joinJami: qsTr("Join Jami")
property string createNewJamiAccount: qsTr("Create new Jami account")
@ -694,9 +697,9 @@ Item {
property string welcomeToJami: qsTr("Welcome to Jami")
// SmartList
property string clearText: qsTr("Clear Text")
property string clearText: qsTr("Clear text")
property string conversations: qsTr("Conversations")
property string searchResults: qsTr("Search Results")
property string searchResults: qsTr("Search results")
// SmartList context menu
property string declineContactRequest: qsTr("Decline contact request")
@ -706,15 +709,16 @@ Item {
property string update: qsTr("Automatically check for updates")
// Generic dialog options
property string optionOk: qsTr("Ok")
property string optionOk: qsTr("OK")
property string optionSave: qsTr("Save")
property string optionCancel: qsTr("Cancel")
property string optionUpgrade: qsTr("Upgrade")
property string optionLater: qsTr("Later")
property string optionDelete: qsTr("Delete")
property string optionRemove: qsTr("Remove")
property string optionLeave: qsTr("Leave")
property string optionBlock: qsTr("Block")
property string optionUnban: qsTr("Unban")
property string optionUnblock: qsTr("Unblock")
// Conference moderation
property string setModerator: qsTr("Set moderator")
@ -735,8 +739,8 @@ Item {
property string removeDefaultModerator: qsTr("Remove default moderator")
// Daemon reconnection
property string reconnectDaemon: qsTr("Trying to reconnect to the Jami daemon (jamid)…")
property string reconnectionFailed: qsTr("Could not re-connect to the Jami daemon (jamid).\nJami will now quit.")
property string reconnectDaemon: qsTr("Attempting to reconnect to the Jami daemon (jamid)…")
property string reconnectionFailed: qsTr("An error occurred while reconnecting to the Jami daemon (jamid).\nThe application will now exit.")
// Message view
property string addEmoji: qsTr("Add emoji")
@ -774,8 +778,8 @@ Item {
property string edit: qsTr("Edit")
property string edited: qsTr("Edited")
property string joinCall: qsTr("Join call")
property string joinInAudio: qsTr("Join in audio")
property string joinInVideo: qsTr("Join in video")
property string joinWithAudio: qsTr("Join with audio")
property string joinWithVideo: qsTr("Join with video")
property string startedACall: qsTr("Started a call")
property string wantToJoin: qsTr("A call is in progress. Do you want to join the call?")
property string needsHost: qsTr("Current host for this swarm seems unreachable. Do you want to host the call?")
@ -790,28 +794,28 @@ Item {
property string hideLocalVideo: qsTr("Hide local video")
// Invitation View
property string invitationViewSentRequest: qsTr("%1 has sent you a request for a conversation.")
property string invitationViewJoinConversation: qsTr("Hello,\nWould you like to join the conversation?")
property string invitationViewAcceptedConversation: qsTr("You have accepted\nthe conversation request")
property string invitationViewSentRequest: qsTr("%1 sent you a conversation invitation.")
property string invitationViewJoinConversation: qsTr("Hello,\nDo you want to join this conversation?")
property string invitationViewAcceptedConversation: qsTr("You have accepted\nthe conversation invitation.")
property string invitationViewWaitingForSync: qsTr("Waiting until %1\nconnects to synchronize the conversation.")
// SwarmDetailsPanel
property string members: qsTr("%1 Members")
property string member: qsTr("Member")
property string swarmName: qsTr("Swarm's name")
property string contactName: qsTr("Contact's name")
property string addADescription: qsTr("Add a description")
property string swarmName: qsTr("Swarm name")
property string contactName: qsTr("Contact name")
property string addDescription: qsTr("Add description")
property string muteConversation: qsTr("Mute conversation")
property string ignoreNotificationsTooltip: qsTr("Ignore all notifications from this conversation")
property string chooseAColor: qsTr("Choose a color")
property string chooseAColor: qsTr("Color")
property string defaultCallHost: qsTr("Default host (calls)")
property string leaveConversation: qsTr("Leave conversation")
property string typeOfSwarm: qsTr("Type of swarm")
property string typeOfSwarm: qsTr("Type")
property string none: qsTr("None")
// NewSwarmPage
property string createTheSwarm: qsTr("Create the swarm")
property string createSwarm: qsTr("Create swarm")
property string goToConversation: qsTr("Go to conversation")
property string kickMember: qsTr("Kick member")
property string reinstateMember: qsTr("Reinstate member")
@ -864,20 +868,20 @@ Item {
property string theme: qsTr("Theme")
property string zoomLevel: qsTr("Text zoom level")
//Donation campaign
// Donation campaign
property string donationTipBoxText: qsTr("Free and private sharing. <a href=\"https://jami.net/whydonate/\">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
// 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
// Connection monitoring
property string connected: qsTr("Connected")
property string connectingTLS: qsTr("Connecting TLS")
property string connectingICE: qsTr("Connecting ICE")

View File

@ -88,7 +88,7 @@ SidePanelBase {
"visible": AppVersionManager.isUpdaterEnabled()
}]
}, {
"title": JamiStrings.audioVideoSettingsTitle,
"title": JamiStrings.mediaSettingsTitle,
"icon": JamiResources.media_black_24dp_svg,
"first": 12,
"last": 14,
@ -103,13 +103,13 @@ SidePanelBase {
"title": JamiStrings.screenSharing
}]
}, {
"title": JamiStrings.pluginSettingsTitle,
"title": JamiStrings.extensionSettingsTitle,
"icon": JamiResources.plugins_24dp_svg,
"first": 15,
"last": 15,
"children": [{
"id": 15,
"title": JamiStrings.pluginSettingsTitle
"title": JamiStrings.extensionSettingsTitle
}]
}];
} else {
@ -160,7 +160,7 @@ SidePanelBase {
"title": JamiStrings.troubleshootTitle
}]
}, {
"title": JamiStrings.audioVideoSettingsTitle,
"title": JamiStrings.mediaSettingsTitle,
"icon": JamiResources.media_black_24dp_svg,
"first": 12,
"last": 14,
@ -175,13 +175,13 @@ SidePanelBase {
"title": JamiStrings.screenSharing
}]
}, {
"title": JamiStrings.pluginSettingsTitle,
"title": JamiStrings.extensionSettingsTitle,
"icon": JamiResources.plugins_24dp_svg,
"first": 15,
"last": 15,
"children": [{
"id": 15,
"title": JamiStrings.pluginSettingsTitle
"title": JamiStrings.extensionSettingsTitle
}]
}];
}

View File

@ -49,7 +49,7 @@ ColumnLayout {
contactName: ContactName
contactID: ContactID
btnImgSource: JamiStrings.optionUnban
btnImgSource: JamiStrings.optionUnblock
btnToolTip: JamiStrings.reinstateContact
onClicked: bannedListWidget.currentIndex = index

View File

@ -10,10 +10,10 @@ import "../../commoncomponents"
ColumnLayout {
function installPlugin() {
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
"title": JamiStrings.selectPluginInstall,
"title": JamiStrings.selectExtensionInstall,
"fileMode": JamiFileDialog.OpenFile,
"folder": StandardPaths.writableLocation(StandardPaths.DownloadLocation),
"nameFilters": [JamiStrings.pluginFiles, JamiStrings.allFiles]
"nameFilters": [JamiStrings.extensionFiles, JamiStrings.allFiles]
});
dlg.fileAccepted.connect(function (file) {
var url = UtilsAdapter.getAbsPath(file.toString());
@ -29,7 +29,7 @@ ColumnLayout {
function presentErrorMessage() {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.installationFailed,
"infoText": JamiStrings.pluginInstallationFailed,
"infoText": JamiStrings.extensionInstallationFailed,
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonTitles": [JamiStrings.optionOk],
"buttonCallBacks": [],

View File

@ -53,7 +53,7 @@ BaseModalDialog {
pinRectangle.visible = true
exportedPIN.text = pin;
} else {
pinRectangle.success = false;
infoLabel.success = false;
infoLabel.visible = true;
switch (status) {
case NameDirectory.ExportOnRingStatus.WRONG_PASSWORD:

View File

@ -44,7 +44,7 @@ ColumnLayout {
} else {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.removeDevice,
"infoText": JamiStrings.sureToRemoveDevice,
"infoText": JamiStrings.confirmRemoveDevice,
"buttonTitles": [JamiStrings.optionOk, JamiStrings.optionCancel],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack],
"buttonCallBacks": [function () {

View File

@ -387,7 +387,7 @@ SettingsPageBase {
Layout.alignment: Qt.AlignLeft
Layout.preferredWidth: parent.width
text: JamiStrings.bannedContacts
text: JamiStrings.blockedContacts
color: JamiTheme.textColor
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter

View File

@ -60,7 +60,7 @@ ItemDelegate {
function presentErrorMessage() {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.installationFailed,
"infoText": JamiStrings.pluginInstallationFailed,
"infoText": JamiStrings.extensionInstallationFailed,
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonTitles": [JamiStrings.optionOk],
"buttonCallBacks": [],

View File

@ -58,7 +58,7 @@ ItemDelegate {
function presentErrorMessage() {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.installationFailed,
"infoText": JamiStrings.pluginInstallationFailed,
"infoText": JamiStrings.extensionInstallationFailed,
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonTitles": [JamiStrings.optionOk],
"buttonCallBacks": []

View File

@ -275,7 +275,7 @@ Rectangle {
onClicked: viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.resetPreferences,
"infoText": JamiStrings.pluginResetConfirmation.arg(pluginId),
"infoText": JamiStrings.confirmExtensionReset.arg(pluginId),
"buttonTitles": [JamiStrings.optionOk, JamiStrings.optionCancel],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack],
"buttonCallBacks": [function () {

View File

@ -204,7 +204,7 @@ Item {
}
Label {
Layout.fillWidth: true
text: JamiStrings.versionPlugin.arg(PluginVersion)
text: JamiStrings.versionExtension.arg(PluginVersion)
font.pixelSize: JamiTheme.headerFontSize
font.kerning: true
color: JamiTheme.textColor
@ -273,13 +273,13 @@ Item {
hoveredColor: JamiTheme.buttonTintedBlackHovered
pressedColor: JamiTheme.buttonTintedBlackPressed
tertiary: true
toolTipText: JamiStrings.pluginUninstallConfirmation.arg(PluginId)
toolTipText: JamiStrings.confirmExtensionUninstall.arg(PluginId)
text: JamiStrings.uninstall
onClicked: viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.uninstallPlugin,
"infoText": JamiStrings.pluginUninstallConfirmation.arg(PluginName),
"title": JamiStrings.uninstallExtension,
"infoText": JamiStrings.confirmExtensionUninstall.arg(PluginName),
"buttonTitles": [JamiStrings.optionOk, JamiStrings.optionCancel],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue, SimpleMessageDialog.ButtonStyle.TintedBlack],
"buttonCallBacks": [function () {

View File

@ -25,7 +25,7 @@ import "../../commoncomponents"
SettingsPageBase {
id: root
title: JamiStrings.pluginSettingsTitle
title: JamiStrings.extensionSettingsTitle
onWidthChanged: resolvePanes()
flickableContent: RowLayout {
width: parent.width

View File

@ -46,7 +46,7 @@ ColumnLayout {
Label {
Layout.fillWidth: true
Layout.bottomMargin: 20
text: JamiStrings.pluginStoreTitle
text: JamiStrings.extensionStoreTitle
font.pixelSize: JamiTheme.settingsTitlePixelSize
font.kerning: true
color: JamiTheme.textColor
@ -113,7 +113,7 @@ ColumnLayout {
color: JamiTheme.textColor
font.pixelSize: JamiTheme.bigFontSize
horizontalAlignment: Text.AlignHCenter
text: JamiStrings.pluginStoreNotAvailable
text: JamiStrings.extensionStoreNotAvailable
}
}
Loader {

View File

@ -111,7 +111,7 @@ SettingsPageBase {
font.pointSize: 18
font.capitalization: Font.AllUppercase
color: "white"
text: JamiStrings.noVideo
text: JamiStrings.noCamera
}
}
}

View File

@ -87,14 +87,14 @@ TipsModel::reset()
tips_.append({{"id", "1"},
{"title", tr("What does Jami mean?")},
{"desc",
tr("The choice of the name Jami was inspired by the Swahili word 'jamii', which "
"means 'community' as a noun and 'together' as an adverb.")},
tr("The choice of the name Jami was inspired by the Swahili word jamii, which "
"means community as a noun and together as an adverb.")},
{"type", "tip"}});
tips_.append({{"id", "2"},
{"title", tr("What is the green dot next to my account?")},
{"desc",
tr("A red dot means that your account is disconnected from the network; it "
"turns green when it's connected.")},
"turns green when its connected.")},
{"type", "tip"}});
tips_.append(
{{"id", "3"},
@ -108,7 +108,7 @@ TipsModel::reset()
{{"id", "4"},
{"title", tr("Can I make a conference call?")},
{"desc",
tr("In a call, you can click on \"Add participants\" to add a contact to a call.")},
tr("In a call, you can click on “Invite members” to add a contact to a call.")},
{"type", "tip"}});
tips_.append({{"id", "6"},
{"title", tr("What is a Jami account?")},
@ -124,7 +124,7 @@ TipsModel::reset()
{"type", "tip"}});
tips_.append(
{{"id", "8"},
{"title", tr("Why don't I have to use a password?")},
{"title", tr("Why dont I have to use a password?")},
{"desc",
tr("With Jami, your account is stored in a directory on your device. The password "
"is only used to encrypt your account in order to protect you from someone "
@ -132,7 +132,7 @@ TipsModel::reset()
{"type", "tip"}});
tips_.append(
{{"id", "9"},
{"title", tr("Why don't I have to register a username?")},
{"title", tr("Why dont I have to register a username?")},
{"desc",
tr("The most permanent, secure identifier is your Jami ID, but since these are difficult "
"to use for some people, you also have the option of registering a username.")},

View File

@ -420,8 +420,14 @@ Utils::contactPhoto(LRCInstance* instance,
try {
auto& accInfo = instance->accountModel().getAccountInfo(
accountId.isEmpty() ? instance->get_currentAccountId() : accountId);
auto contactInfo = accInfo.contactModel->getContact(contactUri);
auto contactPhoto = accInfo.contactModel->avatar(contactUri);
if (!contactPhoto.isEmpty()) {
photo = imageFromBase64String(contactPhoto);
if (!photo.isNull())
return Utils::scaleAndFrame(photo, size);
}
// If no avatar is found, generate one
auto contactInfo = accInfo.contactModel->getContact(contactUri);
auto bestName = accInfo.contactModel->bestNameForContact(contactUri);
if (accInfo.profileInfo.type == profile::Type::SIP
&& contactInfo.profileInfo.type == profile::Type::TEMPORARY) {
@ -429,12 +435,6 @@ Utils::contactPhoto(LRCInstance* instance,
} else if (contactInfo.profileInfo.type == profile::Type::TEMPORARY
&& contactInfo.profileInfo.uri.isEmpty()) {
photo = Utils::fallbackAvatar(QString(), QString());
} else if (!contactPhoto.isEmpty()) {
photo = imageFromBase64String(contactPhoto);
if (photo.isNull()) {
auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
photo = Utils::fallbackAvatar("jami:" + contactInfo.profileInfo.uri, avatarName);
}
} else {
auto avatarName = contactInfo.profileInfo.uri == bestName ? QString() : bestName;
photo = Utils::fallbackAvatar("jami:" + contactInfo.profileInfo.uri, avatarName);
@ -540,13 +540,20 @@ Utils::getCirclePhoto(const QImage original, int sizePhoto)
Qt::KeepAspectRatioByExpanding,
Qt::SmoothTransformation)
.convertToFormat(QImage::Format_ARGB32_Premultiplied);
int margin = 0;
int marginX = 0;
int marginY = 0;
if (scaledPhoto.width() > sizePhoto) {
margin = (scaledPhoto.width() - sizePhoto) / 2;
marginX = (scaledPhoto.width() - sizePhoto) / 2;
}
if (scaledPhoto.height() > sizePhoto) {
marginY = (scaledPhoto.height() - sizePhoto) / 2;
}
painter.drawEllipse(0, 0, sizePhoto, sizePhoto);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.drawImage(0, 0, scaledPhoto, margin, 0);
painter.drawImage(0, 0, scaledPhoto, marginX, marginY);
return target;
}
@ -612,7 +619,12 @@ Utils::getProjectCredits()
return {};
}
QTextStream in(&projectCreditsFile);
return in.readAll();
return in.readAll().arg(
QObject::tr("We would like to thank our contributors, whose efforts over many years have made this software what it is."),
QObject::tr("Developers"), QObject::tr("Media"), QObject::tr("Community Management"), QObject::tr("Special thanks to"),
QObject::tr("This is a list of people who have made a significant investment of time,\
with useful results, into Jami. Any such contributors who wish to be added to the list \
should contact us."));
}
inline QString

View File

@ -26,6 +26,7 @@
#include "systemtray.h"
#include "utils.h"
#include "version.h"
#include "version_info.h"
#include "global.h"
#include <api/datatransfermodel.h>
@ -125,11 +126,17 @@ UtilsAdapter::getProjectCredits()
}
const QString
UtilsAdapter::getVersionStr()
UtilsAdapter::getBuildIDStr()
{
return QString(VERSION_STRING);
}
const QString
UtilsAdapter::getVersionStr()
{
return APP_VERSION_STRING + "." + CORE_VERSION_STRING;
}
void
UtilsAdapter::setClipboardText(QString text)
{

View File

@ -96,6 +96,7 @@ public:
Q_INVOKABLE void setToDefault(const Settings::Key key);
Q_INVOKABLE const QString getProjectCredits();
Q_INVOKABLE const QString getBuildIDStr();
Q_INVOKABLE const QString getVersionStr();
Q_INVOKABLE void setClipboardText(QString text);
Q_INVOKABLE const QString qStringFromFile(const QString& filename);

View File

@ -275,6 +275,7 @@ set(LIBCLIENT_SOURCES
# other
avmodel.cpp
pluginmodel.cpp
interaction.cpp
namedirectory.cpp
renderer.cpp)

View File

@ -166,7 +166,6 @@ public Q_SLOTS:
* @param ok
*/
void slotMigrationEnded(const QString& accountId, bool ok);
/**
* Emit accountProfileReceived
* @param accountId
@ -176,7 +175,6 @@ public Q_SLOTS:
void slotAccountProfileReceived(const QString& accountId,
const QString& displayName,
const QString& userPhoto);
/**
* Emit new position
* @param accountId
@ -415,10 +413,6 @@ AccountModelPimpl::AccountModelPimpl(AccountModel& linked,
&CallbacksHandler::migrationEnded,
this,
&AccountModelPimpl::slotMigrationEnded);
connect(&callbacksHandler,
&CallbacksHandler::accountProfileReceived,
this,
&AccountModelPimpl::slotAccountProfileReceived);
connect(&callbacksHandler,
&CallbacksHandler::newPosition,
this,
@ -434,8 +428,9 @@ AccountModelPimpl::updateAccounts()
const auto previousAccountIdListSize = accountIdList.size();
accountIdList = configurationManager.getAccountList();
// If this is just a reordering of the accounts, don't do anything
// If this is just a reordering of the accounts, just notify the view.
if (accountIdList.size() == previousAccountIdListSize) {
Q_EMIT linked.accountsReordered();
return;
}
@ -531,11 +526,12 @@ AccountModelPimpl::slotAccountStatusChanged(const QString& accountID,
if (status != api::account::Status::INITIALIZING
&& accountInfo.status == api::account::Status::INITIALIZING) {
// Detect when a new account is generated (keys are ready). During
// the generation, a Ring account got the "INITIALIZING" status.
// the generation, an account got the "INITIALIZING" status.
// When keys are generated, the status will change.
// The account is already added and initialized. Just update details from daemon
updateAccountDetails(accountInfo);
// This will load swarms as the account was not loaded before.
accountInfo.contactModel->initContacts();
accountInfo.conversationModel->initConversations();
Q_EMIT linked.accountAdded(accountID);
} else if (!accountInfo.profileInfo.uri.isEmpty()) {
@ -690,25 +686,6 @@ AccountModelPimpl::slotMigrationEnded(const QString& accountId, bool ok)
Q_EMIT linked.migrationEnded(accountId, ok);
}
void
AccountModelPimpl::slotAccountProfileReceived(const QString& accountId,
const QString& displayName,
const QString& userPhoto)
{
LC_WARN << accountId << displayName;
auto account = accounts.find(accountId);
if (account == accounts.end())
return;
auto& accountInfo = account->second.first;
accountInfo.profileInfo.avatar = userPhoto;
accountInfo.profileInfo.alias = displayName;
storage::vcard::setProfile(accountInfo.id, accountInfo.profileInfo);
Q_EMIT linked.profileUpdated(accountId);
}
void
AccountModelPimpl::slotNewPosition(const QString& accountId,
const QString& peerId,
@ -719,6 +696,24 @@ AccountModelPimpl::slotNewPosition(const QString& accountId,
Q_EMIT linked.newPosition(accountId, peerId, body, timestamp, daemonId);
}
void
AccountModelPimpl::slotAccountProfileReceived(const QString& accountId,
const QString& displayName,
const QString& userPhoto)
{
LC_WARN << accountId << displayName;
auto account = accounts.find(accountId);
if (account == accounts.end() || userPhoto.isEmpty())
return;
// NOTE: This signal is still used for JAMS account where the avatar is
// retrieven from the server. In this case we MUST save it.
auto& accountInfo = account->second.first;
accountInfo.profileInfo.avatar = userPhoto;
accountInfo.profileInfo.alias = displayName;
storage::vcard::setProfile(accountInfo.id, accountInfo.profileInfo);
Q_EMIT linked.profileUpdated(accountId);
}
void
AccountModelPimpl::addToAccounts(const QString& accountId)
{

View File

@ -288,6 +288,10 @@ Q_SIGNALS:
* @param accountID
*/
void accountRemoved(const QString& accountID);
/**
* Emitted when the account list order has changed.
*/
void accountsReordered();
/**
* Connect this signal to know when an account was updated.
* @param accountID

View File

@ -168,8 +168,12 @@ struct Info
if (media[MediaAttributeKey::MEDIA_TYPE] == Details::MEDIA_TYPE_VIDEO) {
if (media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::DISPLAY)
|| media[MediaAttributeKey::SOURCE].startsWith(VideoProtocolPrefix::FILE)) {
callInfo["is_sharing"] = true;
callInfo["preview_id"] = media[MediaAttributeKey::SOURCE];
if (media[MediaAttributeKey::MUTED] == TRUE_STR) {
callInfo["is_sharing"] = false;
} else {
callInfo["is_sharing"] = true;
previewId = media[MediaAttributeKey::SOURCE];
}
}
if (media[MediaAttributeKey::ENABLED] == TRUE_STR
&& media[MediaAttributeKey::MUTED] == FALSE_STR && previewId.isEmpty()) {

View File

@ -62,6 +62,8 @@ public:
const BehaviorController& behaviorController);
~ContactModel();
void initContacts();
/**
* Ask the daemon to add a contact.
* @param contactInfo

View File

@ -38,7 +38,7 @@ namespace api {
class BehaviorController;
namespace datatransfer {
class Info;
struct Info;
} // namespace datatransfer
/**

View File

@ -20,6 +20,7 @@
#include <QString>
#include <QObject>
#include <QFileInfo>
#include <ctime>
#include "typedefs.h"
@ -119,6 +120,12 @@ enum class Status {
FAILURE,
SUCCESS,
DISPLAYED,
COUNT__
};
Q_ENUM_NS(Status)
enum class TransferStatus {
INVALID,
TRANSFER_CREATED,
TRANSFER_ACCEPTED,
TRANSFER_CANCELED,
@ -131,7 +138,7 @@ enum class Status {
TRANSFER_FINISHED,
COUNT__
};
Q_ENUM_NS(Status)
Q_ENUM_NS(TransferStatus)
static inline const QString
to_string(const Status& status)
@ -147,26 +154,6 @@ to_string(const Status& status)
return "SUCCESS";
case Status::DISPLAYED:
return "DISPLAYED";
case Status::TRANSFER_CREATED:
return "TRANSFER_CREATED";
case Status::TRANSFER_ACCEPTED:
return "TRANSFER_ACCEPTED";
case Status::TRANSFER_CANCELED:
return "TRANSFER_CANCELED";
case Status::TRANSFER_ERROR:
return "TRANSFER_ERROR";
case Status::TRANSFER_UNJOINABLE_PEER:
return "TRANSFER_UNJOINABLE_PEER";
case Status::TRANSFER_ONGOING:
return "TRANSFER_ONGOING";
case Status::TRANSFER_AWAITING_HOST:
return "TRANSFER_AWAITING_HOST";
case Status::TRANSFER_AWAITING_PEER:
return "TRANSFER_AWAITING_PEER";
case Status::TRANSFER_TIMEOUT_EXPIRED:
return "TRANSFER_TIMEOUT_EXPIRED";
case Status::TRANSFER_FINISHED:
return "TRANSFER_FINISHED";
case Status::INVALID:
case Status::COUNT__:
default:
@ -187,30 +174,68 @@ to_status(const QString& status)
return Status::SUCCESS;
else if (status == "DISPLAYED")
return Status::DISPLAYED;
else if (status == "TRANSFER_CREATED")
return Status::TRANSFER_CREATED;
else if (status == "TRANSFER_ACCEPTED")
return Status::TRANSFER_ACCEPTED;
else if (status == "TRANSFER_CANCELED")
return Status::TRANSFER_CANCELED;
else if (status == "TRANSFER_ERROR")
return Status::TRANSFER_ERROR;
else if (status == "TRANSFER_UNJOINABLE_PEER")
return Status::TRANSFER_UNJOINABLE_PEER;
else if (status == "TRANSFER_ONGOING")
return Status::TRANSFER_ONGOING;
else if (status == "TRANSFER_AWAITING_HOST")
return Status::TRANSFER_AWAITING_HOST;
else if (status == "TRANSFER_AWAITING_PEER")
return Status::TRANSFER_AWAITING_PEER;
else if (status == "TRANSFER_TIMEOUT_EXPIRED")
return Status::TRANSFER_TIMEOUT_EXPIRED;
else if (status == "TRANSFER_FINISHED")
return Status::TRANSFER_FINISHED;
else
return Status::INVALID;
}
static inline const QString
to_string(const TransferStatus& status)
{
switch (status) {
case TransferStatus::TRANSFER_CREATED:
return "TRANSFER_CREATED";
case TransferStatus::TRANSFER_ACCEPTED:
return "TRANSFER_ACCEPTED";
case TransferStatus::TRANSFER_CANCELED:
return "TRANSFER_CANCELED";
case TransferStatus::TRANSFER_ERROR:
return "TRANSFER_ERROR";
case TransferStatus::TRANSFER_UNJOINABLE_PEER:
return "TRANSFER_UNJOINABLE_PEER";
case TransferStatus::TRANSFER_ONGOING:
return "TRANSFER_ONGOING";
case TransferStatus::TRANSFER_AWAITING_HOST:
return "TRANSFER_AWAITING_HOST";
case TransferStatus::TRANSFER_AWAITING_PEER:
return "TRANSFER_AWAITING_PEER";
case TransferStatus::TRANSFER_TIMEOUT_EXPIRED:
return "TRANSFER_TIMEOUT_EXPIRED";
case TransferStatus::TRANSFER_FINISHED:
return "TRANSFER_FINISHED";
case TransferStatus::INVALID:
case TransferStatus::COUNT__:
default:
return "INVALID";
}
}
static inline TransferStatus
to_transferStatus(const QString& status)
{
if (status == "TRANSFER_CREATED")
return TransferStatus::TRANSFER_CREATED;
else if (status == "TRANSFER_ACCEPTED")
return TransferStatus::TRANSFER_ACCEPTED;
else if (status == "TRANSFER_CANCELED")
return TransferStatus::TRANSFER_CANCELED;
else if (status == "TRANSFER_ERROR")
return TransferStatus::TRANSFER_ERROR;
else if (status == "TRANSFER_UNJOINABLE_PEER")
return TransferStatus::TRANSFER_UNJOINABLE_PEER;
else if (status == "TRANSFER_ONGOING")
return TransferStatus::TRANSFER_ONGOING;
else if (status == "TRANSFER_AWAITING_HOST")
return TransferStatus::TRANSFER_AWAITING_HOST;
else if (status == "TRANSFER_AWAITING_PEER")
return TransferStatus::TRANSFER_AWAITING_PEER;
else if (status == "TRANSFER_TIMEOUT_EXPIRED")
return TransferStatus::TRANSFER_TIMEOUT_EXPIRED;
else if (status == "TRANSFER_FINISHED")
return TransferStatus::TRANSFER_FINISHED;
else
return TransferStatus::INVALID;
}
enum class ContactAction { ADD, JOIN, LEAVE, BANNED, UNBANNED, INVALID };
Q_ENUM_NS(ContactAction)
@ -366,6 +391,7 @@ public:
* @var duration
* @var type
* @var status
* @var transferStatus
* @var isRead
* @var commit
* @var linkPreviewInfo
@ -381,6 +407,7 @@ struct Info
std::time_t duration = 0;
Type type = Type::INVALID;
Status status = Status::INVALID;
TransferStatus transferStatus = TransferStatus::INVALID;
bool isRead = false;
MapStringString commit;
QVariantMap linkPreviewInfo = {};
@ -397,108 +424,37 @@ struct Info
std::time_t duration,
Type type,
Status status,
bool isRead)
{
this->authorUri = authorUri;
this->body = body;
this->timestamp = timestamp;
this->duration = duration;
this->type = type;
this->status = status;
this->isRead = isRead;
}
bool isRead,
TransferStatus transferStatus = TransferStatus::INVALID);
static Info contact(const QString& authorUri, std::time_t timestamp);
Info(const Info& other) = default;
Info(Info&& other) = default;
Info& operator=(const Info& other) = delete;
Info& operator=(Info&& other) = default;
bool sent() const
{
return status == Status::SUCCESS || status == Status::DISPLAYED || status == Status::TRANSFER_FINISHED;
}
bool sent() const;
void init(const MapStringString& message, const QString& accountURI)
{
type = to_type(message["type"]);
if (message.contains("react-to") && type == Type::TEXT) {
type = to_type("REACTION");
react_to = message["react-to"];
}
authorUri = message["author"];
void init(const MapStringString& message,
const QString& accountURI,
const QString& accountId,
const QString& conversationId);
if (type == Type::TEXT) {
body = message["body"];
}
timestamp = message["timestamp"].toInt();
status = Status::SUCCESS;
parentId = message["linearizedParent"];
isRead = false;
if (type == Type::CONTACT) {
authorUri = accountURI == message["uri"] ? "" : message["uri"];
} else if (type == Type::INITIAL) {
if (message["mode"] == "0") {
body = QObject::tr("Private conversation created");
} else {
body = QObject::tr("Swarm created");
}
} else if (type == Type::CALL) {
duration = message["duration"].toInt() / 1000;
if (message.contains("confId"))
confId = message["confId"];
}
commit = message;
}
// NOTE: The `accountId` and `conversationId` arguments are only used for messages of
// type DATA_TRANSFER. They can therefore be omitted if the caller knows that `message`
// is of a different type. They must be provided otherwise, as failure to do so would
// result in the `body` and `transferStatus` fields of the returned Info struct to
// contain incorrect information whenever `message` is of type DATA_TRANSFER.
Info(const MapStringString& message,
const QString& accountURI,
const QString& accountId = "",
const QString& conversationId = "");
Info(const MapStringString& message, const QString& accountURI)
{
init(message, accountURI);
}
Info(const SwarmMessage& msg, const QString& accountUri)
{
MapStringString msgBody;
for (auto it = msg.body.cbegin(); it != msg.body.cend(); ++it) {
const auto& key = it.key();
const auto& value = it.value();
msgBody.insert(key, value);
}
init(msgBody, accountUri);
parentId = msg.linearizedParent;
type = to_type(msg.type);
for (const auto& edition : msg.editions)
previousBodies.append(Body {edition.value("id"),
edition.value("body"),
QString(edition.value("timestamp")).toInt()});
QMap<QString, QVariantList> mapStringEmoji;
for (const auto& reaction : msg.reactions) {
auto author = reaction.value("author");
auto body = reaction.value("body");
auto emoji = Emoji {reaction.value("id"), body};
QVariant variant = QVariant::fromValue(emoji);
mapStringEmoji[author].append(variant);
}
for (auto i = mapStringEmoji.begin(); i != mapStringEmoji.end(); i++)
reactions.insert(i.key(), i.value());
// Compute the status of the message.
// Basically, we got the status per member.
// We consider the message as sent if at least one member has received it or displayed if
// someone displayed it.
auto maxStatus = 0;
status = Status::SENDING;
for (const auto& member : msg.status.keys()) {
if (member == accountUri)
continue;
auto stValue = msg.status.value(member);
if (stValue > maxStatus) {
maxStatus = stValue;
status = maxStatus <= 1 ? Status::SENDING
: (stValue == 2 ? Status::SUCCESS : Status::DISPLAYED);
}
if (maxStatus == 3)
break;
}
}
Info(const SwarmMessage& msg,
const QString& accountUri,
const QString& accountId,
const QString& conversationId);
};
static inline bool

View File

@ -40,6 +40,7 @@ struct Info;
X(Duration) \
X(Type) \
X(Status) \
X(TransferStatus) \
X(IsRead) \
X(ContactAction) \
X(ActionUri) \
@ -54,6 +55,7 @@ struct Info;
X(ReplyToAuthor) \
X(TotalSize) \
X(TransferName) \
X(TID) \
X(FileExtension) \
X(Readers) \
X(IsEmojiOnly) \
@ -101,6 +103,7 @@ public:
bool append(const QString& id, const interaction::Info& interaction);
bool update(const QString& id, const interaction::Info& interaction);
bool updateStatus(const QString& id, interaction::Status newStatus, const QString& newBody = {});
bool updateTransferStatus(const QString& id, interaction::TransferStatus newStatus, const QString& newBody = {});
QPair<bool, bool> addOrUpdate(const QString& id, const interaction::Info& interaction);
// Thread-safe access to interactions.

View File

@ -482,14 +482,7 @@ beginConversationWithPeer(Database& db,
db.insertInto("conversations",
{{":id", "id"}, {":participant", "participant"}},
{{":id", newConversationsId}, {":participant", peer_uri}});
api::interaction::Info msg {isOutgoing ? "" : peer_uri,
{},
timestamp ? timestamp : std::time(nullptr),
0,
api::interaction::Type::CONTACT,
isOutgoing ? api::interaction::Status::SUCCESS
: api::interaction::Status::UNKNOWN,
isOutgoing};
api::interaction::Info msg = api::interaction::Info::contact(isOutgoing ? "" : peer_uri, timestamp);
// Add first interaction
addMessageToConversation(db, newConversationsId, msg);
return newConversationsId;
@ -696,9 +689,9 @@ updateDataTransferInteractionForDaemonId(Database& db,
return;
}
auto body = result[0];
auto status = api::interaction::to_status(result[1]);
auto status = api::interaction::to_transferStatus(result[1]);
interaction.body = body;
interaction.status = status;
interaction.transferStatus = status;
}
QString
@ -731,6 +724,16 @@ updateInteractionStatus(Database& db, const QString& id, api::interaction::Statu
{{":id", id}});
}
void
updateInteractionTransferStatus(Database& db, const QString& id, api::interaction::TransferStatus newStatus)
{
db.update("interactions",
{"status=:status"},
{{":status", api::interaction::to_string(newStatus)}},
"id=:id",
{{":id", id}});
}
void
setInteractionRead(Database& db, const QString& id)
{

View File

@ -310,6 +310,7 @@ void updateInteractionBody(Database& db, const QString& id, const QString& newBo
* @param isRead
*/
void updateInteractionStatus(Database& db, const QString& id, api::interaction::Status newStatus);
void updateInteractionTransferStatus(Database& db, const QString& id, api::interaction::TransferStatus newStatus);
/**
* Set interaction to the read state

View File

@ -663,14 +663,6 @@ CallbacksHandler::slotKnownDevicesChanged(const QString& accountId, const MapStr
Q_EMIT knownDevicesChanged(accountId, devices);
}
void
CallbacksHandler::slotDeviceRevokationEnded(const QString& accountId,
const QString& deviceId,
const int status)
{
Q_EMIT deviceRevocationEnded(accountId, deviceId, status);
}
void
CallbacksHandler::slotAccountProfileReceived(const QString& accountId,
const QString& displayName,
@ -679,6 +671,14 @@ CallbacksHandler::slotAccountProfileReceived(const QString& accountId,
Q_EMIT accountProfileReceived(accountId, displayName, userPhoto);
}
void
CallbacksHandler::slotDeviceRevokationEnded(const QString& accountId,
const QString& deviceId,
const int status)
{
Q_EMIT deviceRevocationEnded(accountId, deviceId, status);
}
void
CallbacksHandler::slotExportOnRingEnded(const QString& accountId, int status, const QString& pin)
{

View File

@ -145,12 +145,6 @@ public:
QStringList getCallIds();
/**
* Send the profile VCard into a call
* @param callId
*/
void sendProfile(const QString& callId);
CallModel::CallInfoMap calls;
CallModel::CallParticipantsModelMap participantsModel;
const CallbacksHandler& callbacksHandler;
@ -1550,7 +1544,6 @@ CallModelPimpl::slotCallStateChanged(const QString& accountId,
|| previousStatus == call::Status::OUTGOING_RINGING) {
call->startTime = std::chrono::steady_clock::now();
Q_EMIT linked.callStarted(callId);
sendProfile(callId);
}
// Add to calls if in pendingConferences_
for (int i = 0; i < pendingConferencees_.size(); ++i) {
@ -1783,31 +1776,6 @@ CallModelPimpl::slotConferenceChanged(const QString& accountId,
Q_EMIT linked.currentCallChanged(currentCall_);
}
void
CallModelPimpl::sendProfile(const QString& callId)
{
auto vCard = linked.owner.accountModel->accountVCard(linked.owner.id);
std::random_device rdev;
auto key = std::to_string(dis(rdev));
int i = 0;
int total = vCard.size() / 1000 + (vCard.size() % 1000 ? 1 : 0);
while (vCard.size()) {
auto sizeLimit = std::min(1000, static_cast<int>(vCard.size()));
MapStringString chunk;
chunk[QString("%1; id=%2,part=%3,of=%4")
.arg(lrc::vCard::PROFILE_VCF)
.arg(key.c_str())
.arg(QString::number(i + 1))
.arg(QString::number(total))]
= vCard.left(sizeLimit);
vCard.remove(0, sizeLimit);
++i;
CallManager::instance().sendTextMessage(linked.owner.id, callId, chunk, false);
}
}
void
CallModelPimpl::onRemoteRecordingChanged(const QString& callId, const QString& peerUri, bool state)
{

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