Compare commits

...

88 Commits

Author SHA1 Message Date
0f7e33cf33 misc: bump daemon
Change-Id: I37dc0b49217a2262ebf27ac83f4788b81b62fbbc
2024-11-12 16:38:38 -05:00
73258efdf7 i18n: automatic bump
Change-Id: Ice4cf7f5f34603b131e3ee070e141e9a2d196658
2024-11-11 16:42:30 -05:00
a29d5f791f message_bar: unify layout to be more coherent
The goal of this patch is to make the messagebar (and more broadly
the chatViewFooter) more coherent in its behavior and look/feel.

GitLab: #1846
GitLab: #1848
GitLab: #1639
GitLab: #1420
Change-Id: I0d0ed207df9eba50f724c69fa49f956dc8aaa573
2024-11-06 17:19:08 -05:00
5186c27325 chatview: fix issue with layout stacking
When the conversationview was resized horizontally to be small enough
so that only one pane is visible, the chatview header and footer would be visible, but clicking them would interact with the objects of
the pane below (the left side panel)

GitLab: #1868

Change-Id: Ic1fac91ef30fcc3078223e1705f10c8a112c2091
2024-11-06 15:31:00 -05:00
7e926a3e23 misc: ux/ui rename “swarm” to “group”
A(n) [type] error occurred while {verb} {noun}
createSwarm → createGroup → newGroup
Create swarm → Create new group
startSwarm → startGroup → newGroup
Start swarm → Create new group
swarmName → groupName
Swarm name → Group name

Change-Id: I9cb6f7b124d3db193bd190d2e52b5b27ea10ecf3
GitLab: #1845
2024-11-06 11:32:47 -05:00
93cde493d8 user_search: fix issue with user display incorrectly being updated
When searching for a user, if the user was found, a signal would be
sent to update the display name with incorrect formatting across the
application.

Change-Id: I20a453e2eddf1e1a402985ff741c8e7c7ea6f99f
2024-11-06 09:16:53 -05:00
cb829676e3 file_attachments: fix behaviour when changing conversations
Fixes an issue where the files that were loaded are not cleared
when switching conversations. Implements the correct behavior
for restoring the files as was done with text drafts.

GitLab: #1847
GitLab: #1528

Change-Id: Id04c9820d08f25ef247002da66d99ae893d8495a
2024-11-06 09:15:08 -05:00
112c6a4d7a chatview: disable visibility of sidepanel when adding contact
GitLab: #1871

Change-Id: I1949c0da388c637123801db39310a1c9fd8c7b99
2024-11-05 16:19:55 -05:00
188f487695 chatview: change visibility of reply component
Make it so that the reply/more/share buttons are visible
whenever the cursor hovers over the horizontal area
that a message takes up. Add message highlighting.
Fix small issue with "more" button not being deselected
after choosing an emoji

GitLab: #1870

Change-Id: I4db5230c2a50ce4640eececc69f8e88348356d79
2024-11-05 16:19:19 -05:00
0af01cc62d i18n: automatic bump
Change-Id: I552add4e22956ac7c9b8fd50704a9612e32c133e
2024-11-04 16:42:41 -05:00
a8acc71830 msi-installer: deploy VC CRT files locally with the application
This avoids merge modules which may crush system runtimes files. We've had several issues packaging vc_redist binaries also, so this seems to a better option for now.

Gitlab: #1865
Change-Id: I9ac3d3a1945136d7f78cf5be2de5d05cf377e126
2024-11-04 11:49:03 -05:00
eaf409d6d3 msi-installer: reformat xml
Switches formatter to one not dependant on JDK
- https://github.com/DotJoshJohnson/vscode-xml
- {
      "xmlTools.xmlFormatterImplementation": "v2",
      "xmlTools.splitAttributesOnFormat": true,
  }

Gitlab: #1453
Gitlab: #1865
Change-Id: I82e65d3097ac366f7873ac4c0e1d5beed3ee486e
2024-11-04 12:48:41 -04:00
42e3eeabf6 msi-installer: remove deployment of Windows 7 support runtimes
Gitlab: #1873
Change-Id: I239566f4cfa4dfbdfd08ccc496aa0bc206ece855
2024-11-04 12:47:54 -04:00
41cb6528c2 misc: unify terminology
{Noun} {verb} successfully
A(n) [type] error occurred while [attempting to] {verb} {noun}.
placeAudioCall → startAudioCall
placeVideoCall → startVideoCall
reconnectTry → reconnectAttempt

Change-Id: I918961894fc23989920727009031cc6a2ac1d8f3
GitLab: #1730
2024-11-01 15:30:44 -04:00
b6aa9eedfa misc: update jami.appdata.xml
<image> tag must be before <caption> tag
To translate <description>, tag must include xml:lang
Update URL addresses
Update description to include extensions, JAMS etc

GitLab: #1262

Change-Id: I8b313a02b119f5ddeaa2b9d760cac7ac5c147b7a
2024-11-01 15:14:02 -04:00
3c1b2c22b2 misc: bump daemon
Change-Id: Ica8a83b1ab8a7deaabec41f7fa6a1b72963913c5
2024-10-31 20:40:21 -04:00
fb660b928f about-dialog: only show the project versions if available
This is a workaround for an issue that occurs due to the way Linux
packaging is done, where the git repository is not available in the
build source at configure time, which is when the version files are
generated, so we prevent a "." from being displayed if the version
string is not available.

Gitlab: #1857
Change-Id: I2f6a281eb89ec0f977749d135da68fe5b7c9c2da
2024-10-31 17:23:07 -04:00
2f163846c7 i18n: automatic bump
Change-Id: Idbcacb51bb113174f455221f0b340bde571c9d35
2024-10-28 16:42:27 -04:00
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
222 changed files with 20667 additions and 5783 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

@ -1,3 +1,4 @@
/obj
/bin
Components.wxs
AppComponents.wxs
CrtComponents.wxs

View File

@ -3,13 +3,11 @@
<?define Name="Jami" ?>
<?define ExeName="Jami" ?>
<?define AppName="Jami" ?>
<?define Manufacturer="Savoir-Faire Linux"?>
<?if $(var.Configuration) = Release ?>
<?define ReleaseDir="..\x64\Release"?>
<?else?>
<?define ReleaseDir="..\x64\Beta"?>
<?endif ?>
<?define Manufacturer="Savoir-Faire Linux"?>
<?define UcrtDir="C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64"?>
</Include>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-16"?>
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DeployedProjects />
<DirectoryMappings />
<FileMappings />

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="4.0"
DefaultTargets="Build"
InitialTargets="EnsureWixToolsetInstalled"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x64</Platform>
@ -16,7 +19,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>HarvestPath=..\x64\Release</DefineConstants>
<DefineConstants>AppHarvestPath=..\x64\Release;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
<SuppressPdbOutput>True</SuppressPdbOutput>
<CompilerAdditionalOptions>
</CompilerAdditionalOptions>
@ -26,7 +29,7 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Beta|x64' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>HarvestPath=..\x64\Beta</DefineConstants>
<DefineConstants>AppHarvestPath=..\x64\Beta;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
<SuppressPdbOutput>True</SuppressPdbOutput>
<CompilerAdditionalOptions>
</CompilerAdditionalOptions>
@ -35,8 +38,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
<Compile Include="StandardComponents.wxs" />
<Compile Include="Components.wxs" />
<Compile Include="AppComponents.wxs" />
<Compile Include="CrtComponents.wxs" />
</ItemGroup>
<ItemGroup>
<Content Include="Config.wxi" />
@ -58,13 +61,36 @@
<ItemGroup>
<EmbeddedResource Include="Localization.wxl" />
</ItemGroup>
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' ">
<Import Project="$(WixTargetsPath)"
Condition=" '$(WixTargetsPath)' != '' " />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets"
Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
<Target Name="EnsureWixToolsetInstalled"
Condition=" '$(WixTargetsImported)' != 'true' ">
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\x64\$(Configuration)" PreprocessorVariable="var.HarvestPath" OutputFile="Components.wxs" ComponentGroupName="HeatGenerated" DirectoryRefId="APPLICATIONFOLDER" AutogenerateGuids="true" ToolPath="$(WixToolPath)" SuppressFragments="true" SuppressRegistry="true" SuppressRootDirectory="true" Transforms="HarvestFilter.xslt" />
<HeatDirectory Directory="..\x64\$(Configuration)"
PreprocessorVariable="var.AppHarvestPath"
OutputFile="AppComponents.wxs"
ComponentGroupName="AppHeatGenerated"
DirectoryRefId="APPLICATIONFOLDER"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)"
SuppressFragments="true"
SuppressRegistry="true"
SuppressRootDirectory="true"
Transforms="HarvestFilter.xslt" />
<HeatDirectory Directory="$(VC_CRT_Dir)"
PreprocessorVariable="var.CrtHarvestPath"
OutputFile="CrtComponents.wxs"
ComponentGroupName="CrtHeatGenerated"
DirectoryRefId="APPLICATIONFOLDER"
AutogenerateGuids="true"
ToolPath="$(WixToolPath)"
SuppressFragments="true"
SuppressRegistry="true"
SuppressRootDirectory="true" />
</Target>
<Target Name="AfterBuild">
</Target>

View File

@ -2,6 +2,14 @@
<WixLocalization Culture="en-us"
xmlns="http://schemas.microsoft.com/wix/2006/localization">
<String Id="AdvancedWelcomeEulaDlgDescriptionPerMachine">By installing this software you agree to the terms in the license agreement</String>
<UI Dialog="ExitDialog" Control="OptionalCheckBox" Width="10" Height="10" X="135" Y="110" />
<UI Dialog="ExitDialog" Control="OptionalText" X="150" Y="110" />
<UI Dialog="ExitDialog"
Control="OptionalCheckBox"
Width="10"
Height="10"
X="135"
Y="110" />
<UI Dialog="ExitDialog"
Control="OptionalText"
X="150"
Y="110" />
</WixLocalization>

View File

@ -1,134 +1,220 @@
<?xml version="1.0" encoding="UTF-8"?>
<?include Config.wxi?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="$(var.Name)" Language="1033" Version="$(fun.AutoVersion(1.0))" Manufacturer="$(var.Manufacturer)" UpgradeCode="7c45b52b-0390-4fe8-947a-3f13e82dd346">
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine" />
<Product Id="*"
Name="$(var.Name)"
Language="1033"
Version="$(fun.AutoVersion(1.0))"
Manufacturer="$(var.Manufacturer)"
UpgradeCode="7c45b52b-0390-4fe8-947a-3f13e82dd346">
<Package InstallerVersion="301"
Compressed="yes"
InstallScope="perMachine" />
<MajorUpgrade Schedule="afterInstallInitialize" AllowDowngrades="yes"/>
<MediaTemplate EmbedCab="yes" CompressionLevel="high" MaximumUncompressedMediaSize="4" />
<MajorUpgrade Schedule="afterInstallInitialize"
AllowDowngrades="yes"/>
<MediaTemplate EmbedCab="yes"
CompressionLevel="high"
MaximumUncompressedMediaSize="4" />
<!--Disables interaction of the package with the Restart Manager.-->
<Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
<Property Id="MSIRESTARTMANAGERCONTROL"
Value="Disable" />
<!--Icon File should be in release folder(not wix project), otherwise cannot be read-->
<Icon Id="icon.ico" SourceFile="$(var.ReleaseDir)\jami.ico" />
<Property Id="ARPPRODUCTICON" Value="icon.ico" />
<Property Id="ARPNOMODIFY" Value="1" />
<Icon Id="icon.ico"
SourceFile="$(var.ReleaseDir)\jami.ico" />
<Property Id="ARPPRODUCTICON"
Value="icon.ico" />
<Property Id="ARPNOMODIFY"
Value="1" />
<!-- It seems that QtWebEngineProcess.exe versioning requires us to force reinstall. -->
<Property Id="REINSTALLMODE" Value="dms" />
<Property Id="REINSTALLMODE"
Value="dms" />
<Feature Id="ProductFeature" Title="Main" Level="1" Absent="disallow">
<ComponentGroupRef Id="StandardComponents" Primary="yes" />
<ComponentGroupRef Id="HeatGenerated" />
<Feature Id="ProductFeature"
Title="Main"
Level="1"
Absent="disallow">
<ComponentGroupRef Id="MainExecutable"
Primary="yes" />
<ComponentGroupRef Id="AppHeatGenerated" />
<ComponentGroupRef Id="CrtHeatGenerated" />
<ComponentRef Id="ApplicationShortcutDesktop" />
<ComponentRef Id="ApplicationShortcutStartMenu" />
<ComponentRef Id="RegistryEntries" />
<ComponentRef Id="URLProtocolRegistryEntries" />
</Feature>
<!--Visual C++ Redist merge module-->
<DirectoryRef Id="TARGETDIR">
<Merge Id="VCRedist" SourceFile="$(env.VCRedistMergeModule)" DiskId="1" Language="0" />
</DirectoryRef>
<Feature Id="VCRedist" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<MergeRef Id="VCRedist"/>
</Feature>
<SetProperty After="FindRelatedProducts" Id="FirstInstall" Value="true">
<SetProperty After="FindRelatedProducts"
Id="FirstInstall"
Value="true">
NOT Installed AND NOT WIX_UPGRADE_DETECTED AND NOT WIX_DOWNGRADE_DETECTED
</SetProperty>
<SetProperty After="SetFirstInstall" Id="Upgrading" Value="true">
<SetProperty After="SetFirstInstall"
Id="Upgrading"
Value="true">
WIX_UPGRADE_DETECTED AND NOT (REMOVE="ALL")
</SetProperty>
<SetProperty After="RemoveExistingProducts" Id="RemovingForUpgrade" Sequence="execute" Value="true">
(REMOVE="ALL") AND UPGRADINGPRODUCTCODE
<SetProperty After="RemoveExistingProducts"
Id="RemovingForUpgrade"
Sequence="execute"
Value="true"> (REMOVE="ALL") AND UPGRADINGPRODUCTCODE
</SetProperty>
<SetProperty After="SetUpgrading" Id="Uninstalling" Value="true">
<SetProperty After="SetUpgrading"
Id="Uninstalling"
Value="true">
Installed AND (REMOVE="ALL") AND NOT (WIX_UPGRADE_DETECTED OR UPGRADINGPRODUCTCODE)
</SetProperty>
<SetProperty After="SetUninstalling" Id="Maintenance" Value="true">
<SetProperty After="SetUninstalling"
Id="Maintenance"
Value="true">
Installed AND NOT Upgrading AND NOT Uninstalling AND NOT UPGRADINGPRODUCTCODE
</SetProperty>
<!--SetDirectory of APPLICATIONFOLDER -->
<SetDirectory Id="APPLICATIONFOLDER" Value="[ProgramFiles64Folder][ApplicationFolderName]">APPLICATIONFOLDER=""</SetDirectory>
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize" />
<SetDirectory Id="APPLICATIONFOLDER"
Value="[ProgramFiles64Folder][ApplicationFolderName]">APPLICATIONFOLDER=""</SetDirectory>
<SetProperty Id="ARPINSTALLLOCATION"
Value="[APPLICATIONFOLDER]"
After="CostFinalize" />
<UIRef Id="CustomUI" />
<WixVariable Id="WixUIInfoIcon" Value="icon.ico"/>
<WixVariable Id="WixUIBannerBmp" Value="top-banner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="main-banner.bmp" />
<WixVariable Id="WixUISupportPerUser" Value="0" />
<WixVariable Id="WixUIInfoIcon"
Value="icon.ico"/>
<WixVariable Id="WixUIBannerBmp"
Value="top-banner.bmp" />
<WixVariable Id="WixUIDialogBmp"
Value="main-banner.bmp" />
<WixVariable Id="WixUISupportPerUser"
Value="0" />
<CustomAction Id="RemoveOldJamiFiles"
Directory="APPLICATIONFOLDER"
ExeCommand="cmd /c &quot;del vc_redist.x64.exe; del uninstall.exe; del WinSparkle.dll;&quot;"
Execute="deferred"
Return="ignore"
HideTarget="no"
Impersonate="no"/>
Directory="APPLICATIONFOLDER"
ExeCommand="cmd /c &quot;del vc_redist.x64.exe; del uninstall.exe; del WinSparkle.dll;&quot;"
Execute="deferred"
Return="ignore"
HideTarget="no"
Impersonate="no"/>
<Property Id="QtExecCmdLine"
Value='"[APPLICATIONFOLDER]/$(var.ExeName).exe" --term'/>
Value='"[APPLICATIONFOLDER]/$(var.ExeName).exe" --term'/>
<CustomAction Id="TerminateAppProcess"
BinaryKey="WixCA"
DllEntry="CAQuietExec"
Execute="immediate"
Return="ignore"/>
BinaryKey="WixCA"
DllEntry="CAQuietExec"
Execute="immediate"
Return="ignore"/>
</Product>
<Fragment Id="DirectoryStructure">
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="TARGETDIR"
Name="SourceDir">
<Directory Id="ProgramFiles64Folder">
<Directory Id="APPLICATIONFOLDER" Name="$(var.Name)" />
<Directory Id="APPLICATIONFOLDER"
Name="$(var.Name)" />
</Directory>
<Directory Id="DesktopFolder" Name="Desktop" />
<Directory Id="DesktopFolder"
Name="Desktop" />
<Directory Id="ProgramMenuFolder">
<Directory Id="ApplicationProgramsFolder" />
</Directory>
<Directory Id="WindowsFolder" Name="WINDOWS"/>
<Directory Id="WindowsFolder"
Name="WINDOWS"/>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="MainExecutable"
Directory="APPLICATIONFOLDER">
<Component Id="cmp9CFEE34E3A162AB05264E8B756EC1DEC"
Guid="*">
<File Id="fileMain.exe"
KeyPath="yes"
Source="$(var.ReleaseDir)\$(var.ExeName).exe" />
</Component>
</ComponentGroup>
</Fragment>
<Fragment Id="Shortcuts">
<DirectoryRef Id="DesktopFolder">
<Component Id="ApplicationShortcutDesktop" Guid="*" Win64="yes">
<Shortcut Id="ApplicationShortcutDesktop" Name="$(var.Name)" Description="Launch $(var.Name)" Target="[#fileMain.exe]" WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="DesktopFolder" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\jami.net\$(var.Name)" Name="desktop" Type="integer" Value="1" KeyPath="yes" />
<Component Id="ApplicationShortcutDesktop"
Guid="*"
Win64="yes">
<Shortcut Id="ApplicationShortcutDesktop"
Name="$(var.Name)"
Description="Launch $(var.Name)"
Target="[#fileMain.exe]"
WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="DesktopFolder"
On="uninstall" />
<RegistryValue Root="HKCU"
Key="Software\jami.net\$(var.Name)"
Name="desktop"
Type="integer"
Value="1"
KeyPath="yes" />
<Condition>FirstInstall</Condition>
</Component>
</DirectoryRef>
<DirectoryRef Id="ApplicationProgramsFolder">
<Component Id="ApplicationShortcutStartMenu" Guid="*" Win64="yes">
<Shortcut Id="ApplicationShortcutStartMenu" Name="$(var.Name)" Description="Launch $(var.Name)" Target="[#fileMain.exe]" WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="StartMenuFolder" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\jami.net\$(var.Name)" Name="startmenu" Type="integer" Value="1" KeyPath="yes" />
<Component Id="ApplicationShortcutStartMenu"
Guid="*"
Win64="yes">
<Shortcut Id="ApplicationShortcutStartMenu"
Name="$(var.Name)"
Description="Launch $(var.Name)"
Target="[#fileMain.exe]"
WorkingDirectory="INSTALLFOLDER" />
<RemoveFolder Id="StartMenuFolder"
On="uninstall" />
<RegistryValue Root="HKCU"
Key="Software\jami.net\$(var.Name)"
Name="startmenu"
Type="integer"
Value="1"
KeyPath="yes" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment Id="OtherRegistryEntries">
<DirectoryRef Id="TARGETDIR">
<Component Id="RegistryEntries" Guid="*" Win64="yes">
<RegistryValue Root="HKCU" Key="Software\jami.net\$(var.AppName)" Name="hasRun" Type="integer" Value="0" KeyPath="yes" />
<Component Id="RegistryEntries"
Guid="*"
Win64="yes">
<RegistryValue Root="HKCU"
Key="Software\jami.net\$(var.AppName)"
Name="hasRun"
Type="integer"
Value="0"
KeyPath="yes" />
</Component>
</DirectoryRef>
</Fragment>
<Fragment Id="URLProtocol">
<DirectoryRef Id="TARGETDIR">
<Component Id="URLProtocolRegistryEntries" Guid="*" Win64="yes">
<RegistryKey Root="HKCR" Key="jami" ForceCreateOnInstall="yes" ForceDeleteOnUninstall="yes">
<RegistryValue Type="string" Name="URL Protocol" Value="" />
<RegistryValue Type="string" Value="URL:jami"/>
<Component Id="URLProtocolRegistryEntries"
Guid="*"
Win64="yes">
<RegistryKey Root="HKCR"
Key="jami"
ForceCreateOnInstall="yes"
ForceDeleteOnUninstall="yes">
<RegistryValue Type="string"
Name="URL Protocol"
Value="" />
<RegistryValue Type="string"
Value="URL:jami"/>
<RegistryKey Key="DefaultIcon">
<RegistryValue Type="string" Value="[APPLICATIONFOLDER]$(var.ExeName).exe" />
<RegistryValue Type="string"
Value="[APPLICATIONFOLDER]$(var.ExeName).exe" />
</RegistryKey>
<RegistryKey Key="shell\open\command">
<RegistryValue Type="string" Value='"[APPLICATIONFOLDER]$(var.ExeName).exe" "%1"' />
<RegistryValue Type="string"
Value='"[APPLICATIONFOLDER]$(var.ExeName).exe" "%1"' />
</RegistryKey>
</RegistryKey>
</Component>
@ -137,47 +223,88 @@
<Fragment Id="UI">
<UI Id="CustomUI">
<Property Id="WixAppFolder" Value="WixPerMachineFolder" />
<Property Id="WixAppFolder"
Value="WixPerMachineFolder" />
<!--APPLICATIONFOLDER required by WixUI_Advanced, ApplicationFolderName reset APPLICATIONFOLDER path-->
<Property Id="ApplicationFolderName" Value="$(var.Manufacturer)\$(var.AppName)" />
<Property Id="ApplicationFolderName"
Value="$(var.Manufacturer)\$(var.AppName)" />
<UIRef Id="WixUI_Advanced" />
<!--Remove User Exit Dialog-->
<Publish Dialog="AdvancedWelcomeEulaDlg" Control="Cancel" Property="AbortInstall" Value="1">1</Publish>
<Publish Dialog="InstallDirDlg" Control="Cancel" Property="AbortInstall" Value="1">1</Publish>
<Publish Dialog="FeaturesDlg" Control="Cancel" Property="AbortInstall" Value="1">1</Publish>
<Publish Dialog="MaintenanceWelcomeDlg" Control="Cancel" Property="AbortInstall" Value="1">1</Publish>
<Publish Dialog="MaintenanceTypeDlg" Control="Cancel" Property="AbortInstall" Value="1">1</Publish>
<Publish Dialog="AdvancedWelcomeEulaDlg"
Control="Cancel"
Property="AbortInstall"
Value="1">1</Publish>
<Publish Dialog="InstallDirDlg"
Control="Cancel"
Property="AbortInstall"
Value="1">1</Publish>
<Publish Dialog="FeaturesDlg"
Control="Cancel"
Property="AbortInstall"
Value="1">1</Publish>
<Publish Dialog="MaintenanceWelcomeDlg"
Control="Cancel"
Property="AbortInstall"
Value="1">1</Publish>
<Publish Dialog="MaintenanceTypeDlg"
Control="Cancel"
Property="AbortInstall"
Value="1">1</Publish>
<!--Launch Program If Checkbox is clicked-->
<Publish Dialog="ExitDialog" Control="Finish" Event="DoAction" Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish>
<InstallUISequence>
<Show Dialog="UserExit" OnExit="cancel">NOT AbortInstall = 1</Show>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
<Show Dialog="UserExit"
OnExit="cancel">NOT AbortInstall = 1</Show>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder"
After="WixSetDefaultPerMachineFolder" />
</InstallUISequence>
</UI>
<InstallExecuteSequence>
<Custom Action='TerminateAppProcess' Before='InstallValidate'/>
<Custom Action="RemoveOldJamiFiles" After="RemoveFiles" />
<Custom Action="LaunchApplication_nonUI" After="InstallFinalize"> WIXNONUILAUNCH </Custom>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
<Custom Action='TerminateAppProcess'
Before='InstallValidate'/>
<Custom Action="RemoveOldJamiFiles"
After="RemoveFiles" />
<Custom Action="LaunchApplication_nonUI"
After="InstallFinalize"> WIXNONUILAUNCH </Custom>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder"
After="WixSetDefaultPerMachineFolder" />
</InstallExecuteSequence>
<!--License check box text, Launch check box text (auto check)-->
<Property Id="WIXUI_EXITDIALOGOPTIONALTEXT" Value="Launch $(var.Name)" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.Name)" />
<Property Id="WIXUI_EXITDIALOGOPTIONALTEXT"
Value="Launch $(var.Name)" />
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT"
Value="Launch $(var.Name)" />
<!--CheckBox Default Set to One-->
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX" Value="1"/>
<Property Id="LicenseAccepted" Value="1"/>
<Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOX"
Value="1"/>
<Property Id="LicenseAccepted"
Value="1"/>
<Property Id="WixShellExecTarget" Value="[#fileMain.exe]" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<CustomAction Id="LaunchApplication_nonUI" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes"/>
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder" Property="WixPerMachineFolder" Value="[ProgramFiles64Folder][ApplicationFolderName]" Execute="immediate" />
<Property Id="WixShellExecTarget"
Value="[#fileMain.exe]" />
<CustomAction Id="LaunchApplication"
BinaryKey="WixCA"
DllEntry="WixShellExec"
Impersonate="yes" />
<CustomAction Id="LaunchApplication_nonUI"
BinaryKey="WixCA"
DllEntry="WixShellExec"
Impersonate="yes"/>
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder"
Property="WixPerMachineFolder"
Value="[ProgramFiles64Folder][ApplicationFolderName]"
Execute="immediate" />
<!--License File-->
<WixVariable Id="WixUILicenseRtf" Value="$(var.ReleaseDir)\License.rtf"/>
<WixVariable Id="WixUILicenseRtf"
Value="$(var.ReleaseDir)\License.rtf"/>
</Fragment>
</Wix>

View File

@ -1,86 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Generated with WiX's heat tool using the command:
heat.exe dir x64\Release -ag -cg ProductComponents -dr APPLICATIONFOLDER -srd -var var.ReleaseDir -out JamiInstaller\Components.wxs
Includes:
- the api-ms-win dlls missing parts of vc merge module for windows 7 support
- Jami.exe with a named Id so we can reference it in Product.wxs to launch after install
We run heat in the prebuild step on x64\Release without Jami.exe (instead of an XSLT file), to harvest everything else.
-->
<?include Config.wxi?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="StandardComponents">
<Component Id="cmp9C61F84AF9761955FBF397AFAE21C11B" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil2089BEC9A7AB899CED5A5EE501789299" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-file-l1-2-0.dll" />
</Component>
<Component Id="cmp03BB2697EE10869C4A329E3EA987EFAA" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil44C27F2C97596734BB3BEB7C21F7B71C" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-file-l2-1-0.dll" />
</Component>
<Component Id="cmp6B6AA7AEA5A4D324A4EE7DAE1B1193E0" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil1D16BE23D323A1E37FC1FC7354A9305F" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-localization-l1-2-0.dll" />
</Component>
<Component Id="cmpB5454FB66442C9BFD2145AE30B32D7A9" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil031B78DF53F7A3AC109410907624FC3E" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-processthreads-l1-1-1.dll" />
</Component>
<Component Id="cmp9F6D22CD9B1739E4F75F92F3A07E4CA1" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filE9A3672FA504AA8E518DD72A02CD3E77" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-synch-l1-2-0.dll" />
</Component>
<Component Id="cmp9451422B7074D46F019614C3DE73BD17" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil3C902CA2889BB8855D285C3FBABB334F" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-core-timezone-l1-1-0.dll" />
</Component>
<Component Id="cmp349250459EC2D8C328EED5138B073E7A" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil2466F3D9FBA095A007D0909040D4D688" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-conio-l1-1-0.dll" />
</Component>
<Component Id="cmpCC880F2B054A87EF5FC68232652231BF" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil605A691486569535A1C3548F7DCE753C" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-convert-l1-1-0.dll" />
</Component>
<Component Id="cmpD6CB40D5A5AFF2161B7B4B4F06F03301" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil09AE032A32E2E542A232F7941AC77320" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-environment-l1-1-0.dll" />
</Component>
<Component Id="cmpC02538029646A27A9F786AD690EB3C8E" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil7DE9C3CADCA188356922B0CBD8E313E7" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-filesystem-l1-1-0.dll" />
</Component>
<Component Id="cmp8E50197B377636123F0F1F94FFB004E7" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil584F158D11B8A380C73F1EFE8BBA92B4" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-heap-l1-1-0.dll" />
</Component>
<Component Id="cmp7F729C94A363C73DC4D91B6F48E4F859" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil4BE19B924B98D56F3155B66496D574E5" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-locale-l1-1-0.dll" />
</Component>
<Component Id="cmp7C573E66B0904BA73880788F7057AF88" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filE8495C446FA1237E92562498D20261AA" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-math-l1-1-0.dll" />
</Component>
<Component Id="cmp7A91CED53D8F6E5F20F2049B3B5CD143" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil06951EB208628753677745AF15CC12A5" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-multibyte-l1-1-0.dll" />
</Component>
<Component Id="cmp1CE713C705A95306A1D246AC3AB9DE25" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil8D102BB81768F998470C34797459E306" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-private-l1-1-0.dll" />
</Component>
<Component Id="cmp35840DFBF4D6AE827AFC4EF2A17BB3EB" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filC6C457BD901F940DCB673D271728F9FE" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-process-l1-1-0.dll" />
</Component>
<Component Id="cmpEBB86BDA48FE3B9E2043C1A80D26ACD5" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filE1B2095225B01DEFA5DA9895B432FBCB" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-runtime-l1-1-0.dll" />
</Component>
<Component Id="cmp80C8534B553078EA8B86F100FF542776" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filDAFE58019AD70832B8304DCEA534B5EE" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-stdio-l1-1-0.dll" />
</Component>
<Component Id="cmpCFC348111B5343749A2273A62421C07C" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil1F1B38DB330CA413655F715578D4BE1A" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-string-l1-1-0.dll" />
</Component>
<Component Id="cmp7D5450E04EC419244107942A00DF7DDF" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filEB03BCF3155C5BAE2C2EDBF036EB659D" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-time-l1-1-0.dll" />
</Component>
<Component Id="cmp5456679BDCC818B2E9476B416F71AAA5" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fil5B120DD384CABED37DFC2652C6462666" KeyPath="yes" Source="$(var.UcrtDir)\api-ms-win-crt-utility-l1-1-0.dll" />
</Component>
<Component Id="cmpF23755F862A15FFCBD109C85599B7F20" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="filD6887AD9110E4A8D49143C9A8F0B5843" KeyPath="yes" Source="$(var.UcrtDir)\ucrtbase.dll" />
</Component>
<Component Id="cmp9CFEE34E3A162AB05264E8B756EC1DEC" Directory="APPLICATIONFOLDER" Guid="*">
<File Id="fileMain.exe" KeyPath="yes" Source="$(var.ReleaseDir)\$(var.ExeName).exe" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>

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...ee342157a7

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

@ -1,131 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (C) 2015-2024 Savoir-faire Linux Inc. -->
<component type="desktop-application">
<id>net.jami.Jami</id>
<metadata_license>CC-BY-SA-3.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>Jami</name>
<summary>Privacy-oriented voice, video, chat, and conference platform</summary>
<summary xml:lang="hu">Adatvédelem-orientált hang-, video-, csevegés- és konferenciaplatform</summary>
<icon type="stock">jami</icon>
<description>
<id>net.jami.Jami</id>
<metadata_license>CC-BY-SA-3.0</metadata_license>
<project_license>GPL-3.0+</project_license>
<name>Jami</name>
<summary>Privacy-oriented voice, video, chat, and conference platform</summary>
<summary xml:lang="hu">Adatvédelem-orientált hang-, video-, csevegés- és konferenciaplatform</summary>
<icon type="stock">jami</icon>
<description>
<p>
An end-to-end encrypted secure and distributed voice, video, and
chat communication platform that requires no central server and
leaves the power of privacy and freedom in the hands of users.
Jami [1], a GNU package, is software for universal and
distributed peer-to-peer communication that respects the
freedom and privacy of its users.
</p>
<p>
Jami supports the following key features:
Jami is the simplest and easiest way to connect with people
(and devices) with instant messaging, audio and video calls
over the Internet and LAN/WAN intranets.
</p>
<ul>
<li>One-to-one conversations</li>
<li>File sharing</li>
<li>Audio calls and conferences</li>
<li>Video calls and conferences</li>
<li>Screen sharing in video calls and conferences</li>
<li>Recording and sending audio messages</li>
<li>Recording and sending video messages</li>
<li>Functioning as a SIP phone software</li>
</ul>
<p>
Client applications for GNU/Linux, Windows, macOS, iOS, Android,
and Android TV are available, making Jami an interoperable and
Jami is a free/libre, end-to-end encrypted, and private
communication platform.
</p>
<p>
Jami which used to be known as Ring is also an
open-source alternative (to Facebook Messenger, Signal,
Skype, Teams, Telegram, TikTok, Viber, WhatsApp, Zoom) that
prioritizes the privacy of its users.
</p>
<p>
Jami has a professional-looking design and is available for
a wide range of platforms. Unlike the alternatives, calls
using Jami are directly between users as it does not use
servers to handle calls.
</p>
<p>
This gives the greatest privacy as the distributed nature
of Jami means your calls are only between participants.
</p>
<p>
One-to-one and group conversations with Jami are enhanced
with: instant messaging; audio and video calling;
recording and sending audio and video messages;
file transfers; screen sharing; and, location sharing.
</p>
<p>
Jami can also function as a SIP client.
</p>
<p>
Jami has multiple extensions [2] available:
Audio Filter; Auto Answer; Green Screen; Watermark; and,
Whisper Transcript.
</p>
<p>
Jami can be easily deployed in organizations with the
“Jami Account Management Server” (JAMS) [3], allowing users
to connect with their corporate credentials or create local
accounts. JAMS allows you to manage your own Jami community
while taking advantage of Jamis distributed network
architecture.
</p>
<p>
Jami is available for GNU/Linux, Windows, macOS, iOS,
Android, and Android TV, making Jami an interoperable and
cross-platform communication framework.
</p>
<p xml:lang="hu">
Végpontokig titkosított biztonságos és elosztott hang-, videó-
és csevegés-kommunikációs platform, amely nem igényel központi
kiszolgálót, és a felhasználók kezében hagyja a magánélet és a
szabadság hatalmát.
<p>
Manage multiple SIP accounts, Jami accounts and JAMS
accounts with the Jami client installed on one or multiple
devices.
</p>
<p xml:lang="hu">
A Jami a következő főbb funkciókat támogatja:
<p>
Jami is free, unlimited, private, advertising free,
compatible, fast, autonomous, and anonymous.
</p>
<ul>
<li xml:lang="hu">Személyes beszélgetések</li>
<li xml:lang="hu">Fájlmegosztás</li>
<li xml:lang="hu">Hanghívások és konferenciák</li>
<li xml:lang="hu">Videohívások és konferenciák</li>
<li xml:lang="hu">Képernyőmegosztás videohívásokban és
konferenciákon</li>
<li xml:lang="hu">Hangüzenetek rögzítése és küldése</li>
<li xml:lang="hu">Videoüzenetek rögzítése és küldése</li>
<li xml:lang="hu">SIP-telefonszoftverként működik</li>
</ul>
<p xml:lang="hu">
Elérhetők a GNU/Linux, Windows, macOS, iOS, Android és Android TV
ügyfélalkalmazásai, így a Jami interoperábilis és többplatformos
kommunikációs keretrendszerré válik.
<p>
[1] https://jami.net/
</p>
<p>
[2] https://jami.net/extensions/
</p>
<p>
[3] https://jami.biz/
</p>
</description>
</description>
<description xml:lang="hu">
<p>
A Jami [1], egy GNU-csomag, egy univerzális és elosztott
társ-társ kommunikációra szolgáló szoftver, amely
tiszteletben tartja a felhasználók szabadságát és
magánéletét.
</p>
<p>
A Jami a legegyszerűbb és legegyszerűbb módja annak, hogy
azonnali üzenetküldéssel, hang- és videohívásokkal
kapcsolódjon az emberekhez (és eszközökhöz) az interneten és
a LAN/WAN intraneteken keresztül.
</p>
<p>
A Jami egy ingyenes, teljes körűen titkosított és privát
kommunikációs platform.
</p>
<p>
A Jami amelyet korábban Ring néven ismertek egy nyílt
forráskódú alternatíva is (a Facebook Messenger, a Signal,
a Skype, a Teams, a Telegram, a TikTok, a Viber, a WhatsApp,
a Zoom számára), amely előtérbe helyezi a felhasználók
magánéletét.
</p>
<p>
A Jami professzionális megjelenésű, és platformok széles
skálájához elérhető. Az alternatívákkal ellentétben a Jami-t
használó hívások közvetlenül a felhasználók között zajlanak,
mivel nem használ kiszolgálókat a hívások kezelésére.
</p>
<p>
Ez biztosítja a legnagyobb magánéletet, mivel a Jami
elosztott jellege azt jelenti, hogy a hívások csak a
résztvevők között zajlanak.
</p>
<p>
A Jamival folytatott személyes és csoportos beszélgetéseket
a következők javítják: azonnali üzenetküldés; hang- és
videohívások; hang- és videoüzenetek rögzítése és küldése;
fájlátvitel; képernyőmegosztás; és helymegosztás.
</p>
<p>
A Jami SIP-ügyfélként is működhet.
</p>
<p>
A Jami-nek több bővítménye [2] is elérhető: hangszűrő;
automatikus válasz; zöld képernyő; vízjel; és, suttogó
átirat.
</p>
<p>
A Jami könnyen telepíthető a szervezetekben
a „Jami fiókkezelő kiszolgálóval” (JAMS) [3], amely lehetővé
teszi a felhasználók számára, hogy csatlakozzanak vállalati
hitelesítő adataikhoz, vagy helyi fiókokat hozzanak létre.
A JAMS lehetővé teszi saját Jami közösségének kezelését,
miközben kihasználja a Jami elosztott hálózati
architektúráját.
</p>
<p>
A Jami elérhető GNU/Linux, Windows, macOS, iOS, Android és
Android TV rendszereken, így a Jami egy interoperábilis és
platformok közötti kommunikációs keretrendszer.
</p>
<p>
Kezeljen több SIP-fiókot, Jami-fiókot és JAMS-fiókot az egy
vagy több eszközre telepített Jami-ügyféllel.
</p>
<p>
A Jami ingyenes, korlátlan, privát, reklámmentes,
kompatibilis, gyors, autonóm és névtelen.
</p>
<p>
[1] https://jami.net/hu/
</p>
<p>
[2] https://jami.net/hu/extensions/
</p>
<p>
[3] https://jami.biz/
</p>
</description>
<url type="homepage">https://jami.net/</url>
<url type="bugtracker">https://git.jami.net/savoirfairelinux/jami-client-qt/issues</url>
<url type="faq">https://jami.net/help/</url>
<url type="help">https://docs.jami.net</url>
<url type="donation">https://www.paypal.com/donate/?hosted_button_id=MGUDJLQZ4TP5W</url>
<url type="translate">https://www.transifex.com/savoirfairelinux/jami</url>
<url type="homepage">https://jami.net/</url>
<url type="bugtracker">https://git.jami.net/savoirfairelinux/jami-client-qt/issues</url>
<url type="faq">https://docs.jami.net/user/faq.html</url>
<url type="help">https://forum.jami.net/</url>
<url type="donation">https://jami.net/whydonate/</url>
<url type="translate">https://www.transifex.com/savoirfairelinux/jami</url>
<!-- Maximum caption length is 60 characters -->
<!-- Officially GIF is not an allowed video format, but it appears to work nonetheless -->
<screenshots>
<screenshot type="default">
<caption>Send Audio, Video and Chat messages</caption>
<caption xml:lang="hu">Hang-, video- és csevegőüzeneteket küldhet</caption>
<image type="source" width="1310" height="650">https://dl.jami.net/media-resources/screenshots/jami_linux_audiovideo.png</image>
</screenshot>
<screenshot>
<caption>Easily share desktop contents</caption>
<caption xml:lang="hu">Könnyen megoszthatja az asztali tartalmat</caption>
<image type="source" width="1016" height="659">https://dl.jami.net/media-resources/screenshots/jami_linux_screenshare.png</image>
</screenshot>
<screenshot>
<caption>Crystal clear audio calls between Jami users</caption>
<caption xml:lang="hu">Kristálytiszta hanghívások a Jami felhasználók között</caption>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/audio-call_web.webm</video>
</screenshot>
<screenshot>
<caption>Conference calls with an unlimited participants</caption>
<caption xml:lang="hu">Konferenciahívások korlátlan számú résztvevővel</caption>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/conference_web.webm</video>
</screenshot>
<screenshot>
<caption>Encrypted and secure text messaging, no servers</caption>
<caption xml:lang="hu">Titkosított és biztonságos csevegési üzenetküldés, kiszolgálók nélkül</caption>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/chat_web.webm</video>
</screenshot>
<screenshot>
<caption>Send files of any size</caption>
<caption xml:lang="hu">Bármilyen méretű fájl küldése</caption>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/files-share_web.webm</video>
</screenshot>
</screenshots>
<!-- Maximum caption length is 60 characters -->
<!-- Officially GIF is not an allowed video format, but it appears to work nonetheless -->
<screenshots>
<screenshot type="default">
<image type="source" width="1310" height="650">https://dl.jami.net/media-resources/screenshots/jami_linux_audiovideo.png</image>
<caption>Send chat messages and talk with audio and video</caption>
<caption xml:lang="hu">Csevegőüzenetek küldése, valamint hang- és videobeszélgetés</caption>
</screenshot>
<screenshot>
<image type="source" width="1016" height="659">https://dl.jami.net/media-resources/screenshots/jami_linux_screenshare.png</image>
<caption>Screen sharing</caption>
<caption xml:lang="hu">Képernyőmegosztás</caption>
</screenshot>
<screenshot>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/audio-call_web.webm</video>
<caption>Crystal clear audio calls between Jami users</caption>
<caption xml:lang="hu">Kristálytiszta hanghívások a Jami felhasználók között</caption>
</screenshot>
<screenshot>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/conference_web.webm</video>
<caption>Conference calls with an unlimited number of participants</caption>
<caption xml:lang="hu">Konferenciahívások korlátlan számú résztvevővel</caption>
</screenshot>
<screenshot>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/chat_web.webm</video>
<caption>Encrypted and secure text messaging without servers</caption>
<caption xml:lang="hu">Titkosított és biztonságos csevegési üzenetküldés, kiszolgálók nélkül</caption>
</screenshot>
<screenshot>
<video container="webm" codec="vp9" width="600" height="400">https://dl.jami.net/media-resources/gifs_features/conversiongif_webm/files-share_web.webm</video>
<caption>Transfer files of any size</caption>
<caption xml:lang="hu">Bármilyen méretű fájl küldése</caption>
</screenshot>
</screenshots>
<launchable type="desktop-id">jami.desktop</launchable>
<launchable type="desktop-id">jami.desktop</launchable>
<provides><binary>jami</binary></provides>
<provides><binary>jami</binary></provides>
<!-- https://specifications.freedesktop.org/menu-spec/latest/apa.html -->
<!-- https://specifications.freedesktop.org/menu-spec/latest/apas02.html -->
<categories>
<category>Chat</category>
<category>Communication</category>
<category>FileTransfer</category>
<category>InstantMessaging</category>
<category>Network</category>
<category>P2P</category>
<category>Productivity</category>
</categories>
<!-- https://specifications.freedesktop.org/menu-spec/latest/apa.html -->
<!-- https://specifications.freedesktop.org/menu-spec/latest/apas02.html -->
<categories>
<category>Chat</category>
<category>Communication</category>
<category>FileTransfer</category>
<category>InstantMessaging</category>
<category>Network</category>
<category>P2P</category>
<category>Productivity</category>
</categories>
<translation type="gettext">jami-client-qt</translation>
<translation type="gettext">jami-client-qt</translation>
<content_rating type="oars-1.1">
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-audio">intense</content_attribute>
</content_rating>
<content_rating type="oars-1.1">
<content_attribute id="social-chat">intense</content_attribute>
<content_attribute id="social-audio">intense</content_attribute>
</content_rating>
<requires><id>net.jami.daemon</id></requires>
<requires><id>net.jami.daemon</id></requires>
</component>

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

@ -85,7 +85,7 @@ ApplicationWindow {
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.topMargin: preferredMargin
text: connectionFailed ? JamiStrings.reconnectWarn : JamiStrings.reconnectTry
text: connectionFailed ? JamiStrings.reconnectWarn : JamiStrings.reconnectAttempt
font.pointSize: 11
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter

View File

@ -362,7 +362,7 @@ ApplicationWindow {
function onUpdateCheckReplyReceived(ok, found) {
if (!ok) {
// Show an error dialog describing that we could not successfully check for an update.
// Show an error dialog describing that an update check failed.
presentUpdateInfoDialog(JamiStrings.updateCheckError);
return;
}

View File

@ -145,7 +145,7 @@ QtObject {
if (!view.managed)
view.presented();
}, props)) {
print("could not create view:", viewName);
print("An error occurred while creating view:", viewName);
}
}
@ -184,7 +184,7 @@ QtObject {
} else
view = rootView.pop(StackView.Immediate);
if (!view) {
print("could not pop view:", obj.objectName);
print("An error occurred while attempting to pop view:", obj.objectName);
resolveStack();
return;
}
@ -194,7 +194,7 @@ QtObject {
if (view.managed) {
var objectName = view ? view.objectName : obj.objectName;
if (!viewManager.destroyView(resources[objectName])) {
print("could not destroy view:", objectName);
print("An error occurred while attempting to destroy view:", objectName);
} else {
print("destroyed view:", objectName);
}

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

@ -230,6 +230,12 @@ Control {
RowLayout {
id: msgRowlayout
HoverHandler {
id: parenthandler
}
property bool msgHovered: CurrentAccount.type !== Profile.Type.SIP && root.type !== Interaction.Type.CALL && Body !== "" && (bubbleArea.bubbleHovered || hovered || more.hovered || share.hovered || parenthandler.hovered)
Layout.preferredHeight: {
var h = innerContent.height + root.extraHeight;
if (emojiReactions.emojis !== "")
@ -278,14 +284,10 @@ 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
HoverHandler {
id: bgHandler
}
PushButton {
id: more
objectName: "more"
@ -299,24 +301,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: msgRowlayout.msgHovered
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(() => msgRowlayout.msgHovered);
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 +334,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 +350,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: msgRowlayout.msgHovered
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: msgRowlayout.msgHovered
property bool isOpen: false
property var obj: undefined
function setBindings() { // when the popup is closed, setBindings is called to reset the icon's visual settings
share.isOpen = false;
visible = Qt.binding(() => msgRowlayout.msgHovered);
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 +440,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 +524,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

@ -89,8 +89,10 @@ BaseContextMenu {
emojiPicker.emojiIsPicked.connect(function (content) {
if (emojiReplied.includes(content)) {
MessagesAdapter.removeEmojiReaction(CurrentConversation.id, content, msgId);
parent.setBindings();
} else {
MessagesAdapter.addEmojiReaction(CurrentConversation.id, content, msgId);
parent.setBindings();
}
});
if (emojiPicker !== null) {
@ -107,8 +109,11 @@ BaseContextMenu {
property bool isScrolling: listView.verticalScrollBar.active
onOpened: root.closeWithoutAnimation = false
onClosed: if (emojiPicker)
emojiPicker.closeEmojiPicker()
onClosed: {
if (emojiPicker) {
emojiPicker.closeEmojiPicker();
}
}
function getQuickEmojiListModel() {
const defaultModel = ["👍", "👎", "😂"];
@ -153,7 +158,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 +180,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 +203,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

@ -99,7 +99,7 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
}
case Role::Draft: {
if (!item.uid.isEmpty())
return lrcInstance_->getContentDraft(item.uid, item.accountId);
return lrcInstance_->getContentDraft(item.uid, item.accountId)["text"];
return {};
}
case Role::ActiveCallsCount: {
@ -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);
@ -133,7 +137,7 @@ ConversationListModelBase::dataForItem(item_t item, int role) const
auto bestName = interaction.authorUri == accInfo.profileInfo.uri
? accInfo.accountModel->bestNameForAccount(accInfo.id)
: accInfo.contactModel->bestNameForContact(
interaction.authorUri);
interaction.authorUri);
lastInteractionBody
= interaction::getContactInteractionString(bestName,
interaction::to_action(

View File

@ -152,7 +152,7 @@ CurrentConversation::updateData()
updateProfile(convId);
updateActiveCalls(accountId, convId);
} catch (...) {
qWarning() << "Can't update current conversation data for" << convId;
qWarning() << "An error occurred while updating current conversation data for" << convId;
}
}

View File

@ -29,13 +29,13 @@ void
DBusErrorHandler::errorCallback()
{
qDebug() << "Dring has possibly crashed, "
"or has been killed... will wait 2.5 seconds and try to reconnect";
"or has been killed will wait 2.5 seconds before attempting to reconnect.";
Q_EMIT showDaemonReconnectPopup(true);
QTimer::singleShot(2500, this, [this]() {
if ((!lrc::api::Lrc::isConnected()) || (!lrc::api::Lrc::dbusIsValid())) {
qDebug() << "Could not reconnect to the daemon";
qDebug() << "An error occurred while attempting to reconnect to the daemon.";
Q_EMIT daemonReconnectFailed();
} else {
static_cast<DBusErrorHandler&>(GlobalInstances::dBusErrorHandler())

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;
@ -348,30 +352,36 @@ LRCInstance::stopAudioMeter()
});
}
QString
QVariantMap
LRCInstance::getContentDraft(const QString& convUid, const QString& accountId)
{
auto draftKey = accountId + "_" + convUid;
return contentDrafts_[draftKey];
QVariantMap draftMap;
draftMap["text"] = contentDrafts_[draftKey];
draftMap["files"] = fileDrafts_[draftKey];
return draftMap;
}
void
LRCInstance::setContentDraft(const QString& convUid,
const QString& accountId,
const QString& content)
const QString& textDraft,
const QList<QString>& filePathDraft)
{
if (accountId.isEmpty() || convUid.isEmpty()) {
return;
}
auto draftKey = accountId + "_" + convUid;
// prevent a senseless dataChanged signal from the
// model if nothing has changed
if (contentDrafts_[draftKey] == content)
if (contentDrafts_[draftKey] == textDraft && fileDrafts_[draftKey] == filePathDraft) {
return;
}
contentDrafts_[draftKey] = content;
contentDrafts_[draftKey] = textDraft;
fileDrafts_[draftKey] = filePathDraft;
// this signal is only needed to update the current smartlist
Q_EMIT draftSaved(convUid);
}

View File

@ -102,10 +102,12 @@ public:
Q_INVOKABLE void deselectConversation();
Q_INVOKABLE void makeConversationPermanent(const QString& convId = {},
const QString& accountId = {});
Q_INVOKABLE QString getContentDraft(const QString& convUid, const QString& accountId);
Q_INVOKABLE QVariantMap getContentDraft(const QString& convUid, const QString& accountId);
Q_INVOKABLE void setContentDraft(const QString& convUid,
const QString& accountId,
const QString& content);
const QString& textDraft,
const QList<QString>& filePathDraft);
Q_INVOKABLE int indexOfActiveCall(const QString& confId,
const QString& uri,
const QString& deviceId);
@ -157,6 +159,7 @@ private:
QString selectedConvUid_;
MapStringString contentDrafts_;
MapStringString lastConferences_;
MapStringListString fileDrafts_;
conversation::Info invalid {"", nullptr};

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,30 @@ 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: {
// HACK: Only display the version string if it has been constructed properly.
// This is a workaround for an issue that occurs due to the way Linux
// packaging is done, where the git repository is not available in the
// build source at configure time, which is when the version files are
// generated, so we prevent a "." from being displayed if the version
// string is not available.
var contentStr = JamiStrings.buildID + ": " + UtilsAdapter.getBuildIDStr();
const versionStr = UtilsAdapter.getVersionStr()
if (versionStr.length > 1) {
contentStr += "\n" + JamiStrings.version + ": " + (isBeta ? "(Beta) " : "") + versionStr
}
return contentStr
}
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

@ -27,6 +27,14 @@ import "../js/pluginhandlerpickercreation.js" as PluginHandlerPickerCreation
Rectangle {
id: root
// HACK: Added to capture the mouse when the layouts start stacking.
// The header and footer we're unable to be interacted with otherwise.
MouseArea {
anchors.fill: parent
propagateComposedEvents: false
enabled: viewCoordinator.isInSinglePaneMode
}
// An enum to make the details panels more readable.
enum ExtrasPanel {
SwarmDetailsPanel,
@ -133,8 +141,13 @@ Rectangle {
target: CurrentConversation
function onIdChanged() {
if (!chatViewHeader.interactionButtonsVisibility)
if (!chatViewHeader.detailsButtonVisibility) {
extrasPanel.closePanel();
} else if (width < JamiTheme.mainViewMinWidth + extrasPanel.width) {
extrasPanel.closePanel();
} else if (!chatViewHeader.interactionButtonsVisibility) {
extrasPanel.closePanel();
}
}
function onNeedsHost() {

View File

@ -43,17 +43,31 @@ Rectangle {
color: JamiTheme.primaryBackgroundColor
function updateMessageDraft() {
LRCInstance.setContentDraft(previousConvId, previousAccountId, messageBar.text);
// Store the current files that have not been sent, if any. Do the same for the message draft.
var filePathDraft = [];
while(messageBar.fileContainer.filesToSendCount > 0) {
var currentIndex = messageBar.fileContainer.filesToSendListModel.index(0, 0);
var filePath = messageBar.fileContainer.filesToSendListModel.data(currentIndex, FilesToSend.FilePath);
filePathDraft.push(filePath);
messageBar.fileContainer.filesToSendListModel.removeFromPending(0);
}
LRCInstance.setContentDraft(previousConvId, previousAccountId, messageBar.text, filePathDraft);
previousConvId = CurrentConversation.id;
previousAccountId = CurrentAccount.id;
// turn off the button animations when switching convs
messageBar.animate = false;
messageBar.textAreaObj.clearText();
// restore the draft state of contents for a specific conversation
var restoredContent = LRCInstance.getContentDraft(CurrentConversation.id, CurrentAccount.id);
if (restoredContent) {
messageBar.textAreaObj.insertText(restoredContent);
messageBar.textAreaObj.insertText(restoredContent["text"]);
for (var i = 0; i < restoredContent["files"].length; ++i) {
messageBar.fileContainer.filesToSendListModel.addToPending(restoredContent["files"][i]);
}
}
}
Connections {
@ -134,7 +148,7 @@ Rectangle {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: footerColumnLayout.width
Layout.leftMargin: 0
Layout.leftMargin: marginSize
Layout.rightMargin: marginSize
Layout.bottomMargin: marginSize
Layout.preferredHeight: height

View File

@ -23,7 +23,6 @@ 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"
Rectangle {
@ -46,6 +45,8 @@ Rectangle {
}
}
property bool detailsButtonVisibility: detailsButton.visible
readonly property bool interactionButtonsVisibility: {
if (CurrentConversation.inCall)
return false;
@ -59,9 +60,7 @@ Rectangle {
}
property bool addMemberVisibility: {
return swarmDetailsVisibility
&& !CurrentConversation.isCoreDialog
&& !CurrentConversation.isRequest;
return swarmDetailsVisibility && !CurrentConversation.isCoreDialog && !CurrentConversation.isRequest;
}
property bool swarmDetailsVisibility: {
@ -79,8 +78,10 @@ Rectangle {
anchors.rightMargin: 10 + layoutManager.qwkSystemButtonSpacing.right
spacing: 16
JamiPushButton { QWKSetParentHitTestVisible {}
JamiPushButton {
id: backToWelcomeViewButton
QWKSetParentHitTestVisible {
}
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 8
@ -88,7 +89,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()
}
@ -107,8 +108,10 @@ Rectangle {
color: JamiTheme.transparentColor
ColumnLayout { QWKSetParentHitTestVisible {}
ColumnLayout {
id: userNameOrIdColumnLayout
QWKSetParentHitTestVisible {
}
objectName: "userNameOrIdColumnLayout"
height: parent.height
@ -146,72 +149,79 @@ Rectangle {
}
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: startAAudioCallButton
JamiPushButton {
id: startAudioCallButton
QWKSetParentHitTestVisible {
}
visible: interactionButtonsVisibility &&
(!addMemberVisibility || UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
visible: interactionButtonsVisibility && (!addMemberVisibility || UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
source: JamiResources.place_audiocall_24dp_svg
toolTipText: JamiStrings.placeAudioCall
toolTipText: JamiStrings.startAudioCall
onClicked: CallAdapter.placeAudioOnlyCall()
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: startAVideoCallButton
JamiPushButton {
id: startVideoCallButton
QWKSetParentHitTestVisible {
}
visible: interactionButtonsVisibility &&
CurrentAccount.videoEnabled_Video &&
(!addMemberVisibility || UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
visible: interactionButtonsVisibility && CurrentAccount.videoEnabled_Video && (!addMemberVisibility || UtilsAdapter.getAppValue(Settings.EnableExperimentalSwarm))
source: JamiResources.videocam_24dp_svg
toolTipText: JamiStrings.placeVideoCall
toolTipText: JamiStrings.startVideoCall
onClicked: CallAdapter.placeCall()
}
JamiPushButton { QWKSetParentHitTestVisible {}
id: addParticipantsButton
JamiPushButton {
id: inviteMembersButton
QWKSetParentHitTestVisible {
}
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
JamiPushButton {
id: selectExtensionsButton
QWKSetParentHitTestVisible {
}
visible: PluginAdapter.chatHandlersListCount && interactionButtonsVisibility
source: JamiResources.plugins_24dp_svg
toolTipText: JamiStrings.showPlugins
toolTipText: JamiStrings.showExtensions
onClicked: pluginSelector()
}
JamiPushButton { QWKSetParentHitTestVisible {}
JamiPushButton {
id: sendContactRequestButton
QWKSetParentHitTestVisible {
}
objectName: "sendContactRequestButton"
visible: CurrentConversation.isTemporary || CurrentConversation.isBanned
source: JamiResources.add_people_24dp_svg
toolTipText: JamiStrings.addToConversations
onClicked: CurrentConversation.isBanned ?
MessagesAdapter.unbanConversation(CurrentConversation.id) :
MessagesAdapter.sendConversationRequest()
onClicked: CurrentConversation.isBanned ? MessagesAdapter.unbanConversation(CurrentConversation.id) : MessagesAdapter.sendConversationRequest()
}
JamiPushButton { QWKSetParentHitTestVisible {}
JamiPushButton {
id: searchMessagesButton
QWKSetParentHitTestVisible {
}
objectName: "searchMessagesButton"
checkable: true
checked: extrasPanel.isOpen(ChatView.MessagesResearchPanel)
visible: root.swarmDetailsVisibility
source: JamiResources.ic_baseline_search_24dp_svg
source: JamiResources.ic_baseline_search_24dp_svg
toolTipText: JamiStrings.search
onClicked: extrasPanel.switchToPanel(ChatView.MessagesResearchPanel)
@ -224,8 +234,10 @@ Rectangle {
}
}
JamiPushButton { QWKSetParentHitTestVisible {}
JamiPushButton {
id: detailsButton
QWKSetParentHitTestVisible {
}
objectName: "detailsButton"
checkable: true

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

@ -28,7 +28,6 @@ Rectangle {
property alias filesToSendListModel: repeater.model
property alias filesToSendCount: repeater.count
color: JamiTheme.primaryBackgroundColor
LayoutMirroring.enabled: UtilsAdapter.isRTL
LayoutMirroring.childrenInherit: true
@ -51,7 +50,7 @@ Rectangle {
layoutDirection: UtilsAdapter.isRTL ? Qt.RightToLeft : Qt.LeftToRight
spacing: JamiTheme.filesToSendContainerSpacing
padding: JamiTheme.filesToSendContainerPadding
//padding: JamiTheme.filesToSendContainerPadding
Repeater {
id: repeater

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

File diff suppressed because it is too large Load Diff

View File

@ -17,23 +17,20 @@
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "../../commoncomponents"
import QtQuick.Layouts
import SortFilterProxyModel 0.2
import "../../commoncomponents"
JamiFlickable {
id: root
property int maxWidth: 330
property bool tooMuch: {
if (maxWidth > 0)
return textArea.contentWidth > maxWidth;
return false;
}
property alias text: textArea.text
property var textAreaObj: textArea
property alias placeholderText: textArea.placeholderText
@ -42,16 +39,15 @@ JamiFlickable {
property alias selectionEnd: textArea.selectionEnd
property bool showPreview: false
property bool isShowTypo: UtilsAdapter.getAppValue(Settings.Key.ShowMardownOption)
property int textWidth: textArea.contentWidth
ScrollBar.vertical.visible: textArea.text
ScrollBar.horizontal.visible: textArea.text
// Used to cache the editable text when showing the preview message
// and also to debounce the textChanged signal's effect on the composing status.
property string cachedText
property string debounceText
signal sendMessagesRequired
function heightBinding() {
textArea.height = Qt.binding(() => textArea.lineCount === 1 ? 35 : textArea.paintedHeight);
}
function selectText(start, end) {
textArea.select(start, end);
}
@ -60,18 +56,18 @@ JamiFlickable {
textArea.insert(textArea.cursorPosition, text);
}
function clearText() {
var multiLine = textArea.lineCount !== 1;
textArea.clear();
if (multiLine) {
heightBinding();
}
}
function pasteText() {
textArea.paste();
}
function clearText() {
textArea.clear();
}
function restoreVisibilityAfterSend() {
showPreview = false;
}
LineEditContextMenu {
id: textAreaContextMenu
@ -84,94 +80,55 @@ JamiFlickable {
}
}
interactive: true
attachedFlickableMoving: textAreaPreview.height > height || textArea.height > height || root.moving
ScrollBar.vertical.visible: text
ScrollBar.horizontal.visible: text
contentHeight: showPreview ? textAreaPreview.height : textArea.height
boundsMovement: Flickable.StopAtBounds
boundsBehavior: Flickable.DragOverBounds
interactive: true
function resetEditableText() {
textArea.text = cachedText;
textArea.update();
}
onShowPreviewChanged: {
if (showPreview) {
textAreaPreview.height = textArea.lineCount === 1 ? textArea.height : textAreaPreview.paintedHeight;
cachedText = textArea.text;
MessagesAdapter.parseMessage("", textArea.text, false, "", "");
} else {
textArea.textFormatChanged.disconnect(resetEditableText);
textArea.textFormatChanged.connect(resetEditableText);
}
heightBinding();
}
TextArea {
id: textAreaPreview
onWidthChanged: root.height = this.height
overwriteMode: false
readOnly: true
height: textArea.lineCount === 1 ? textArea.height : this.paintedHeight
width: textArea.width
visible: showPreview
leftPadding: JamiTheme.scrollBarHandleSize
rightPadding: JamiTheme.scrollBarHandleSize
topPadding: 0
bottomPadding: 0
Connections {
target: textArea
function onTextChanged() {
MessagesAdapter.parseMessage("", textArea.text, false, "", "");
Connections {
target: MessagesAdapter
function onMessageParsed(messageId, messageText) {
if (messageId === "") {
textArea.text = messageText;
textArea.update();
}
}
Connections {
target: MessagesAdapter
function onMessageParsed(messageId, messageText) {
if (messageId === "") {
textAreaPreview.text = messageText;
}
}
}
verticalAlignment: TextEdit.AlignVCenter
font.pointSize: JamiTheme.textFontSize + 2
font.hintingPreference: Font.PreferNoHinting
color: JamiTheme.textColor
wrapMode: TextEdit.Wrap
textFormat: TextEdit.RichText
placeholderTextColor: JamiTheme.messageBarPlaceholderTextColor
horizontalAlignment: Text.AlignLeft
background: Rectangle {
border.width: 0
color: "transparent"
}
}
TextArea.flickable: TextArea {
id: textArea
visible: !showPreview
readOnly: showPreview
leftPadding: JamiTheme.scrollBarHandleSize
rightPadding: JamiTheme.scrollBarHandleSize
topPadding: 0
bottomPadding: 0
persistentSelection: true
height: textArea.lineCount === 1 ? 35 : textArea.paintedHeight
verticalAlignment: TextEdit.AlignVCenter
font.pointSize: JamiTheme.textFontSize + 2
font.hintingPreference: Font.PreferNoHinting
color: JamiTheme.textColor
wrapMode: TextEdit.Wrap
selectByMouse: true
textFormat: TextEdit.PlainText
selectByMouse: !showPreview
textFormat: showPreview ? TextEdit.RichText : TextEdit.PlainText
placeholderTextColor: JamiTheme.messageBarPlaceholderTextColor
horizontalAlignment: Text.AlignLeft
property var cacheText: ""
background: Rectangle {
border.width: 0
@ -184,8 +141,8 @@ JamiFlickable {
}
onTextChanged: {
if (text != cacheText) {
cacheText = text;
if (text !== debounceText && !showPreview) {
debounceText = text;
MessagesAdapter.userIsComposing(text ? true : false);
}
}

View File

@ -0,0 +1,693 @@
/*
* 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/>.
*/
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import SortFilterProxyModel 0.2
import net.jami.Adapters 1.1
import net.jami.Models 1.1
import net.jami.Enums 1.1
import net.jami.Constants 1.1
import "../../commoncomponents"
import "qrc:/js/markdownedition.js" as MDE
Rectangle {
id: messageBarRowLayout
Layout.preferredWidth: showTypo ? firstRow.width + secondRow.width : secondRow.width
LayoutMirroring.enabled: UtilsAdapter.isRTL
LayoutMirroring.childrenInherit: true
Row {
id: firstRow
anchors.left: messageBarRowLayout.left
anchors.bottom: messageBarRowLayout.bottom
Row {
id: listViewTypo
height: JamiTheme.chatViewFooterButtonSize
ListView {
id: listViewTypoFirst
objectName: "listViewTypoFirst"
visible: showTypo
width: visible ? contentWidth + 2 * leftMargin : 0
Behavior on width {
NumberAnimation {
duration: JamiTheme.longFadeDuration / 2
}
}
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
property list<Action> menuTypoActionsFirst: [
Action {
id: boldAction
property string iconSrc: JamiResources.bold_black_24dp_svg
property string shortcutText: JamiStrings.bold
property string shortcutKey: "Ctrl+B"
property bool isStyle: MDE.isStyle(messageBarTextArea, rectangle.text, "**", "**")
onTriggered: MDE.addStyle(messageBarTextArea, rectangle.text, "**", "**")
},
Action {
id: italicAction
property string iconSrc: JamiResources.italic_black_24dp_svg
property string shortcutText: JamiStrings.italic
property string shortcutKey: "Ctrl+I"
property bool isStyle: MDE.isStyle(messageBarTextArea, rectangle.text, "*", "*")
onTriggered: MDE.addStyle(messageBarTextArea, rectangle.text, "*", "*")
},
Action {
id: strikethroughAction
property string iconSrc: JamiResources.s_barre_black_24dp_svg
property string shortcutText: JamiStrings.strikethrough
property string shortcutKey: "Shift+Alt+X"
property bool isStyle: MDE.isStyle(messageBarTextArea, rectangle.text, "~~", "~~")
onTriggered: MDE.addStyle(messageBarTextArea, rectangle.text, "~~", "~~")
},
Action {
id: titleAction
property string iconSrc: JamiResources.title_black_24dp_svg
property string shortcutText: JamiStrings.heading
property string shortcutKey: "Ctrl+Alt+H"
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, rectangle.text, "### ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, rectangle.text, "### ", false)
},
Action {
id: linkAction
property string iconSrc: JamiResources.link_web_black_24dp_svg
property string shortcutText: JamiStrings.link
property string shortcutKey: "Ctrl+Alt+K"
property bool isStyle: MDE.isStyle(messageBarTextArea, rectangle.text, "[", "](url)")
onTriggered: MDE.addStyle(messageBarTextArea, rectangle.text, "[", "](url)")
},
Action {
id: codeAction
property string iconSrc: JamiResources.code_black_24dp_svg
property string shortcutText: JamiStrings.code
property string shortcutKey: "Ctrl+Alt+C"
property bool isStyle: MDE.isStyle(messageBarTextArea, rectangle.text, "```", "```")
onTriggered: MDE.addStyle(messageBarTextArea, rectangle.text, "```", "```")
}
]
model: menuTypoActionsFirst
delegate: PushButton {
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
preferredSize: JamiTheme.chatViewFooterButtonSize
imageContainerWidth: 15
imageContainerHeight: 15
radius: 5
hoverEnabled: !showPreview
enabled: !showPreview
toolTipText: modelData.shortcutText
shortcutKey: modelData.shortcutKey
hasShortcut: true
source: modelData.iconSrc
focusPolicy: Qt.TabFocus
normalColor: {
if (showPreview) {
return JamiTheme.primaryBackgroundColor;
} else if (modelData.isStyle) {
return JamiTheme.hoveredButtonColor;
} else {
return JamiTheme.primaryBackgroundColor;
}
}
imageColor: {
if (showPreview) {
return JamiTheme.chatViewFooterImgDisableColor;
} else if (hovered) {
return JamiTheme.chatViewFooterImgHoverColor;
} else if (modelData.isStyle) {
return JamiTheme.chatViewFooterImgHoverColor;
} else {
return JamiTheme.chatViewFooterImgColor;
}
}
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
action: modelData
}
}
Rectangle {
height: JamiTheme.chatViewFooterButtonSize
color: JamiTheme.primaryBackgroundColor
visible: showTypo && showTypoSecond
width: 5
Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
width: 1
height: JamiTheme.chatViewFooterButtonSize * 2 / 3
color: showPreview ? JamiTheme.chatViewFooterImgDisableColor : JamiTheme.chatViewFooterSeparateLineColor
}
}
Rectangle {
z: -1
radius: 0
color: JamiTheme.primaryBackgroundColor
width: JamiTheme.chatViewFooterButtonSize
height: JamiTheme.chatViewFooterButtonSize
visible: showTypo && !showTypoSecond
ComboBox {
id: showMoreTypoButton
width: JamiTheme.chatViewFooterButtonSize
height: width
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
enabled: !showPreview
hoverEnabled: !showPreview
MaterialToolTip {
id: toolTip
parent: showMoreTypoButton
visible: showMoreTypoButton.hovered && (text.length > 0)
delay: Qt.styleHints.mousePressAndHoldInterval
text: markdownPopup.visible ? JamiStrings.showLess : JamiStrings.showMore
}
background: Rectangle {
implicitWidth: showMoreTypoButton.width
implicitHeight: showMoreTypoButton.height
radius: 5
color: showPreview ? JamiTheme.transparentColor : (parent && parent.hovered ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor)
}
indicator: ResponsiveImage {
containerHeight: 20
containerWidth: 20
width: 18
height: 18
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
source: JamiResources.more_vert_24dp_svg
color: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (parent && parent.hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
}
popup: MarkdownPopup {
id: markdownPopup
y: 1.5 * parent.height
x: -parent.width * 2
width: listViewTypoSecond.width + 10
height: JamiTheme.chatViewFooterButtonSize
menuTypoActionsSecond: listViewTypoSecond.menuTypoActionsSecond
}
}
}
ListView {
id: listViewTypoSecond
visible: showTypo && showTypoSecond
width: contentWidth + 2 * leftMargin
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
Rectangle {
anchors.fill: parent
color: JamiTheme.transparentColor
z: -1
}
property list<Action> menuTypoActionsSecond: [
Action {
id: quoteAction
property string iconSrc: JamiResources.quote_black_24dp_svg
property string shortcutText: JamiStrings.quote
property string shortcutKey: "Shift+Alt+9"
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, rectangle.text, "> ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, rectangle.text, "> ", false)
},
Action {
id: unorderedListAction
property string iconSrc: JamiResources.bullet_point_black_24dp_svg
property string shortcutText: JamiStrings.unorderedList
property string shortcutKey: "Shift+Alt+8"
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, rectangle.text, "- ", false)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, rectangle.text, "- ", false)
},
Action {
id: orderedListAction
property string iconSrc: JamiResources.bullet_number_black_24dp_svg
property string shortcutText: JamiStrings.orderedList
property string shortcutKey: "Shift+Alt+7"
property bool isStyle: MDE.isPrefixSyle(messageBarTextArea, rectangle.text, "", true)
onTriggered: MDE.addPrefixStyle(messageBarTextArea, rectangle.text, "", true)
}
]
model: menuTypoActionsSecond
delegate: PushButton {
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
preferredSize: JamiTheme.chatViewFooterButtonSize
imageContainerWidth: 20
imageContainerHeight: 20
radius: 5
hoverEnabled: !showPreview
enabled: !showPreview
toolTipText: modelData.shortcutText
shortcutKey: modelData.shortcutKey
hasShortcut: modelData.hasShortcut ? true : false
source: modelData.iconSrc
focusPolicy: Qt.TabFocus
normalColor: {
if (showPreview) {
return JamiTheme.primaryBackgroundColor;
} else if (modelData.normalColor) {
return modelData.normalColor;
} else if (modelData.isStyle) {
return JamiTheme.hoveredButtonColor;
} else {
return JamiTheme.primaryBackgroundColor;
}
}
imageColor: {
if (showPreview) {
return JamiTheme.chatViewFooterImgDisableColor;
} else if (hovered) {
return JamiTheme.chatViewFooterImgHoverColor;
} else if (modelData.isStyle) {
return JamiTheme.chatViewFooterImgHoverColor;
} else {
return JamiTheme.chatViewFooterImgColor;
}
}
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
action: modelData
}
}
}
}
Row {
id: secondRow
anchors.right: messageBarRowLayout.right
anchors.bottom: messageBarRowLayout.bottom
PushButton {
id: typoButton
preferredSize: JamiTheme.chatViewFooterButtonSize
imageContainerWidth: 24
imageContainerHeight: 24
radius: JamiTheme.chatViewFooterButtonRadius
hoverEnabled: !showPreview
enabled: !showPreview
toolTipText: showTypo ? JamiStrings.hideFormatting : JamiStrings.showFormatting
source: JamiResources.text_edit_black_24dp_svg
normalColor: showPreview ? JamiTheme.primaryBackgroundColor : (showTypo ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor)
imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered || showTypo ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
onClicked: {
showTypo = !showTypo;
messageBarTextArea.isShowTypo = showTypo;
if (messageBar.width < messageBarLayoutMaximumWidth + sendMessageButton.width + 2 * JamiTheme.preferredMarginSize)
showTypoSecond = false;
if (!showDefault)
showDefault = true;
UtilsAdapter.setAppValue(Settings.Key.ShowMardownOption, showTypo);
UtilsAdapter.setAppValue(Settings.Key.ShowSendOption, !showDefault);
}
}
ListView {
id: listViewMoreButton
width: 0
Behavior on width {
NumberAnimation {
duration: JamiTheme.longFadeDuration / 2
}
}
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
leftMargin: 10
rightMargin: 10
property list<Action> menuMoreButton: [
Action {
id: 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
property bool noSip: false
onTriggered: function clickAction() {
audioRecordMessageButtonClicked();
}
},
Action {
id: 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
property bool noSip: false
onTriggered: function clickAction() {
videoRecordMessageButtonClicked();
}
},
Action {
id: 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
property bool noSip: false
onTriggered: function clickAction() {
showMapClicked();
}
}
]
ListModel {
id: listMoreButton
Component.onCompleted: {
for (var i = 0; i < listViewMoreButton.menuMoreButton.length; i++) {
append({
"menuAction": listViewMoreButton.menuMoreButton[i]
});
}
}
}
model: SortFilterProxyModel {
sourceModel: listMoreButton
filters: [
ExpressionFilter {
expression: menuAction.show === true
enabled: showDefault
},
ExpressionFilter {
expression: menuAction.needWebEngine === false
enabled: !WITH_WEBENGINE
},
ExpressionFilter {
expression: menuAction.noSip === true
enabled: CurrentConversation.isSip
},
ExpressionFilter {
expression: menuAction.needVideoDevice === false
enabled: VideoDevices.listSize === 0
}
]
}
delegate: PushButton {
id: buttonDelegateMoreButton
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
preferredSize: JamiTheme.chatViewFooterButtonSize
imageContainerWidth: 20
imageContainerHeight: 20
radius: 5
enabled: !showPreview
hoverEnabled: !showPreview
toolTipText: modelData.toolTip
source: modelData.iconSrc
normalColor: showPreview ? JamiTheme.primaryBackgroundColor : (showTypo ? JamiTheme.hoveredButtonColor : JamiTheme.primaryBackgroundColor)
imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
action: modelData
}
}
Rectangle {
height: JamiTheme.chatViewFooterButtonSize
width: JamiTheme.chatViewFooterButtonSize
Layout.alignment: Qt.AlignRight
visible: !CurrentConversation.isSip
color: JamiTheme.transparentColor
ComboBox {
id: showMoreButton
focus: true
width: JamiTheme.chatViewFooterButtonSize
height: JamiTheme.chatViewFooterButtonSize
anchors.bottom: parent.bottom
enabled: !showPreview
hoverEnabled: !showPreview
// Used to choose the correct color for the button.
readonly property bool highlight: down || hovered
background: Rectangle {
implicitWidth: showMoreButton.width
implicitHeight: showMoreButton.height
radius: 5
color: showMoreButton.highlight ? JamiTheme.hoveredButtonColor : JamiTheme.transparentColor
}
MaterialToolTip {
id: toolTipMoreButton
parent: showMoreButton
visible: showMoreButton.hovered && (text.length > 0)
delay: Qt.styleHints.mousePressAndHoldInterval
text: showMoreButton.down ? JamiStrings.showLess : JamiStrings.showMore
}
indicator: ResponsiveImage {
width: 20
height: 20
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
source: JamiResources.more_menu_black_24dp_svg
color: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
}
Component {
id: sharePopupComp
ShareMenu {
id: sharePopup
onAudioRecordMessageButtonClicked: rectangle.audioRecordMessageButtonClicked()
onVideoRecordMessageButtonClicked: rectangle.videoRecordMessageButtonClicked()
onShowMapClicked: rectangle.showMapClicked()
modelList: listViewMoreButton.menuMoreButton
y: showMoreButton.y + 31
x: showMoreButton.x - 3
}
}
popup: ShareMenu {
id: sharePopup
onAudioRecordMessageButtonClicked: rectangle.audioRecordMessageButtonClicked()
onVideoRecordMessageButtonClicked: rectangle.videoRecordMessageButtonClicked()
onShowMapClicked: rectangle.showMapClicked()
modelList: listViewMoreButton.menuMoreButton
y: showMoreButton.y + 31
x: showMoreButton.x - 3
}
}
}
ListView {
id: listViewAction
width: contentWidth + 2 * leftMargin
Behavior on width {
NumberAnimation {
duration: JamiTheme.longFadeDuration / 2
}
}
height: JamiTheme.chatViewFooterButtonSize
orientation: ListView.Horizontal
interactive: false
property list<Action> menuActions: [
Action {
id: 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
property bool noSip: false
onTriggered: function clickAction() {
sendFileButtonClicked();
textAreaObj.forceActiveFocus();
}
},
Action {
id: 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
property bool noSip: true
onTriggered: function clickAction() {
emojiButtonClicked();
}
}
]
ListModel {
id: listActions
Component.onCompleted: {
for (var i = 0; i < listViewAction.menuActions.length; i++) {
append({
"menuAction": listViewAction.menuActions[i]
});
}
}
}
model: SortFilterProxyModel {
sourceModel: listActions
filters: [
ExpressionFilter {
expression: menuAction.show === true
enabled: rectangle.showDefault
},
ExpressionFilter {
expression: menuAction.needWebEngine === false
enabled: !WITH_WEBENGINE
},
ExpressionFilter {
expression: menuAction.noSip === true
enabled: CurrentConversation.isSip
},
ExpressionFilter {
expression: menuAction.needVideoDevice === false
enabled: VideoDevices.listSize === 0
}
]
}
delegate: PushButton {
id: buttonDelegate
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
preferredSize: JamiTheme.chatViewFooterButtonSize
imageContainerWidth: 25
imageContainerHeight: 25
radius: 5
hoverEnabled: !showPreview
enabled: !showPreview
toolTipText: modelData.toolTip
source: modelData.iconSrc
normalColor: JamiTheme.primaryBackgroundColor
imageColor: showPreview ? JamiTheme.chatViewFooterImgDisableColor : (hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor)
hoveredColor: JamiTheme.hoveredButtonColor
pressedColor: hoveredColor
action: modelData
}
}
Rectangle {
Layout.alignment: Qt.AlignRight
height: JamiTheme.chatViewFooterButtonSize
width: JamiTheme.chatViewFooterButtonSize
Layout.rightMargin: marginSize / 2
visible: true
color: JamiTheme.transparentColor
PushButton {
id: sendMessageButton
objectName: "sendMessageButton"
anchors.bottom: parent.bottom
enabled: sendButtonVisibility
hoverEnabled: enabled
width: scale * JamiTheme.chatViewFooterButtonSize
height: JamiTheme.chatViewFooterButtonSize
radius: JamiTheme.chatViewFooterButtonRadius
preferredSize: JamiTheme.chatViewFooterButtonIconSize - 6
imageContainerWidth: 25
imageContainerHeight: 25
toolTipText: JamiStrings.send
mirror: UtilsAdapter.isRTL
source: JamiResources.send_black_24dp_svg
normalColor: enabled ? JamiTheme.chatViewFooterSendButtonColor : JamiTheme.chatViewFooterSendButtonDisableColor
imageColor: enabled ? JamiTheme.chatViewFooterSendButtonImgColor : JamiTheme.chatViewFooterSendButtonImgColorDisable
hoveredColor: JamiTheme.buttonTintedBlueHovered
pressedColor: hoveredColor
opacity: 1
scale: opacity
Behavior on opacity {
enabled: animate
NumberAnimation {
duration: JamiTheme.shortFadeDuration
easing.type: Easing.InOutQuad
}
}
onClicked: {
rectangle.showPreview = false;
sendMessageButtonClicked();
}
}
}
}
}

View File

@ -19,40 +19,37 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt.labs.qmlmodels
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import "../../commoncomponents"
JamiListView {
id: root
function getDistanceToBottom() {
const scrollDiff = ScrollBar.vertical.position -
(1.0 - ScrollBar.vertical.size)
return Math.abs(scrollDiff) * contentHeight
const scrollDiff = ScrollBar.vertical.position - (1.0 - ScrollBar.vertical.size);
return Math.abs(scrollDiff) * contentHeight;
}
function loadMoreMsgsIfNeeded() {
if (atYBeginning && !CurrentConversation.allMessagesLoaded) {
MessagesAdapter.loadMoreMessages()
MessagesAdapter.loadMoreMessages();
}
}
function computeTimestampVisibility(item1, item1Index, item2, item2Index) {
if (item1 && item2) {
if (item1Index < item2Index) {
item1.showTime = item1.timestamp - item2.timestamp > JamiTheme.timestampIntervalTime
item1.showDay = item1.formattedDay !== item2.formattedDay
item1.showTime = item1.timestamp - item2.timestamp > JamiTheme.timestampIntervalTime;
item1.showDay = item1.formattedDay !== item2.formattedDay;
} else {
item2.showTime = item2.timestamp - item1.timestamp > JamiTheme.timestampIntervalTime
item2.showDay = item2.formattedDay !== item1.formattedDay
item2.showTime = item2.timestamp - item1.timestamp > JamiTheme.timestampIntervalTime;
item2.showDay = item2.formattedDay !== item1.formattedDay;
}
return true
return true;
}
return false
return false;
}
function scrollToBottom() {
@ -60,27 +57,28 @@ JamiListView {
}
function computeChatview(item, itemIndex) {
if (!root) return
var rootItem = root.itemAtIndex(0)
var pItem = root.itemAtIndex(itemIndex - 1)
var pItemIndex = itemIndex - 1
var nItem = root.itemAtIndex(itemIndex + 1)
var nItemIndex = itemIndex + 1
if (!root)
return;
var rootItem = root.itemAtIndex(0);
var pItem = root.itemAtIndex(itemIndex - 1);
var pItemIndex = itemIndex - 1;
var nItem = root.itemAtIndex(itemIndex + 1);
var nItemIndex = itemIndex + 1;
// middle insertion
if (pItem && nItem) {
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex)
computeSequencing(item, nItem, root.itemAtIndex(itemIndex + 2))
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex);
computeSequencing(item, nItem, root.itemAtIndex(itemIndex + 2));
}
// top buffer insertion = scroll up
if (pItem && !nItem) {
computeTimestampVisibility(item, itemIndex, pItem, pItemIndex)
computeSequencing(root.itemAtIndex(itemIndex - 2), pItem, item)
computeTimestampVisibility(item, itemIndex, pItem, pItemIndex);
computeSequencing(root.itemAtIndex(itemIndex - 2), pItem, item);
}
// bottom buffer insertion = scroll down
if (!pItem && nItem) {
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex)
computeSequencing(item, nItem, root.itemAtIndex(itemIndex + 2))
computeTimestampVisibility(item, itemIndex, nItem, nItemIndex);
computeSequencing(item, nItem, root.itemAtIndex(itemIndex + 2));
}
// index 0 insertion = new message
if (itemIndex === 0) {
@ -88,57 +86,56 @@ JamiListView {
// This needs to be done in a delayed fashion because the new message is inserted
// at the top of the list and the list is not yet updated.
Qt.callLater(() => {
var fItem = root.itemAtIndex(1)
if (fItem) {
computeTimestampVisibility(item, 0, fItem, 1)
computeSequencing(null, item, fItem)
computeSequencing(item, fItem, root.itemAtIndex(2))
}
})
var fItem = root.itemAtIndex(1);
if (fItem) {
computeTimestampVisibility(item, 0, fItem, 1);
computeSequencing(null, item, fItem);
computeSequencing(item, fItem, root.itemAtIndex(2));
}
});
}
// top element
if(itemIndex === root.count - 1 && CurrentConversation.allMessagesLoaded) {
item.showTime = true
item.showDay = true
if (itemIndex === root.count - 1 && CurrentConversation.allMessagesLoaded) {
item.showTime = true;
item.showDay = true;
}
}
function computeSequencing(pItem, item, nItem) {
if (root === undefined || !item)
return
return;
function isFirst() {
if (!nItem) return true
if (!nItem)
return true;
else {
if (item.showTime || item.isReply ) {
return true
if (item.showTime || item.isReply) {
return true;
} else if (nItem.author !== item.author) {
return true
return true;
}
}
return false
return false;
}
function isLast() {
if (!pItem) return true
if (!pItem)
return true;
else {
if (pItem.showTime || pItem.isReply) {
return true
return true;
} else if (pItem.author !== item.author) {
return true
return true;
}
}
return false
return false;
}
if (isLast() && isFirst())
item.seq = MsgSeq.single
item.seq = MsgSeq.single;
if (!isLast() && isFirst())
item.seq = MsgSeq.first
item.seq = MsgSeq.first;
if (isLast() && !isFirst())
item.seq = MsgSeq.last
item.seq = MsgSeq.last;
if (!isLast() && !isFirst())
item.seq = MsgSeq.middle
item.seq = MsgSeq.middle;
}
// fade-in mechanism
@ -151,12 +148,16 @@ JamiListView {
SequentialAnimation {
id: fadeAnimation
NumberAnimation {
target: overlay; property: "opacity"
to: 1; duration: 0
target: overlay
property: "opacity"
to: 1
duration: 0
}
NumberAnimation {
target: overlay; property: "opacity"
to: 0; duration: 240
target: overlay
property: "opacity"
to: 0
duration: 240
}
}
}
@ -167,7 +168,7 @@ JamiListView {
anchors.fill: parent
function instantiateToast(dest) {
instantiate(JamiStrings.fileSaved.arg(dest), 1000, 400)
instantiate(JamiStrings.fileSaved.arg(dest), 1000, 400);
}
}
@ -175,8 +176,8 @@ JamiListView {
target: CurrentConversation
function onScrollTo(id) {
// Get the filtered index from the interaction ID.
var idx = MessagesAdapter.messageListModel.getDisplayIndex(id)
positionViewAtIndex(idx, ListView.Visible)
var idx = MessagesAdapter.messageListModel.getDisplayIndex(id);
positionViewAtIndex(idx, ListView.Visible);
}
}
@ -203,8 +204,8 @@ JamiListView {
roleValue: Interaction.Type.TEXT
TextMessageDelegate {
Component.onCompleted: {
computeChatview(this, index)
Component.onCompleted: {
computeChatview(this, index);
}
}
}
@ -213,8 +214,8 @@ JamiListView {
roleValue: Interaction.Type.CALL
CallMessageDelegate {
Component.onCompleted: {
computeChatview(this, index)
Component.onCompleted: {
computeChatview(this, index);
}
}
}
@ -223,8 +224,8 @@ JamiListView {
roleValue: Interaction.Type.CONTACT
ContactMessageDelegate {
Component.onCompleted: {
computeChatview(this, index)
Component.onCompleted: {
computeChatview(this, index);
}
}
}
@ -234,8 +235,8 @@ JamiListView {
GeneratedMessageDelegate {
font.bold: true
Component.onCompleted: {
computeChatview(this, index)
Component.onCompleted: {
computeChatview(this, index);
}
}
}
@ -244,12 +245,11 @@ JamiListView {
roleValue: Interaction.Type.DATA_TRANSFER
DataTransferMessageDelegate {
Component.onCompleted: {
computeChatview(this, index)
Component.onCompleted: {
computeChatview(this, index);
}
}
}
}
onAtYBeginningChanged: loadMoreMsgsIfNeeded()
@ -271,9 +271,8 @@ JamiListView {
target: MessagesAdapter
function onNewInteraction() {
if (root.getDistanceToBottom() < 80 &&
!root.atYEnd) {
Qt.callLater(root.positionViewAtBeginning)
if (root.getDistanceToBottom() < 80 && !root.atYEnd) {
Qt.callLater(root.positionViewAtBeginning);
}
}
@ -284,7 +283,7 @@ JamiListView {
}
function onFileCopied(dest) {
toastManager.instantiateToast(dest)
toastManager.instantiateToast(dest);
}
}
@ -294,7 +293,7 @@ JamiListView {
anchors.bottom: root.bottom
anchors.bottomMargin: JamiTheme.chatViewScrollToBottomButtonBottomMargin
anchors.horizontalCenter: root.horizontalCenter
visible: 1 - verticalScrollBar.position >= verticalScrollBar.size * 2
visible: 1 - verticalScrollBar.position >= verticalScrollBar.size * 2
onClicked: scrollToBottom()
}
@ -326,36 +325,31 @@ JamiListView {
Connections {
target: MessagesAdapter
function onCurrentConvComposingListChanged () {
var typeIndicatorNameTextString = ""
var nameList = MessagesAdapter.currentConvComposingList
function onCurrentConvComposingListChanged() {
var typeIndicatorNameTextString = "";
var nameList = MessagesAdapter.currentConvComposingList;
if (nameList.length > 4) {
typeIndicatorNameText.text = ""
typeIndicatorEndingText.text = JamiStrings.typeIndicatorMax
typeIndicatorNameText.calculateWidth()
return
typeIndicatorNameText.text = "";
typeIndicatorEndingText.text = JamiStrings.typeIndicatorMax;
typeIndicatorNameText.calculateWidth();
return;
}
if (nameList.length === 1) {
typeIndicatorNameText.text = nameList[0]
typeIndicatorEndingText.text =
JamiStrings.typeIndicatorSingle.replace("{}", "")
typeIndicatorNameText.calculateWidth()
return
typeIndicatorNameText.text = nameList[0];
typeIndicatorEndingText.text = JamiStrings.typeIndicatorSingle.replace("{}", "");
typeIndicatorNameText.calculateWidth();
return;
}
for (var i = 0; i < nameList.length; i++) {
typeIndicatorNameTextString += nameList[i]
typeIndicatorNameTextString += nameList[i];
if (i === nameList.length - 2)
typeIndicatorNameTextString += JamiStrings.typeIndicatorAnd
typeIndicatorNameTextString += JamiStrings.typeIndicatorAnd;
else if (i !== nameList.length - 1)
typeIndicatorNameTextString += ", "
typeIndicatorNameTextString += ", ";
}
typeIndicatorNameText.text = typeIndicatorNameTextString
typeIndicatorEndingText.text =
JamiStrings.typeIndicatorPlural.replace("{}", "")
typeIndicatorNameText.calculateWidth()
typeIndicatorNameText.text = typeIndicatorNameTextString;
typeIndicatorEndingText.text = JamiStrings.typeIndicatorPlural.replace("{}", "");
typeIndicatorNameText.calculateWidth();
}
}
@ -364,17 +358,13 @@ JamiListView {
property int textWidth: 0
function calculateWidth () {
function calculateWidth() {
if (!text)
return 0
return 0;
else {
var textSize = JamiQmlUtils.getTextBoundingRect(font, text).width
var typingContentWidth = typingDots.width + typingDots.anchors.leftMargin
+ typeIndicatorNameText.anchors.leftMargin
+ typeIndicatorEndingText.contentWidth
typeIndicatorNameText.Layout.preferredWidth =
Math.min(typeIndicatorContainer.width - 5 - typingContentWidth,
textSize)
var textSize = JamiQmlUtils.getTextBoundingRect(font, text).width;
var typingContentWidth = typingDots.width + typingDots.anchors.leftMargin + typeIndicatorNameText.anchors.leftMargin + typeIndicatorEndingText.contentWidth;
typeIndicatorNameText.Layout.preferredWidth = Math.min(typeIndicatorContainer.width - 5 - typingContentWidth, textSize);
}
}

View File

@ -98,7 +98,6 @@ Page {
underlineColor: CurrentConversation.color
underlineColorHovered: CurrentConversation.color
down: researchTabBar.currentIndex === 1
labelText: JamiStrings.files
Layout.fillWidth: true

View File

@ -150,7 +150,7 @@ DualPaneView {
Layout.preferredWidth: JamiTheme.preferredFieldWidth
staticText: ""
placeholderText: JamiStrings.swarmName
placeholderText: JamiStrings.groupName
textColor: {
if (UtilsAdapter.luma(root.color)) {
@ -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.newGroup
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

@ -214,7 +214,7 @@ SidePanelBase {
font.bold: true
font.pointSize: JamiTheme.contactEventPointSize
text: JamiStrings.createSwarm
text: JamiStrings.newGroup
}
PushButton {
@ -288,7 +288,7 @@ SidePanelBase {
visible: !swarmMemberSearchList.visible && CurrentAccount.type !== Profile.Type.SIP
source: smartListLayout.visible ? JamiResources.create_swarm_svg : JamiResources.round_close_24dp_svg
toolTipText: smartListLayout.visible ? JamiStrings.startSwarm : JamiStrings.cancel
toolTipText: smartListLayout.visible ? JamiStrings.newGroup : JamiStrings.cancel
onClicked: toggleCreateSwarmView()
}

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

@ -115,7 +115,7 @@ Rectangle {
titleLine.editMode = activeFocus;
}
infoTipLineText: CurrentConversation.isCoreDialog ? JamiStrings.contactName : JamiStrings.swarmName
infoTipLineText: CurrentConversation.isCoreDialog ? JamiStrings.contactName : JamiStrings.groupName
}
ModalTextEdit {
@ -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

@ -29,25 +29,26 @@ Item {
property string accept: qsTr("Accept")
property string acceptAudio: qsTr("Accept in audio")
property string acceptVideo: qsTr("Accept in video")
property string refuse: qsTr("Refuse")
property string refuse: qsTr("Decline")
property string endCall: qsTr("End call")
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 newGroup: qsTr("Create new group")
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.")
property string migrateConversation: qsTr("Migrate conversation")
// DaemonReconnectWindow
property string reconnectWarn: qsTr("Could not re-connect to the Jami daemon (jamid).\nJami will now quit.")
property string reconnectTry: qsTr("Trying to reconnect to the Jami daemon (jamid)…")
property string reconnectWarn: qsTr("An error occurred while attempting to reconnect to the Jami daemon (jamid).\nJami will now quit.")
property string reconnectAttempt: qsTr("Attempting 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,16 @@ 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 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 +378,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 +394,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.")
@ -415,12 +414,12 @@ Item {
property string linkedOtherDevices: qsTr("Other linked devices")
// CurrentAccountSettings && AdvancedSettings
property string backupSuccessful: qsTr("Backup successful")
property string backupFailed: qsTr("Backup failed")
property string changePasswordSuccess: qsTr("Password changed successfully")
property string changePasswordFailed: qsTr("Password change failed")
property string setPasswordSuccess: qsTr("Password set successfully")
property string setPasswordFailed: qsTr("Password set failed")
property string backupSuccessful: qsTr("Backup completed successfully.")
property string backupFailed: qsTr("An error occurred while backing up account.")
property string changePasswordSuccess: qsTr("Password changed successfully.")
property string changePasswordFailed: qsTr("An error occurred while changing account password.")
property string setPasswordSuccess: qsTr("Password set successfully.")
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 +430,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 +449,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 +498,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,26 +518,26 @@ 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")
property string experimentalCallSwarm: qsTr("(Experimental) Enable call support for swarm")
property string experimentalCallSwarmTooltip: qsTr("This feature will enable call buttons in swarms with multiple participants.")
property string experimentalCallSwarm: qsTr("(Experimental) Enable call support for groups")
property string experimentalCallSwarmTooltip: qsTr("This feature will enable the audio and video call buttons in group conversations.")
// Recording Settings
property string quality: qsTr("Quality")
@ -546,9 +546,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 +557,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 +577,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 +611,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 +626,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 +663,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 +683,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 +695,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 +707,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 +737,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,12 +776,12 @@ 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?")
property string selectHost: qsTr("Select dedicated device for hosting future calls in this swarm. If not set, the host will be the device starting a call.")
property string needsHost: qsTr("Current host for this group conversation seems unreachable. Do you want to host the call?")
property string selectHost: qsTr("Select dedicated device for hosting future calls in this group conversation. If not set, the host will be the device starting a call.")
property string selectThisDevice: qsTr("Select this device")
property string selectDevice: qsTr("Select device")
property string removeCurrentDevice: qsTr("Remove current device")
@ -790,28 +792,27 @@ 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
// SwarmDetailsPanel (group conversation panel)
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 groupName: qsTr("Group 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")
// NewSwarmPage (new group conversation page)
property string goToConversation: qsTr("Go to conversation")
property string kickMember: qsTr("Kick member")
property string reinstateMember: qsTr("Reinstate member")
@ -864,20 +865,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

@ -513,6 +513,9 @@ Item {
// MessageBar
property int messageBarMarginSize: 10
property int messageBarMinimumWidth: 438
property int showTypoSecondToggleWidth: 540
property int messageBarMaximumHeight: 150
property int messageBarMinimumHeight: 36
// InvitationView
property real invitationViewAvatarSize: 112

View File

@ -159,7 +159,7 @@ NetworkManager::downloadFile(const QUrl& url,
if (!file->open(QIODevice::WriteOnly)) {
Q_EMIT errorOccurred(GetError::ACCESS_DENIED);
files_.remove(uuid);
qWarning() << Q_FUNC_INFO << "Could not open file for writing";
qWarning() << Q_FUNC_INFO << "An error occurred while opening file for writing.";
return 0;
}

View File

@ -454,7 +454,7 @@ ScreenCastPortal::getPipewireFd()
g_main_loop_run(glib_main_loop);
// The main loop will run until it's stopped by openPipewireRemote (if
// all DBus method calls were successfully), abort (in case of error) or
// all DBus method calls were successful), abort (in case of error) or
// on_cancelled_callback (if a DBus request is cancelled).
// In the latter two cases, pw_ctx->portal_error gets set to a nonzero value.
if (portal_error)
@ -512,9 +512,10 @@ ScreenCastPortal::~ScreenCastPortal()
// file descriptor needs to be closed by the client.
if (close(pipewireFd) != 0) {
int err = errno;
qWarning() << "Error while attempting to close PipeWire file descriptor: errno =" << err;
qWarning() << "An error occurred while attempting to close PipeWire file descriptor: errno ="
<< err;
} else {
qInfo() << "Successfully closed PipeWire file descriptor";
qInfo() << "PipeWire file descriptor closed successfully.";
}
#endif
}

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 () {

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