Compare commits

...

161 Commits

Author SHA1 Message Date
82eb5c59a6 CallButtonDelegate: fix audio devices index not updating
UI was not updating when an audio or video device was selected. The code
was using the currentIndex property, which is not present in
AudioDeviceModel and VideoInputDeviceModel.

They are now treated as a separate case

Change-Id: Ifbbcb99b9044daf7ab789122dad7356698595f86
2025-08-05 14:02:27 -04:00
84a9ba4196 misc: bump daemon submodule
Change-Id: I6296622528575369160a1aa68249229a92cd790f
2025-08-04 15:30:42 -04:00
6dac4d2ee3 packaging: remove Ubuntu 24.10 (EOL)
Change-Id: Id0e69c2c61d3c0d45b31a73768a27f2dfce75a7f
2025-07-30 14:24:27 -04:00
674bf38766 JamiStrings.qml: spell checker dictionary
Change-Id: I37c9b4aceb26ddfe10b62d89fe5a22fc5b291b19
2025-07-28 17:41:33 -04:00
52f3a9bc28 *.desktop and *.metainfo.xml: localize
Follow up to the https://review.jami.net/c/jami-client-qt/+/31007 patch.

Change-Id: I624aecdc9a4608fe4300db0838f57885588b33fe
GitLab: #1955
2025-07-24 17:24:27 -04:00
abce881b50 tests: fix building of previewengine_unittest
This test started failing to build with Qt 6.8.2 and/or GCC 14 in
Guix:

   error: ‘class QHttpServer’ has no member named ‘listen’
      31 |         server->listen(QHostAddress::LocalHost, 8000);

Adjust to use what the Qt documentation suggests, which is to bind the
server to a distinct QTcpServer instance.

Fixes: #1144
Change-Id: I3308acab793b3cdf74458f8196933bca26b41bb1
2025-07-22 15:43:21 -04:00
666b149033 Metainfo: Add latest stable/20250718.0 release details
Change-Id: I8fc881e707c5ef3c6d461e69f19aef92d3c2bae6
2025-07-22 10:34:04 -04:00
eb10ccbd4a misc: bump daemon submodule
Change-Id: I9f9efa528bc929d85bb072e599c2ca30c4c5488d
2025-07-21 14:02:42 -04:00
f513358236 LayoutManager: respect WITH_WEBENGINE flag
This patch updates LayoutManager to use WebEngine only
when WITH_WEBENGINE is set to true.

Change-Id: Idcfc99af9fb4d74c68aac8fc9029cde2bc05b4eb
2025-07-18 14:10:39 -04:00
3c00829afb packaging: use new icon filename
Follow-up to commit 5c772960bc.

Change-Id: Ib5c0b4bc1c5e3f5112bbd49bf323aeb4cc87c75e
2025-07-18 13:30:23 -04:00
84a59889e3 tests/qml: fix undefined references to appWindow
GitLab: #1780
Change-Id: I166f68c7abdf0f21d8d5dcec85e377c27de798a3
2025-07-16 16:17:16 -04:00
6c35561817 Reinstate "cmake: Simplify lookup logic for libjami headers." (again).
This reinstates commit f6c8197cba, which was seemingly reverted by
mistake in 4d2c55348b ("packaging: migrate from Qt 6.2.3 to
6.4.3").

Change-Id: I603e004431be0503be0acdd7ce37fa5aaa4ecd91
2025-07-16 12:58:01 -04:00
6ffdda7b81 tests: Fix WITH_WEBENGINE check.
Use #if, not #ifdef, to test the integer value of WITH_WEBENGINE, not
just whether it's defined.  Otherwise, -DWITH_WEBENGINE=OFF would not
work.

* tests/qml/main.cpp: Replace '#ifdef WITH_WEBENGINE' with '#if
WITH_WEBENGINE'.

Change-Id: Ieda8c46fa696afa1e4118acc7d4fecd4b7f9a171
2025-07-16 12:03:56 -04:00
a51078c900 tests: Avoid takeFirst-caused segfaults on empty arrays.
Replace EXPECT_EQ with ASSERT_EQ where a failure should be
fatal (abort execution).

Relates-to: <https://git.jami.net/savoirfairelinux/jami-client-qt/-/issues/1507>.
Change-Id: I4b5e38cdc399c1d1a51f72abab23cce963578541
2025-07-16 11:59:26 -04:00
76a710e2ab Fix running tests when building out of the source tree.
CMake's enable_testing needs to be called from the root of the project
as well for CTest to discover the tests in the build tree.  This is
covered in CMake's manual in section 7.2.17 enable_testing.

Change-Id: I7c9b845c52064ff83e39b483b76137b529c1a9a4
2025-07-16 11:57:28 -04:00
bc324aa8bb build: update guix manifest for build.py
Change-Id: I878ad4b2ae4adee4ebc623e4ab40362fd9e1034a
2025-07-16 11:56:55 -04:00
5c772960bc Adhere to flatpak/flathub requirements
- Developer id must be rDns identifier of developer
- Exported icons should match rDNS of app id
- Release version and dates should be included
- Added light and dark branding colours for Flathub banner
- Contact url removed - does not pass appstream validation

Change-Id: Ic5e2a5abeab4310ea87a34cc81363d1851135bcd
2025-07-16 11:31:12 -04:00
da2acefced packaging: add AlmaLinux 10
GitLab: #2065
Change-Id: I4252e2c128f72b3f6a78204a4134374b44155b80
2025-07-14 16:58:06 -04:00
524c9b0ed4 misc: bump daemon submodule
Change-Id: I98aed9601ef2c5dbaf5430ee4abf4d3ee3741f63
2025-07-14 13:29:10 -04:00
8677349c4a accessibility: fix chatview
Add keyboard and screen-reader navigation for the chat view.

Change-Id: I11a5dc1ee3b0d6303f4598f10008ecc6979bb777
2025-07-11 15:08:43 -04:00
905b2e858e build: Guard against potential unset CMAKE_BUILD_TYPE.
This would fail the build with the error:

  CMake Error at tests/CMakeLists.txt:74 (string):
    string no output variable specified

* tests/CMakeLists.txt [CMAKE_BUILD_TYPE]: Make BUILD_TYPE variable
assignment conditional.

Change-Id: I610fe296ed18bd038b2d23d4acd530f05f9526ce
2025-07-11 17:07:56 +09:00
6fc2e75a33 CMakeLists.txt: use system <md4c, tidy>
Search for libraries in the system first, falling back to bundled
copies in case they aren't found.

Change-Id: I10e154f18c569d87dbdcbee3341316ceed57f13c
GitLab: #1506
2025-07-10 10:59:30 -04:00
c738caa3a4 accessibility: fix the messagebar
Add proper labels to the messagebar and remove the existing
keyboard trap in the showmore menu.

Change-Id: Ib70ca29979dc3909585383d612d1062259df83a8
2025-07-09 11:58:49 -04:00
cb13d4f771 accessibility: fix the tip row
Indicate correctly what tips are on the main page.

Change-Id: I142cde7ab3e553cf981a59090b363694dab08775
2025-07-09 11:58:49 -04:00
436e11a6a4 accessibility: fix buttons
Fix the frameless, conversations and invitations buttons for
accessibility.

GitLab: #2049
Change-Id: I82b6722de53c40a260e706a2517aa7cb37dd99a5
2025-07-09 11:58:46 -04:00
869aef8929 accessibility: fix call action bar
Make the call action bar usable with only a keyboard and a
screen-reader by makint it visible using tab and inplementing
proper labels.

GitLab: #2049
Change-Id: Ifa1f1463f27b30bcfffae228058223729f00e51d
2025-07-08 16:40:31 -04:00
e0f939318e accessibility: fix the account creation wizard
Add support for screen readers and keyboard navigation for the account
creation.

GitLab: #2049
Change-Id: Ie91d7222388a9fb627d5a981ba9e7d8afdebcd55
2025-07-08 15:12:42 -04:00
136dea011f accessibility: fix accountlist
Allow to naviguate with keyboard inside of the accountlist and label
the accounts properly

GitLab: #2049

Change-Id: I53e5e97f344df86d6390ab444a642dcabea61cde
2025-07-08 14:16:36 -04:00
af09269d81 conversationmodel: fix multi-device file transfers
The current logic for handling received messages assumes that files sent
by the user don't need to be downloaded. However, this assumption is
incorrect when the user's account is present on multiple devices.

GitLab: #2069
Change-Id: I4e6a53389d736aec4aa86cd39862b7905b9b09ad
2025-06-26 15:30:20 -04:00
5a5ef4711d *.desktop and *.metainfo.xml: update
https://github.com/flathub/net.jami.Jami/blob/master/files/jami-client-qt_appdata.patch
https://docs.flathub.org/docs/for-app-authors/metainfo-guidelines
https://www.freedesktop.org/software/appstream/docs/chap-Metadata.html
https://specifications.freedesktop.org/desktop-entry-spec/latest/file-naming.html
https://specifications.freedesktop.org/desktop-entry-spec/latest/localized-keys.html
https://www.rfc-editor.org/rfc/bcp/bcp47.txt
https://review.jami.net/c/jami-client-android/+/30260
https://review.jami.net/c/jami-client-qt/+/29902

GitLab: #1955

Change-Id: Ib6a3c9770693cdae0f5d6a6a0ccee624febeabe3
2025-06-17 19:34:51 -04:00
1dd745d446 packaging: remove EOL distributions
GitLab: #2064
Change-Id: I566936c16512e7cc3db085a362fbd30f32bb693f
2025-06-17 13:30:12 -04:00
3dd2d26d86 versioning: add build version to snap packaging
GitLab: #2045
Change-Id: I173342d3b9351644a4bad4f70e033d29f06a6cd8
2025-06-16 16:45:33 -04:00
eb6b6a2b93 versioning: add build version to rpm packaging
GitLab: #2045
Change-Id: I44e1c6862305706bb177b1d8f4b1900f1c0098a5
2025-06-16 16:45:10 -04:00
b15d692a0e spellchecker: fix codec segfault
Fix the segfault happening when a codec is not properly loaded by
only activated spellcheck when a dictionnary has been successfully
loaded, initializing a default codec and adding error handling.

GitLab: #2063

Change-Id: I48339ce6d13120cfbae3c6c7eb6f40e87f16f084
2025-06-13 16:03:38 -04:00
e76bcbd555 versioning: add build version to debian packaging
GitLab: #2045
Change-Id: If0f8e2fef4ed38ae9cd4238bb725158526d24658
2025-06-13 10:21:43 -04:00
b5a979e6b1 versioning: add build version propagation for unix packaging system
The application on linux systems currently has a different build version
built into it than the build version generated on Jenkins which dictates
the filenames for release packages. This commit aims to propagate a
build version defined in the gnu-linux Jenkinsfile down to the
build-package-*.sh scripts.

Changes:
- create build version (timestamp) in Jenkinsfile
- propagate build version to Makefile, then the docker containers that
will execute the build-package-*.sh scripts

GitLab: #2045
Change-Id: Ia7cbb2f707c233741039dc7bfd3e5bd6a96c2270
2025-06-12 13:32:03 -04:00
898444dd3c versioning: add build version as windows build argument
The application currently has a different build version than the one set
in Jenkins. This causes issues in the crash reports on windows where
they contain a different build version than the one defined on Jenkins.
This leads to the names of the build artifacts on dl.jami.net not
matching the crash report's build version.

Changes:
- Add build version as parameter to the build-windows.py script.
- Propagate build version value to the application through the
BUILD_VERSION symbol.
- Deprecate version.h file and VERSION_STRING symbol.

GitLab: #2045
Change-Id: I7986679aaeebf2bcbbd63a781499f5a50e089712
2025-06-12 13:31:59 -04:00
99f246016d cmake : fix output directory for windows builds
The output directory for windows builds currently matches either Release
or Beta. This does not work as Beta is only a build option, not a build
type. Changes :

- Change build output directory to match the cmake build type (Release
or Debug)
- Change Beta output path references to Release

Change-Id: Ib513f177d93e3c9fb529e00aa160443ac2e804b5
2025-06-12 13:31:54 -04:00
e24f3d91e8 spellchecker: fix greek
greek spell correction wasn't working. this is because  modern greek
is in a special encoding : ISO8859-7. The text in Jami is in utf-8.
Therefore this patch detect the encoding and decode/encode informations
in the relevent encoding between the client and the hunspell library.

GitLab: #2062
Change-Id: Ia33f154e3bf4b84f8337f669df81152ddcd25ec6
2025-06-10 10:29:11 -04:00
3a7850b398 theme: add dark mode support in keyboard shortcuts window
GitLab: #1891
Change-Id: I1e0746b00776564cc7ddbe12e4ad5665f037a092
2025-06-10 10:28:22 -04:00
1e1750024b JamiStrings: spellChecker name
Change-Id: Id163c032c7507496254061f2d707debefe7ab1b5
2025-06-06 01:52:10 -04:00
2ba53a2e40 misc: bump daemon
Change-Id: I33da6f7a22d31b8ac5289f53ea7596b7f7925a66
2025-06-05 14:38:22 -04:00
ceec1f95b9 spellcheck: windows and macos
Implement the hunspell spellchecker for Windows and MacOS. It also
changes the base implementation for Linux. The system dictionaries
(if any) are aggregated with those installed from the LibreOffice
repository via Jami's dictionary management interface.

This commit implements a major refactoring of the spellcheck system
to improve UI responsiveness and user experience:

Core Changes:
- Used QAbstractListModel to represent the list of dictionaries
- Added new QML components:
  - DictionaryInstallView.qml
  - ManageDictionariesDialog.qml
  - SpellCheckLanguageComboBox.qml
- Updated property names for clarity
- Fixed a bug in the settings combo box custom component that caused
  out-of-range errors for filtered models

GitLab: #1997
Change-Id: Ibd0879f957f27f4c7c5720762ace553ca84e2bc3
2025-06-03 19:24:16 -04:00
1ac3db4f33 i18n: automatic bump
Change-Id: Iad0d5ca77493f5d1c213249f899152104eefd2e4
2025-06-02 16:47:00 -04:00
93d3d18c7b ci: change apt mirror to http://gpl.savoirfairelinux.net
Change-Id: I88c130e91bb719b7b5479b4d9d5b4b4262ea6bed
2025-05-29 14:35:52 -04:00
d4b7891f48 packaging: fix Qt build on AlmaLinux
Qt 6.6.3 doesn't build on AlmaLinux when using the latest available
version of the clang-devel and llvm-devel packages. Going back to an
earlier version fixes the issue.

GitLab: #2051
Change-Id: Ie78699197a129cc8804d073085e53cae525c9281
2025-05-27 11:20:54 -04:00
d7c294edd0 misc: bump daemon
Change-Id: I5fdc20fdb4db46e82a559798843e8cbddc8cefb4
2025-05-23 15:16:02 -04:00
945cfe176d accessibility: repair broken shortcut
Repair the shortcut for open account list. It was duplicated in 2 views.

GitLab: #2029

Change-Id: I5590c7a36abb6eba290d7944c83fcb13de8269e6
2025-05-23 15:13:57 -04:00
fa3a153896 autoanswer: allow to choose 2nd call behavior (qt)
Add a setting to choose if the user wants 2nd calls to be declined
while already in one auto-answered.

GitLab: #2005
Change-Id: Iccd8c3e128c6d9456861b4a1ccd951de9136b74b
2025-05-23 13:16:31 -04:00
e9106b2bcc packaging: fix build error for snap dockerfile
The Python installation fix in the Dockerfile is obsolete and now causes
the build to fail due to a reference to a directory that no longer
exists.

GitLab: #2019
Change-Id: I5cc9c8c26761e16af41616c02326a8522c00b10d
2025-05-22 13:45:18 -04:00
a967518d45 manageAccountPage: make the buttons visible again
Restore a previous change to set the width of the page to a set amount.

GitLab: #2011
Change-Id: I323844a4c0439de4041503744a12faf3d1e2027c
2025-05-20 10:15:32 -04:00
7ebed53e97 reply to: text spacing
Removed space between "replied to" and "Me"
Changed "Me" to "you"

Gitlab: #1973
Change-Id: Ifcb7b1ff64e0e8c08aeb2e4a89c6e11c36e6a1cd
2025-05-20 08:23:44 -04:00
ca05963c40 packaging: fix linking error on Debian unstable
There is no longer a reason to downgrade GCC now that 14.2.0 is the
default version on Debian unstable, and doing so started causing linking
errors recently due to some system libraries (such as libyaml-cpp.so)
requiring a more recent version of libc than the one used when compiling
with GCC 12.

GitLab: #2018
Change-Id: I19879541c4182886bcd3af5e84f0ba0d237345b6
2025-05-15 17:00:28 -04:00
df98c6c3fd misc: bump daemon
Change-Id: I6a52a9dc5376d3b1fca82047ba1e6c0b0ec97601
2025-05-15 14:58:41 -04:00
05501e33e9 WelcomePage: add possibility to switch languages
Allow switching languages directly when creating an account.

Change-Id: I73bf3e72e4ceb48c95210447335c8191981d3546
2025-05-15 14:41:23 -04:00
91780ae400 packaging: remove obsolete build option
The --enable-gnutls option was added to the bootstrap command on
Debian-based distributions in jami-project commit 46bdda4 in 2017,
because at the time they built GnuTLS without HeartBeat support. This is
no longer true on the more modern versions of Debian and Ubuntu that we
currently support.

GitLab: #1998
Change-Id: I593682e0f8aeb2015a109980840f373b1306670a
2025-05-15 14:28:07 -04:00
4900ca9f1b createAccountPage: update wizard
Add the ability to set a displayname and a profile picture directly
when creating an account.

Change-Id: I346779132111917eec09cabdc281d0f7721e01b0
2025-05-15 11:15:03 -04:00
0f965aae28 control: fix removed packages on debian installer (linuxmint)
The debian installer requires libavcodec60 as a dependency, which is
already included in linuxmint through libavcodec-extra60, creating a
package conflict.
Changes to fix this :
- also accept libavcodec-extra as a dependency as it includes libavcodec

GitLab: #1937
Change-Id: Ia3ab39e6d8bd233414c607ab70fd70af629595b0
2025-05-14 11:30:28 -04:00
f8c29fc4a1 JamiStrings.qml: cleanup
Change-Id: Ic947a31c4c867cf266018373b2624a745c1fc88c
2025-05-13 22:44:50 -04:00
2e1889caf1 Spell checker and tidy-ups
Spellchecking (verb) → Spell checker (noun)
https://en.wikipedia.org/wiki/Spell_checker

Send (to back) → Bring (to front)

Contextual menu: Cut, Copy, Paste

GitLab: #1997
GitLab: #2015

Change-Id: I86bf7e875d5e336c90daed0e89621dbef4aca0b7
2025-05-13 17:00:25 -04:00
8070d1bfc2 i18n: automatic bump
Change-Id: I1bfe0f4d398d10ae8afb0a51dd1fe0553ac00778
2025-05-12 16:42:33 -04:00
4ee1a309a1 cmake: fix hunspell
Consider system hunspell.

Change-Id: I8f78e8c12a7c16937cab83091113b3e474d9f44e
2025-05-12 13:45:20 -04:00
0333016c44 cmake: add missing argument to add_subdirectory
We need the EXCLUDE_FROM_ALL argument to prevent Hunspell's headers from
being installed by Jami's "install" make target.

GitLab: #1997
Change-Id: Ie60c6f4dc8dc8b33fbccb95d667b4b2eafefecb6
2025-05-10 16:12:44 -04:00
32b7525ee3 packaging: add missing submodule
The Hunspell library was added to the project as a git submodule in
commit 2a72da5, but some packaging scripts were not updated accordingly.

GitLab: #1997
Change-Id: I5e6079fc23aeecfba2076067ecf5c4ed1f5a591a
2025-05-09 21:23:13 -04:00
32b941ab96 misc: bump daemon
Change-Id: I6f53893b30c2cff8761f6d0ab4a92b85f7f873fb
2025-05-09 17:00:32 -04:00
e4932abd39 spellcheck: fix default language value
The default value was set to "None" in appsettingsmanager.h but the rest
of the code assumes that the default is "NONE" (see commit 2a72da5).

GitLab: #1997
Change-Id: Ifeac3399b1b48bad0863a1b7da9228df43f73b76
2025-05-09 16:46:22 -04:00
718d1d266d mainapplicationwindow: raise when called
Add a setting to allow the app to be raised to foreground when called.
Some special setups like virtual machines can prevent this behaviour.

GitLab: #2004
Change-Id: I0f6ea442f6abe88109e81933b731f81d10bd6c8f
2025-05-09 16:13:39 -04:00
8d55f352b4 settings: allow devs to modify default settings
Delete the default settings in the settings file so that only user
defined ones are stored locally.

Previously, we stored every value in the settings file. This created a problem where we could not modify a default value as we had no way of knowing if it was user defined or not.

This patch allow us to know that if a value was in the file, it's that it was different from the default.

GitLab: #2000
Change-Id: I7d5154b258c2ca97a1976dc006a70db0d5fe0b31
2025-05-09 15:37:06 -04:00
2a72da564e spellcheck: for linux system dicts
Implement a first version of the spellcheck for linux that use the
systemwide installed dictionaries.

GitLab: #1997

Change-Id: I7158e6c61061e7d0a7fe651069247227bbe399a4
2025-05-09 15:05:19 -04:00
88d0539085 packaging: add Fedora 42
Change-Id: Ia03ae84d8ae435dd4e24fc1d0d64a9c70580e768
2025-05-08 14:16:55 -04:00
4b1c299a1d INSTALL.md: update windows build instructions
Change-Id: Ia6c246539ab5d76cd6a66df484427e94149d8791
2025-05-05 15:35:30 -04:00
479da3ca54 misc: bump daemon
Change-Id: I695d57f8feb393a23a3e36b89e03d1c2bb64b86c
2025-04-30 13:37:04 -04:00
02140a11c4 i18n: automatic bump
Change-Id: I13067c46aa61b9fb46ee7c58c23616afac0ef02f
2025-04-30 13:03:09 -04:00
b5dbe23c17 windowsharing: set the preview to 1 FPS
Set the preview of the windows shared at one FPS and allows to set
custom FPS count to a window.

GitLab: #1242
Change-Id: Ia189500267de18d0809d8d4db781c7015623fa8c
2025-04-29 14:27:59 -04:00
ff5f94b34a settings: update devices list when devices changed
When a new device is connected/disconnected update audio devices list in
the media settings.

This commit also bumps jami-daemon to support DevicesChanged events on
Windows.

Gitlab: #689
Gitlab: #1878
Change-Id: Ibb607939897853794fdbd09eab72f378257d458c
2025-04-24 13:14:28 -04:00
def2e19abe packaging: stop using dpkg-sig
The dpkg-sig tool appears to no longer be maintained and, as far as I
can tell, was never actually used by Debian or Ubuntu to verify the
integrity of packages. Both distributions no longer include the dpkg-sig
package in their newest releases [1, 2].

[1] https://tracker.debian.org/pkg/dpkg-sig
[2] https://manpages.ubuntu.com/manpages/jammy/en/man1/dpkg-sig.1.html

Change-Id: I356ff7eafb340a49622cc37899dad7ef84dbd100
2025-04-24 11:35:52 -04:00
69430c4af3 packaging: fix Qt build on Debian testing
Change-Id: I798cdcf297ac3c0b448b4f61e192edd177e7fcbf
2025-04-24 10:13:21 -04:00
911fdbc9e5 frameless: fix participant overlay actions
Fixed click actions on the overlay for group calls.

Gitlab: #1990
Change-Id: I2331c6f8b34f0b2c2a89ecb52bb65c3563d50f17
2025-04-23 14:54:05 -04:00
80b3336f1b misc: bump daemon
Change-Id: I86ab9faec20b702091136063e5e86d70f89c81f7
2025-04-22 13:43:48 -04:00
f8bafd4154 packaging: remove Fedora 37 and 38 (EOL)
Change-Id: I8d25303236781cad8f97b2f6f35ee159d814cdb6
2025-04-22 13:39:48 -04:00
b8b06ccfa1 packaging: remove openSUSE Leap 15.4 (EOL)
Change-Id: I7d4dac8a9a8463e402b4eaff501bbab4fb368661
2025-04-21 10:30:45 -04:00
6cb5a8206a packaging: add openSUSE Leap 15.6
Change-Id: Iacd096705f8e88bc886715d04a378e66c4042ede
2025-04-21 10:30:37 -04:00
ae1a2462e2 packaging: add Ubuntu 25.04
Change-Id: I19a0d3e5de48a4e85822d5fcd00f83af0da16e1a
2025-04-18 11:16:41 -04:00
31581db7f5 misc: bump daemon
Brings in some build fixes. Also prevents applying the qmsetup patch
on Windows, and calls build-windows.py --init with the qt parameter
which is required if when using Qt installed in a non-standard location.

Change-Id: I40facbdc93289792130a15b0f4151f78137bc1ef
2025-04-16 17:16:47 -04:00
c323dcfe13 bump daemon
Change-Id: I30104807a42b70d9e3d4dbbc9baff3ffea9ec923
2025-04-16 13:31:00 -04:00
8a31aca346 JamiStrings.qml: cleanup
other → {source, new}

Change-Id: I60f4b81a8fc2a47395f73768caed383e0a597b64
2025-04-13 03:29:00 -04:00
7eeabbe1c6 i18n: automatic bump
Change-Id: I50397f9858be1db3447afce3ceac6eb8086f8fbc
2025-04-11 16:25:03 -04:00
8c0ecaf3c5 bump daemon
Change-Id: I6d010bcec7e2ae2507349b5982f7c20a80af0bea
2025-04-11 15:48:15 -04:00
c91bff35b6 QWK: fix build issue on Debian/Ubuntu
This commit adds a patch for QWindowKit to ensure that it always
installs its dependency QMSetup in a directory where CMake will be able
to find it. This makes the previous QWindowKit patch unnecessary and
fixes a build issue when packaging Jami on Debian and Ubuntu that
started occurring when QWindowKit was updated in commit 6b70ffc.

GitLab: #1976
Change-Id: I5f23fcbb612aa6d0eb0e77e9a5a006b24a5af082
2025-04-03 09:29:45 -04:00
cb05b4afd0 i18n: automatic bump
Change-Id: Ic2efc297abc2410f951f2bdd185d5327e35829df
2025-03-31 16:42:43 -04:00
4419f7bfbc PopUp: Title margins
Added right margins to PopUp titles.

GitLab: #1968
Change-Id: I5a3ce3eb1abc6e7737acea8cb2ef6271df515f16
2025-03-31 13:34:39 -04:00
deaa15a36e misc: remove deprecated operator
The ""_qs operator (used to create QString literals) was deprecated in
version 6.8 of Qt:
https://doc.qt.io/qt-6/qstring-obsolete.html#operator-22-22_qs

GitLab: #1944
Change-Id: I4fc69f3aae6b1e2096735c3714e899ee3c8203bc
2025-03-30 21:55:29 -04:00
6b70ffcf3e QWK: fix build issue with version 6.8 of Qt
This commit updates QWindowKit in order to fix the following build issue
on Qt 6.8: https://github.com/stdware/qwindowkit/pull/154

GitLab: #1944
Change-Id: Iab82514b51577148ff5dc1ba382f8bb517c94f8a
2025-03-30 21:54:32 -04:00
a407fa2c47 fullscreen: reimplement fullscreen for reliability
Reimplement the fullscreen behavior to only work during calls
and to make it more consistent.

Change-Id: I8fbad30dfcf577f5af7d809073e20105374deb35
2025-03-28 09:32:43 -04:00
3143d60760 ConversationModel: use index in slotCallEnded
Change-Id: I2d2952007ce1c437bac9c96d35c2931816f185ac
2025-03-26 10:31:50 -04:00
73eacd5125 src/app/linkdevicemodel.cpp: cleanup
New device identifier is not recognized.\nPlease follow above instruction. → Unrecognized new device identifier. Please follow the instructions above.

Change-Id: I75a1f89d738629eff031bdd3258435d7b72a4fce
2025-03-25 18:12:38 -04:00
fc70ddc6dc src/app/currentconversation.cpp: cleanup
Change-Id: I9514660fc4a5b39232fb4b293b5f7957338185f4
2025-03-25 17:05:41 -04:00
e2e5a0c8cc RTL: RecordBox buttons
Adapted radius for RTL.

GitLab: #1967
Change-Id: Ic14b089f12d4a50227036b800353654a54584cc1
2025-03-25 11:28:14 -04:00
dd9ed8d57d i18n: automatic bump
Change-Id: If32bee03cbac617649bbded29bf732f907aed5d3
2025-03-24 16:42:45 -04:00
7eea1484c5 misc: bump daemon
Change-Id: I789d0ed1a76ebe3364e6fddae69393164d80b72d
2025-03-21 15:27:24 -04:00
6fac40340b messageparser: fix link recognition
The attempted fix in commit 65d3bef was based on the incorrect
assumption that md4c systematically fails to detect links that contain
at least one +, - or _. This commit removes the postprocessing step
added in 65d3bef and instead patches md4c to directly fix its link
recognition algorithm.

GitLab: #1903
GitLab: #1964
Change-Id: Ic1d6302e3250390af66611a16715a6397578abb5
2025-03-21 15:10:15 -04:00
04a1544d56 calls: fix call-action button sub-menu positioning
The submenus are no longer created dynamically, so bindings are
required for positioning.

Gitlab: #1965
Change-Id: Idc2fe77f00ff9b2124f0bad4cc1a8160cd01bf04
2025-03-21 15:07:45 -04:00
91fd8a0295 screen-share: fix the screen/window selection widget
The bug is caused by the computation of `elementWidth` when the list
model length is zero and `showWindows` is true. In this case, division
by zero causes the `elementWidth` to have the value `Infinity`. We
presume that at this point, the component's rendering may take a
while.

This commit refactors the layout to use a GridLayout and a more stable
approach to displaying the delegate components, while removing a
potentially harmful Qt bug [1] workaround.

[1]: https://bugreports.qt.io/browse/QTBUG-110323

Gitlab: #1242
Change-Id: Ib3df1568fdbcdd799fcdcf0b39cb87e3de50dc42
2025-03-21 15:07:45 -04:00
bad5698e71 RTL: JamiIdentifier layout fix
Adapted radius for RTL.

GitLab: #1953
Change-Id: I732cd33b403fea1f115527db19faffe131b259eb
2025-03-21 14:30:40 -04:00
7f0a94dd48 RTL: AboutPopUp fix
Fixed the alignment problem with RTL languages on the About Jami PopUp.

GitLab: #1952
Change-Id: I8262cb658ac3099a113e04574df3e93bd7993f0b
2025-03-21 13:58:56 -04:00
81112ff1f8 RTL: Popup layout fix
Reorganized layout margins for BaseModelDialog and adapted affected components.

GitLab: #1946
Change-Id: I36d0a99fb81fd645cdcdd33a3d10ccea6d4c0424
2025-03-21 13:23:16 -04:00
b63eb384b6 i18n: automatic bump
Change-Id: Ib0106a894896c24d466fd00c1025f1a7072823ff
2025-03-21 13:05:22 -04:00
ebcc60c570 RTL: display Azerbaijani as a RTL language
Azerbaijani is now recognised as an RTL language.

GitLab: #1957
Change-Id: Id1a4f947bf5d0371f558ad5fa507e375c4a2be32
2025-03-21 12:03:28 -04:00
c12a753979 misc: update background image
Homogenizes the image sizes and effect parameters.

Change-Id: Icd8b3968aec7311de5700664f03358c289622a40
2025-03-19 16:11:35 -04:00
386b578e47 UX: fix behavior with lists scrolling offscreen
Fixes behavior introduced in Qt where flickables (list) can scroll
infinitely off screen. Temporary fix to have more polished feel to
the app. Functionality to have a soft overscroll is supposedly fixed
in Qt 6.7 onward.

Change-Id: I031c590e1a351a0fe0d0ea1ea9ed17c24c5c572b
2025-03-19 14:49:25 -04:00
76417edfa4 build: update macOS dependencies
- Enable building natpmp
- Disable building freetype

Change-Id: Iba6c311dff4fb175efbe16cc1f82e51355f5d25e
2025-03-17 12:31:05 -05:00
960fdc0f05 misc: bump daemon
Change-Id: Ic85d1b225778c4e038091e8c1aa04f5706d59543
2025-03-14 17:12:19 -04:00
2567d81359 misc: update release name to Εἰρήνη
Change-Id: Id3d532358c3f5f8b4b17ce85efd0492e51e6877d
2025-03-14 16:49:08 -04:00
e700d8160a downloadprogressbar: fix the implementation
Implement a timer to refresh the download progress bar periodically.

GitLab: #1809
Change-Id: I0c9e142ce5d30c443c4fc6998de3387ec751b1d7
2025-03-14 16:40:26 -04:00
37065cb7d6 theme: reload cached image on theme change
Change-Id: Idf683c3c68c22889fb3e605112167930f2729cd8
2025-03-14 16:23:01 -04:00
03efee4c14 theme: update welcome page background
Change-Id: Ie534479b1af33b4a2d089425c26157a31dc8a5d8
2025-03-14 16:23:01 -04:00
04e43b07f4 RTL: fix GeneralMenuItem text position
Added anchors to improve design for RTL languages

Gitlab: #1949
Change-Id: I2f867a0cda6a9e70ddbb2960a8f466f5ee322421
2025-03-14 15:32:12 -04:00
a00a191371 RTLlanguages: Fix crash when opening settings
Delete the preferedWidth of a row in the accountComboBox to avoid an
infinite polish() loop when accessing the settings with an RTL language.

GitLab: #1945

Change-Id: I37a4a1c61a296743835d677ab242c0fe214e8d16
2025-03-14 14:07:05 -04:00
65d3befad8 messages display: fix the display of links
The links are now postprocessed to compensate for the malfunctions of
md4c. It now displays properly even with a + or - in it. It's also
checked by the unittests.

GitLab: #1903
Change-Id: I0d7f520a7a3fe06fb89107fe6b08f83325218cd4
2025-03-14 11:21:19 -04:00
84ac5dba02 main: fix desktop file name
Commit 49d83fd937 changed the name of
Jami's .desktop file, but didn't make the corresponding change to the
argument passed to setDesktopFileName in the main() function. This
causes a bug where GNOME (and possibly other desktop environments)
doesn't display the correct icon in the taskbar when Jami is running.

GitLab: #1948
Change-Id: I695057979b180777011a9995d799d38f9a4a0487
2025-03-13 16:23:41 -04:00
a149a575a7 cmake: add missing argument to add_subdirectory
We need the EXCLUDE_FROM_ALL argument when adding git submodules via
add_subdirectory in the CMakeLists file. Without it, the "install" make
target for Jami will also install the submodule's files.

GitLab: #1947
Change-Id: I477c4733951ac5a9fa2b6a52a1463c4a585ab8b7
2025-03-13 16:20:29 -04:00
407561732f packaging: add missing submodule
The ZXing-C++ library was recently added to the project as a git
submodule, but some of the packaging scripts were not updated
accordingly.

GitLab: #1947
Change-Id: Ic5324bd807e30bec44c0e07076b1f38903e12895
2025-03-12 15:38:07 -04:00
82c2a9d9c6 link device: correct tooltip for the close button
Change-Id: Ia0057b83b0484c656c33835dd4233e1c5b8fb9ee
2025-03-11 13:17:18 -04:00
1414e1804f link device: fix manual token entry
This patch fixes the export process when a token
is entered manually.

Gitlab: #1695
Change-Id: Ib87a933baa42319bcd17acf10402aafdccf23d1a
2025-03-11 11:09:36 -04:00
7146f20b18 UI/UX: fix link device issues
- Make token copyable
- Fix UI in dark mode
- Remove text animation for export side

Gitlab: #1695
Change-Id: Idb701867ba4998bb75715e598ddac66a5e1ac8ca
2025-03-11 11:09:36 -04:00
5ee4990534 tests: fix arguments for createNewAccount
Change-Id: Ied19a578f1dbe80d468fcf4c5220f2c340cadcab
2025-03-11 10:41:22 -04:00
0d1bdfdfdd link device: fix ui for dark mode
Change-Id: I2d978db411036dab5af45cfc44a7e404d97a177f
2025-03-10 14:52:15 -04:00
f3dd3b4643 chatview: settings: details: fix alignment issue
Fix the alignment of the avatars and text in the details panel

GitLab: #1796
Change-Id: I982ba3982b8128c6e43478146fa80dbfaa8f38cc
2025-03-07 20:53:18 -05:00
d3c76eac8d account: implement export-from-device using new API
- Implements new APIs
- Implements export-from-device mechanism
(link device in account settings)

Gitlab: #1695
Change-Id: I3d3486380e695ea44c199dbe0a0448f724b4d2db
2025-03-07 15:54:21 -05:00
33da15daba account: implement import-from-device using new API
- Implements new APIs
- Implements import-from-device mechanism (creation wizard)
- Minor refactoring of accountmodel and accountadapter

Gitlab: #1695
Change-Id: Ib3c6301b82b19a25320dd703f2f7e941f8048a8e
2025-03-07 15:54:15 -05:00
82c876c0fa message_search: remake component
GitLab: #1827
Change-Id: I877d8a6d15e56c6a8a40ffaa5768ba2812c86d39
2025-03-07 11:08:09 -05:00
83765dcebf view-coordinator: use the view name to destroy dialogs
In the case of a unique view, we need to use the view name used in
the viewmanager to destroy the dialog. This is now provided by the
viewName parameter of the callback used when creating the dialog.

Gitlab: #1938
Change-Id: I3645fc1c7fda44eea9fde8d9d5886647820685ea
2025-03-06 17:14:49 -05:00
b76570b892 conversation model: avoid using database for jami accounts
GitLab: #1794
Change-Id: I48e5e7c42854440f3ee389a7256b8b99a0520eb2
2025-03-06 17:14:37 -05:00
ffb9bb8748 misc: bump daemon
Change-Id: I60872d3444d91c33ce48e477f708fc1f26cc6f13
2025-03-06 10:33:53 -05:00
416137d6dd JamiStrings.qml: merge "clearConversation" with "deleteConversation"
https://review.jami.net/c/jami-client-ios/+/29862

Change-Id: I4a657f73a9240b335cfe04e88f0465abf9a73081
2025-03-05 18:00:31 -05:00
ffcfaffc90 Conversation: add "You left the conversation." string
Follow up to https://review.jami.net/c/jami-client-qt/+/30295

GitLab: #1932

Change-Id: Ic6e78bd3384c9b825a7fd3bc82409d3e6df2b721
2025-03-05 00:06:41 -05:00
a950a3f9e7 appversionmanager: improve version logging
Gitlab: #1934
Change-Id: Ic73b39bb3b6e9c14cbe4b4e0773d744da68f5c72
2025-03-04 15:02:32 -05:00
3c279b292d SimpleMessageDialog.qml: use var for buttonRoles
In practice, the QML engine fails to set arrays of non-variant types
when creating QML components dynamically.

Gitlab: #1934
Change-Id: I5e9c0e73dd35c088bdaf070e04cf73c009ea9099
2025-03-04 15:01:57 -05:00
c19af7f97f networkmanager: prevent generic network error when canceling download
To avoid multiple popups when canceling download, we avoid emitting the
`CANCELLED` signal directly, and rely on the QNetworkReply error handler
to emit the `CANCELLED` signal after translating the error triggered by
aborting the download.

Gitlab: #1934
Change-Id: I87bc1404405a9140b52c2c43d2aeb3501e06aec7
2025-03-04 15:01:09 -05:00
0087f1b8a8 UpdateDownloadDialog.qml: set autoClose to false
The `autoClose` property was set to the default value of `true`.
This causes an issue where if a user refocuses the Jami window, the
update dialog closes and cancels the update.

Gitlab: #1934
Change-Id: Ia7a90875702a0998de71133ed2215fb0583e161e
2025-03-04 14:06:10 -05:00
19f7f43912 crashreportclient: add build variant metadata
This will make it easier to reproduce the build that crashed.

Note: we should be able to use the build ID (build timestamp), but the
git tag is not the same as the build ID currently. This is a problem and
should be fixed in the future.

Gitlab: #1454
Change-Id: I8c6e25a685421398eef3052a9f48681ac369926c
2025-03-04 12:53:32 -05:00
c818eeedce MainApplicationWindow.qml: remove unused import of QtQuick.Dialogs
The module is not used anywhere in the file and breaks the client
on Windows.

GitLab: #1905
Change-Id: I7e4f6e3516a3fd88c7e150b3eeb70cab823d388b
2025-03-04 12:50:03 -05:00
0f08dbcf59 misc: bump daemon
Change-Id: I8743f9c6b0fcbd7cf187d78018420f2b94e5eb01
2025-03-04 11:41:11 -05:00
7d3331d235 i18n: automatic bump
Change-Id: Icf3c5ad4bf2757b2f16368d62f4a0bd837c4f602
2025-03-03 16:42:42 -05:00
aa375a7f89 FileDialog: make a single instance filedialog
Modify the presentDialog method to account for single instance windows and implement a "hack" around the modality issues of Qt.

GitLab: #1905
Change-Id: I166bfc028939240955f20ec9b5777d6f282ccf78
2025-03-03 15:35:36 -05:00
9b51f26e80 i18n: automatic bump
Change-Id: Ia7d8a7341370c77df4ddfb30cea75d8fe3c72e69
2025-03-03 13:58:25 -05:00
6b0adb7005 notifications: no longer blank notifications when leaving or joining a group
Fixed the issue of blank notification when leaving a group by updating the
OnNewUnreadNotification function.

GitLab: #1921

Change-Id: I87f4c3828a72c9b504a9a68707d6b257ce00154c
2025-03-03 09:19:16 -05:00
217efe603b calls: fix the display of incoming calls
When called, it shows "Incoming ... call from username" instead of
"incoming ....call from %1". This adress an issue created in the commit
30419 :https://review.jami.net/c/jami-client-qt/+/30419

GitLab: #1929
Change-Id: I4695a9aebf1787eebef148c234cf6b8eaa2d7ac0
2025-02-28 15:59:16 -05:00
00febee4c7 UserProfile: add ID copy functionnality
Allow to copy UID from the user profile menu.
Make the alias always visible and assure we cannot copy it by mistake.
Allow to copy the username from the chatViewHeader.

Change-Id: I8ff257850286e8a1142c5bd2fbb26e29e8fe5060
2025-02-27 16:10:01 -05:00
c88797163c misc: bump libjami version
Brings in fixes for broken account profiles on Windows.

Gitlab: #1899
Change-Id: I2ff2123a20b76b385413cd5d5fffd0120526a7c1
2025-02-27 14:41:02 -05:00
f7a771f7e1 JamiStrings.qml: unify
Change-Id: I6aea8d17415e362427a36f9092d7d40cefc3f99c
2025-02-27 14:07:33 -05:00
03756aedd0 MessageBar: show less is only visible when the context menu is open
Changed the property of ToolTipMoreButton on the messageBar to ensure that the show less
text display properly only when the context menu is open and not while holding click.

Gitlab: #1904
Change-Id: I4f74802d42e58c38abb3b64dc4277f5c1b79a5f6
2025-02-26 18:02:08 -05:00
8af5a25607 i18n: automatic bump
Change-Id: I1eaab0a31e05e9fedc1ba03f792f9ab5b479ffa2
2025-02-26 11:26:51 -05:00
fe4c63b775 contrib: Windows: bump openssl to 3.4.0
https: //git.jami.net/savoirfairelinux/jami-daemon/-/issues/1108
Change-Id: I689f2e4ac3fef152bcafd89e125f97b948627b8f
2025-02-26 11:26:36 -05:00
4ee1f1a5d3 documentation: update the build instructions for windows
Update install.md to add relevent init command to the windows
compilation steps.

Change-Id: I59be668fbba1f81db7ecfbf80d4ddd2f615eaf57
2025-02-26 09:29:00 -05:00
37f29c9882 videoprovider: fix possible use-after-free on Windows
This creates a deep copy QImage of the video frame during the call to
captureRawVideoFrame.

Gitlab: #1916
Change-Id: Ifa3ba8950ddd1fb13892665d011733fd45c88d12
2025-02-24 11:20:47 -05:00
1bfacdbb76 JamiStrings: cleanup of the usages of old variables
Add variables to strings to make complete sentences.

Change-Id: I669366ef6de92c3a7e49f677e88c10c59da0f92f
2025-02-21 13:32:29 -05:00
c5e455a9de JamiStrings.qml: cleanup
Join Jami → Create Jami account
not available → unavailable
would you → do you want to

https://review.jami.net/c/jami-client-ios/+/30358

Change-Id: I74535b7f502b34e5faa04bba2c6998ec4053c7ba
2025-02-20 16:15:13 -05:00
f489f21271 profile: vcard: fix add deletion logic check
If you are deleting a conversation with yourself, you
should not delete your own vCard. This will cause your profile
picture to be removed, among other things.

GitLab: #1838
Change-Id: I2e6ec3e941e6fdef1bf9df24238e720a73aba6dd
2025-02-20 13:58:18 -05:00
560f44f6f1 src/app/utils.cpp: cleanup
Remove consecutive whitespaces in string.

https://app.transifex.com/savoirfairelinux/search/?q=source_language%3Aen+target_language%3Ahu+source_text%3A%27%5BThis+is+a+list+of+people+who+have+made+a+significant+investment+of+time%2C++++++++with+useful+results%2C+into+Jami.+Any+such+contributors+who+want+to+be+added+to+the+list+++++++++should+contact+us.%5D%27

Change-Id: Id7ef7dac3a8dfafa50c69dc3182b8654b1695b72
2025-02-18 13:35:38 -05:00
d0639b4e88 src/libclient/api/interaction.h: cleanup
Change-Id: I5f3509ee76db39aa054f0ad8d06c3a3e49ca4c06
2025-02-17 18:22:22 -05:00
341 changed files with 165089 additions and 141093 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ doc/Doxyfile
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
### VisualStudioCode Patch ###
# Ignore all local history of files

10
.gitmodules vendored
View File

@ -21,9 +21,17 @@
ignore = dirty
[submodule "3rdparty/md4c"]
path = 3rdparty/md4c
url = https://github.com/mity/md4c.git
url = https://github.com/fsimonfc/md4c.git
ignore = dirty
[submodule "3rdparty/tidy-html5"]
path = 3rdparty/tidy-html5
url = https://github.com/htacg/tidy-html5.git
ignore = dirty
[submodule "3rdparty/zxing-cpp"]
path = 3rdparty/zxing-cpp
url = https://github.com/nu-book/zxing-cpp.git
ignore = dirty
[submodule "3rdparty/hunspell"]
path = 3rdparty/hunspell
url = https://gitlab.savoirfairelinux.com/jami/hunspell.git
ignore = dirty

1
3rdparty/hunspell vendored Submodule

Submodule 3rdparty/hunspell added at 749cd84a0b

2
3rdparty/md4c vendored

1
3rdparty/zxing-cpp vendored Submodule

Submodule 3rdparty/zxing-cpp added at a920817b6f

View File

@ -76,6 +76,7 @@ list(APPEND QWINDOWKIT_OPTIONS
QWINDOWKIT_BUILD_WIDGETS OFF
QWINDOWKIT_INSTALL OFF
QWINDOWKIT_BUILD_STATIC ON
QWINDOWKIT_BUILD_QUICK ON
)
if(WIN32)
@ -83,29 +84,27 @@ if(WIN32)
if(BETA)
message(STATUS "Beta config enabled")
add_definitions(-DBETA)
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Beta)
else()
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/Release)
endif()
set(JAMI_OUTPUT_DIRECTORY_RELEASE ${PROJECT_SOURCE_DIR}/x64/${CMAKE_BUILD_TYPE})
endif()
if(WIN32)
list(APPEND QWINDOWKIT_OPTIONS QWINDOWKIT_ENABLE_WINDOWS_SYSTEM_BORDERS OFF)
endif()
# qmsetup uses the wrong package dir on some distributions
# (including Fedora and openSUSE Leap at least)
check_distro_needs_qmsetup_patch(DISTRO_NEEDS_QMSETUP_PATCH)
if(DISTRO_NEEDS_QMSETUP_PATCH)
list(APPEND QWINDOWKIT_PATCHES ${EXTRA_PATCHES_DIR}/0001-fix-fedora-fc-build.patch)
set(qmsetup_cmake_path ${CMAKE_BINARY_DIR}/_install/lib64/cmake/qmsetup)
# If qwindowkit can't find qmsetup via cmake's find_package function, it will install it and
# then call find_package again. Unfortunately, even the second call to find_package sometimes
# fails due to qmsetup having been installed in the wrong directory. The following patch
# ensures that qmsetup is always installed in the directory where find_package looks for it.
if(NOT WIN32)
list(APPEND QWINDOWKIT_PATCHES ${EXTRA_PATCHES_DIR}/0001-fix-qm_install_package-function.patch)
endif()
# qwindowkit (frameless window)
add_fetch_content(
TARGET qwindowkit
URL https://github.com/stdware/qwindowkit.git
BRANCH 79b1f3110754f9c21af2d7dacbd07b1a9dbaf6ef
BRANCH 758b00cb6c2d924be3a1ea137ec366dc33a5132d
PATCHES ${QWINDOWKIT_PATCHES}
OPTIONS ${QWINDOWKIT_OPTIONS}
)
@ -245,7 +244,7 @@ set(CMAKE_MODULE_PATH
${CMAKE_MODULE_PATH} "${EXTRAS_DIR}/build/cmake/modules")
find_package(LibJami REQUIRED)
if(LIBJAMI_FOUND)
include_directories(${LIBJAMI_INCLUDE_DIRS})
include_directories(${LIBJAMI_INCLUDE_DIR})
endif()
include(FindPython3)
@ -254,7 +253,7 @@ set(PYTHON_EXEC ${Python3_EXECUTABLE})
# Versioning and build ID generation
set(VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/version_info.cpp)
# Touch the file to make sure it exists at configure time as
# Touch the file to ensure it exists at configure time as
# we add it to the target_sources below.
file(TOUCH ${VERSION_FILE})
add_custom_target(
@ -265,6 +264,7 @@ add_custom_target(
-DAPP_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
-DCORE_SOURCE_DIR=${DAEMON_DIR}
-DCPP_INT_FILE=${VERSION_INFO_DIR}/version_info.cpp.in
-DBUILD_VERSION=${BUILD_VERSION}
-P ${CMAKE_SCRIPTS_DIR}/generate_version_info.cmake
)
list(APPEND CLIENT_INCLUDE_DIRS ${VERSION_INFO_DIR})
@ -346,6 +346,8 @@ set(COMMON_SOURCES
${APP_SRC_DIR}/conversationlistmodel.cpp
${APP_SRC_DIR}/searchresultslistmodel.cpp
${APP_SRC_DIR}/calloverlaymodel.cpp
${APP_SRC_DIR}/spellcheckdictionarylistmodel.cpp
${APP_SRC_DIR}/spellcheckadapter.cpp
${APP_SRC_DIR}/filestosendlistmodel.cpp
${APP_SRC_DIR}/wizardviewstepmodel.cpp
${APP_SRC_DIR}/avatarregistry.cpp
@ -360,11 +362,13 @@ set(COMMON_SOURCES
${APP_SRC_DIR}/currentcall.cpp
${APP_SRC_DIR}/messageparser.cpp
${APP_SRC_DIR}/previewengine.cpp
${APP_SRC_DIR}/imagedownloader.cpp
${APP_SRC_DIR}/filedownloader.cpp
${APP_SRC_DIR}/pluginversionmanager.cpp
${APP_SRC_DIR}/connectioninfolistmodel.cpp
${APP_SRC_DIR}/pluginversionmanager.cpp
)
${APP_SRC_DIR}/linkdevicemodel.cpp
${APP_SRC_DIR}/qrcodescannermodel.cpp
${APP_SRC_DIR}/spellchecker.cpp)
set(COMMON_HEADERS
${APP_SRC_DIR}/global.h
@ -374,7 +378,6 @@ set(COMMON_HEADERS
${APP_SRC_DIR}/appversionmanager.h
${APP_SRC_DIR}/utils.h
${APP_SRC_DIR}/bannedlistmodel.h
${APP_SRC_DIR}/version.h
${APP_SRC_DIR}/accountlistmodel.h
${APP_SRC_DIR}/instancemanager.h
${APP_SRC_DIR}/connectivitymonitor.h
@ -416,6 +419,8 @@ set(COMMON_HEADERS
${APP_SRC_DIR}/conversationlistmodel.h
${APP_SRC_DIR}/searchresultslistmodel.h
${APP_SRC_DIR}/calloverlaymodel.h
${APP_SRC_DIR}/spellcheckdictionarylistmodel.h
${APP_SRC_DIR}/spellcheckadapter.h
${APP_SRC_DIR}/filestosendlistmodel.h
${APP_SRC_DIR}/wizardviewstepmodel.h
${APP_SRC_DIR}/avatarregistry.h
@ -430,13 +435,15 @@ set(COMMON_HEADERS
${APP_SRC_DIR}/currentcall.h
${APP_SRC_DIR}/messageparser.h
${APP_SRC_DIR}/htmlparser.h
${APP_SRC_DIR}/imagedownloader.h
${APP_SRC_DIR}/filedownloader.h
${APP_SRC_DIR}/pluginversionmanager.h
${APP_SRC_DIR}/connectioninfolistmodel.h
${APP_SRC_DIR}/pttlistener.h
${APP_SRC_DIR}/crashreportclient.h
${APP_SRC_DIR}/crashreporter.h
)
${APP_SRC_DIR}/linkdevicemodel.h
${APP_SRC_DIR}/qrcodescannermodel.h
${APP_SRC_DIR}/spellchecker.h)
# For libavutil/avframe.
set(LIBJAMI_CONTRIB_DIR "${DAEMON_DIR}/contrib")
@ -464,6 +471,25 @@ if(ENABLE_CRASHREPORTS)
endif()
endif()
find_package(PkgConfig REQUIRED)
# hunspell
pkg_search_module(hunspell IMPORTED_TARGET hunspell)
if(hunspell_FOUND)
message(STATUS "hunspell found")
set(HUNSPELL_LIBRARIES PkgConfig::hunspell)
else()
message(STATUS "hunspell not found - building hunspell")
set(HUNSPELL_DIR ${PROJECT_SOURCE_DIR}/3rdparty/hunspell)
# Build using the submodule and its CMakeLists.txt
add_subdirectory(${HUNSPELL_DIR} hunspell_build EXCLUDE_FROM_ALL)
set(HUNSPELL_INCLUDE_DIR ${HUNSPELL_DIR}/src)
set(HUNSPELL_LIBRARIES hunspell::hunspell)
endif()
if(MSVC)
set(WINDOWS_SYS_LIBS
windowsapp.lib
@ -526,8 +552,6 @@ elseif (NOT APPLE)
${APP_SRC_DIR}/screencastportal.h)
list(APPEND QT_MODULES DBus)
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLIB REQUIRED glib-2.0)
if(GLIB_FOUND)
add_definitions(${GLIB_CFLAGS_OTHER})
@ -610,6 +634,13 @@ else() # APPLE
endif()
endif()
message(STATUS "Adding HUNSPELL_INCLUDE_DIR" ${HUNSPELL_INCLUDE_DIR})
list(APPEND CLIENT_INCLUDE_DIRS ${HUNSPELL_INCLUDE_DIR} ${CMAKE_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/hunspell/src)
message(STATUS "Adding HUNSPELL_LIBRARIES" ${HUNSPELL_INCLUDE_DIR})
list(APPEND CLIENT_LIBS ${HUNSPELL_LIBRARIES})
# Qt find package
if(QT6_VER AND QT6_PATH)
message(STATUS "Using custom Qt version")
@ -663,20 +694,43 @@ add_subdirectory(3rdparty/SortFilterProxyModel)
set(SFPM_OBJECTS $<TARGET_OBJECTS:SortFilterProxyModel>)
# md4c
set(BUILD_MD2HTML_EXECUTABLE OFF CACHE BOOL "Don't build md2html executable" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Don't build shared md4c library" FORCE)
add_subdirectory(3rdparty/md4c EXCLUDE_FROM_ALL)
list(APPEND CLIENT_LINK_DIRS ${MD4C_BINARY_DIR}/src)
list(APPEND CLIENT_INCLUDE_DIRS ${MD4C_SOURCE_DIR}/src)
list(APPEND CLIENT_LIBS md4c-html)
find_package(md4c)
if(md4c_FOUND)
message(STATUS "Using system-provided md4c-html")
list(APPEND CLIENT_LIBS md4c::md4c-html)
else()
message("Using bundled md4c-html library")
set(BUILD_MD2HTML_EXECUTABLE OFF CACHE BOOL "Don't build md2html executable" FORCE)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Don't build shared md4c library" FORCE)
add_subdirectory(3rdparty/md4c EXCLUDE_FROM_ALL)
list(APPEND CLIENT_LINK_DIRS ${MD4C_BINARY_DIR}/src)
list(APPEND CLIENT_INCLUDE_DIRS ${MD4C_SOURCE_DIR}/src)
list(APPEND CLIENT_LIBS md4c-html)
endif()
# tidy-html5
set(BUILD_SHARED_LIB OFF CACHE BOOL "Don't build shared tidy library" FORCE)
set(SUPPORT_CONSOLE_APP OFF CACHE BOOL "Don't build tidy console app" FORCE)
add_subdirectory(3rdparty/tidy-html5 EXCLUDE_FROM_ALL)
list(APPEND CLIENT_LINK_DIRS ${tidy_BINARY_DIR}/Release)
list(APPEND CLIENT_INCLUDE_DIRS ${tidy_SOURCE_DIR}/include)
list(APPEND CLIENT_LIBS tidy-static)
pkg_check_modules(tidy IMPORTED_TARGET tidy)
if(tidy_FOUND)
message(STATUS "Using system-provided tidy")
list(APPEND CLIENT_LIBS PkgConfig::tidy)
else()
message("Using bundled tidy library")
set(BUILD_SHARED_LIB OFF CACHE BOOL "Don't build shared tidy library" FORCE)
set(SUPPORT_CONSOLE_APP OFF CACHE BOOL "Don't build tidy console app" FORCE)
add_subdirectory(3rdparty/tidy-html5 EXCLUDE_FROM_ALL)
list(APPEND CLIENT_LINK_DIRS ${tidy_BINARY_DIR}/Release)
list(APPEND CLIENT_INCLUDE_DIRS ${tidy_SOURCE_DIR}/include)
list(APPEND CLIENT_LIBS tidy-static)
endif()
# ZXing-cpp configuration
set(BUILD_EXAMPLES OFF CACHE BOOL "")
set(BUILD_BLACKBOX_TESTS OFF CACHE BOOL "")
add_subdirectory(3rdparty/zxing-cpp EXCLUDE_FROM_ALL)
# Add ZXing-cpp to includes and libraries
list(APPEND CLIENT_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/zxing-cpp/core/src)
list(APPEND CLIENT_LIBS ZXing)
# common executable sources
qt_add_executable(
@ -687,9 +741,12 @@ qt_add_executable(
${COMMON_SOURCES}
${QML_RESOURCES}
${QML_RESOURCES_QML}
${SFPM_OBJECTS})
${SFPM_OBJECTS}
src/app/spellcheckadapter.h src/app/spellcheckadapter.cpp)
# Make sure we can find the generated version file
#add_dependencies(${PROJECT_NAME} hunspell)
# Ensure the generated version file can be found.
add_dependencies(${PROJECT_NAME} generate_version_info)
foreach(MODULE ${QT_MODULES})
@ -783,14 +840,19 @@ elseif (NOT APPLE)
PRIVATE
JAMI_INSTALL_PREFIX="${JAMI_DATA_PREFIX}")
target_compile_definitions(
${PROJECT_NAME}
PRIVATE
HUNSPELL_INSTALL_DIR="${HUNSPELL_DICT_DIR}")
# Logos
install(
FILES resources/images/jami.svg
FILES resources/images/net.jami.Jami.svg
DESTINATION
${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/scalable/apps)
install(
FILES resources/images/jami-48px.png
FILES resources/images/net.jami.Jami-48px.png
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps
RENAME jami.png)
@ -968,5 +1030,6 @@ qt_finalize_executable(${PROJECT_NAME})
# tests
if(BUILD_TESTING)
message("Add Jami tests")
enable_testing()
add_subdirectory(${TESTS_DIR})
endif()

View File

@ -189,7 +189,7 @@ Only 64-bit MSVC build can be compiled.
- Download [Qt (Open Source)](https://www.qt.io/download-open-source?hsCtaTracking=9f6a2170-a938-42df-a8e2-a9f0b1d6cdce%7C6cb0de4f-9bb5-4778-ab02-bfb62735f3e5)
- Using the online installer, install the following Qt 6.6.1 components:
- Using the online installer, install the following Qt 6.6.2 components:
- Git 2.10.2
- MSVC 2019 64-bit
@ -237,9 +237,14 @@ Only 64-bit MSVC build can be compiled.
- Using a new **Non-Elevated Command Prompt**
```bash
python build.py --init --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.2/msvc2019_64)
```
```bash
python build.py --install --qt <path-to-qt-bin-folder> (e.g. C:/Qt/6.6.2/msvc2019_64)
```
> **CMake** Note: The build script does not specify what CMake generator should be used. This means CMake will search the system for the appropriate generator, which might not always select the right one if, for instance, Ninja is installed. To resolve that, the CMAKE_GENERATOR environment variable can be used, set to "Visual Studio 16 2019" or "Visual Studio 19 2022" depending on the installed Visual Studio version.
> **SDK** Note:
> Jami can be build with more recent Windows SDK than the one specified in the table above. However, if your have another version than SDK 10.0.18362.0 installed, you need to identify it according to the example below. And you still need to have the required version in addition to the one you chose.

View File

@ -4,10 +4,5 @@
<?define ExeName="Jami" ?>
<?define AppName="Jami" ?>
<?define Manufacturer="Savoir-Faire Linux"?>
<?if $(var.Configuration) = Release ?>
<?define ReleaseDir="..\x64\Release"?>
<?else?>
<?define ReleaseDir="..\x64\Beta"?>
<?endif ?>
</Include>

View File

@ -16,9 +16,9 @@
<InstallerPlatform>x64</InstallerPlatform>
<DefineSolutionProperties>false</DefineSolutionProperties>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<PropertyGroup>
<OutputPath>bin\Release\</OutputPath>
<IntermediateOutputPath>obj\Release\</IntermediateOutputPath>
<DefineConstants>AppHarvestPath=..\x64\Release;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
<SuppressPdbOutput>True</SuppressPdbOutput>
<CompilerAdditionalOptions>
@ -26,16 +26,6 @@
<WixVariables>
</WixVariables>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Beta|x64' ">
<OutputPath>bin\$(Configuration)\</OutputPath>
<IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
<DefineConstants>AppHarvestPath=..\x64\Beta;CrtHarvestPath=$(VC_CRT_Dir)</DefineConstants>
<SuppressPdbOutput>True</SuppressPdbOutput>
<CompilerAdditionalOptions>
</CompilerAdditionalOptions>
<WixVariables>
</WixVariables>
</PropertyGroup>
<ItemGroup>
<Compile Include="Product.wxs" />
<Compile Include="AppComponents.wxs" />
@ -70,7 +60,7 @@
<Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" />
</Target>
<Target Name="BeforeBuild">
<HeatDirectory Directory="..\x64\$(Configuration)"
<HeatDirectory Directory="..\x64\Release"
PreprocessorVariable="var.AppHarvestPath"
OutputFile="AppComponents.wxs"
ComponentGroupName="AppHeatGenerated"

View File

@ -112,7 +112,7 @@ ZYPPER_CLIENT_DEPENDENCIES = [
'qt6-svg-devel', 'qt6-multimedia-devel', 'qt6-multimedia-imports',
'qt6-declarative-devel', 'qt6-qmlcompiler-private-devel',
'qt6-quickcontrols2-devel', 'qt6-shadertools-devel',
'qrencode-devel', 'NetworkManager-devel'
'qrencode-devel', 'NetworkManager-devel', 'hunspell-devel', 'libhunspell-devel'
]
ZYPPER_QT_WEBENGINE = [
@ -139,7 +139,7 @@ DNF_CLIENT_DEPENDENCIES = [
'libnotify-devel',
'qt6-qtbase-devel',
'qt6-qtsvg-devel', 'qt6-qtmultimedia-devel', 'qt6-qtdeclarative-devel',
'qrencode-devel', 'NetworkManager-libnm-devel'
'qrencode-devel', 'NetworkManager-libnm-devel', 'hunspell-devel', 'libhunspell-devel'
]
DNF_QT_WEBENGINE = ['qt6-qtwebengine-devel']
@ -171,7 +171,7 @@ APT_CLIENT_DEPENDENCIES = [
'qml6-module-qtquick-dialogs', 'qml6-module-qtquick-layouts',
'qml6-module-qtquick-shapes', 'qml6-module-qtquick-window',
'qml6-module-qtquick-templates', 'qml6-module-qt-labs-platform',
'libqrencode-dev', 'libnm-dev'
'libqrencode-dev', 'libnm-dev', 'hunspell', 'libhunspell-dev'
]
APT_QT_WEBENGINE = [
@ -194,7 +194,7 @@ PACMAN_CLIENT_DEPENDENCIES = [
'qt6-declarative', 'qt6-5compat', 'qt6-multimedia',
'qt6-networkauth', 'qt6-shadertools',
'qt6-svg', 'qt6-tools',
'qrencode', 'libnm'
'qrencode', 'libnm', 'hunspell'
]
PACMAN_QT_WEBENGINE = ['qt6-webengine']
@ -374,7 +374,7 @@ def run_install(args):
# Prepare the build-windows.py script call
build_windows = 'extras/scripts/build-windows.py'
# Initialize build environment
execute_script([f'python {build_windows} --init'])
execute_script([f'python {build_windows} --init --qt={args.qt}'])
# Construct build command with options
build_cmd = [

2
daemon

Submodule daemon updated: 8f2b6d3f5a...33400db731

View File

@ -17,32 +17,6 @@
include(FetchContent)
include(CMakeParseArguments)
# Helper function to check if we're on a distribution that requires us
# to apply a patch in order for qmsetup to use the right package directory
function(check_distro_needs_qmsetup_patch DISTRO_NEEDS_QMSETUP_PATCH)
set(${DISTRO_NEEDS_QMSETUP_PATCH} FALSE PARENT_SCOPE)
# Check for the existence of /etc/os-release
if(EXISTS "/etc/os-release")
# Read the content of the file
file(READ "/etc/os-release" OS_RELEASE_CONTENT)
# Check if the distribution is Fedora or Red Hat-based
string(REGEX MATCH "ID=fedora|ID_LIKE=\"rhel fedora\"|ID_LIKE=\"rhel centos fedora\"" RED_HAT_BASED "${OS_RELEASE_CONTENT}")
# Check if the distribution is openSUSE Leap
string(REGEX MATCH "ID=\"opensuse-leap\"" OPENSUSE_LEAP "${OS_RELEASE_CONTENT}")
if(RED_HAT_BASED)
set(${DISTRO_NEEDS_QMSETUP_PATCH} TRUE PARENT_SCOPE)
message(STATUS "Running on a Red Hat-based distribution (Fedora, RHEL, CentOS, etc.)")
elseif(OPENSUSE_LEAP)
set(${DISTRO_NEEDS_QMSETUP_PATCH} TRUE PARENT_SCOPE)
message(STATUS "Running on openSUSE Leap")
else()
message(STATUS "Distribution is not openSUSE Leap or Red Hat-based")
endif()
else()
message(STATUS "Cannot determine the distribution type: /etc/os-release not found")
endif()
endfunction()
# Helper function to add external content with patches and options.
# Parameters:
# TARGET: Name of the target to create

View File

@ -24,6 +24,7 @@ set(CMAKE_CURRENT_BINARY_DIR ${APP_BINARY_DIR})
# Generate the version string for the application and core
configure_version_string(${APP_SOURCE_DIR} APP_VERSION_STRING)
configure_version_string(${CORE_SOURCE_DIR} CORE_VERSION_STRING)
set(BUILD_VERSION_STRING ${BUILD_VERSION})
# Get output file names with the .in extension removed
get_filename_component(VERSION_CPP_FILENAME ${CPP_INT_FILE} NAME_WE)

View File

@ -16,30 +16,19 @@
# Once done, this find module will set:
#
# LIBJAMI_INCLUDE_DIRS - libjami include directories
# LIBJAMI_INCLUDE_DIR - libjami include directory
# LIBJAMI_FOUND - whether it was able to find the include directories
# LIBJAMI_LIB - path to libjami or libring library
set(LIBJAMI_FOUND true)
if(WITH_DAEMON_SUBMODULE)
set(LIBJAMI_INCLUDE_DIRS ${DAEMON_DIR}/src/jami)
set(LIBJAMI_INCLUDE_DIR ${DAEMON_DIR}/src/jami)
else()
if(EXISTS ${LIBJAMI_INCLUDE_DIR}/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${LIBJAMI_INCLUDE_DIR})
elseif(EXISTS ${LIBJAMI_BUILD_DIR}/jami/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${LIBJAMI_BUILD_DIR}/jami)
elseif(EXISTS ${RING_INCLUDE_DIR}/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${RING_INCLUDE_DIR})
elseif(EXISTS ${RING_BUILD_DIR}/jami/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${RING_BUILD_DIR}/jami)
elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/include/jami/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/include/jami)
elseif(EXISTS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami/jami.h)
set(LIBJAMI_INCLUDE_DIRS ${CMAKE_INSTALL_PREFIX}/daemon/include/jami)
else()
find_path(LIBJAMI_INCLUDE_DIR jami.h PATH_SUFFIXES jami)
if(NOT LIBJAMI_INCLUDE_DIR)
message(STATUS "Jami daemon headers not found!
Set -DLIBJAMI_BUILD_DIR or -DCMAKE_INSTALL_PREFIX")
To build using the daemon git submodule, set -DWITH_DAEMON_SUBMODULE")
set(LIBJAMI_FOUND false)
endif()
endif()
@ -121,5 +110,5 @@ endif()
# Restore the original value of CMAKE_FIND_LIBRARY_SUFFIXES.
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES_orig})
message(STATUS "Jami daemon headers are in " ${LIBJAMI_INCLUDE_DIRS})
message(STATUS "Jami daemon headers are in " ${LIBJAMI_INCLUDE_DIR})
message(STATUS "Jami daemon library is at " ${LIBJAMI_LIB})

View File

@ -4,11 +4,24 @@ ENV DEBIAN_FRONTEND noninteractive
ENV QT_QUICK_BACKEND software
ENV QT_QPA_PLATFORM offscreen
RUN apt-get clean
RUN apt-get update && \
apt-get install -y devscripts equivs
apt-get install -y --no-install-recommends ca-certificates && \
rm -rf /var/lib/apt/lists/*
# Use only the custom Savoir-faire Linux Ubuntu mirror
RUN rm -f /etc/apt/sources.list /etc/apt/sources.list.d/* && \
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy main restricted universe multiverse" > /etc/apt/sources.list && \
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy-updates main restricted universe multiverse" >> /etc/apt/sources.list && \
echo "deb http://gpl.savoirfairelinux.net/pub/mirrors/ubuntu jammy-security main restricted universe multiverse" >> /etc/apt/sources.list
RUN apt-get update && \
apt-get install -y \
devscripts \
equivs \
gnupg \
dirmngr \
curl
RUN apt install gnupg dirmngr ca-certificates curl --no-install-recommends
RUN curl -s https://dl.jami.net/public-key.gpg | tee /usr/share/keyrings/jami-archive-keyring.gpg > /dev/null
RUN sh -c "echo 'deb [signed-by=/usr/share/keyrings/jami-archive-keyring.gpg] https://dl.jami.net/internal/ubuntu_22.04/ jami main' > /etc/apt/sources.list.d/jami.list"
RUN apt-get update && apt-get install libqt-jami -y
@ -69,7 +82,8 @@ RUN apt-get install -y pandoc \
libcppunit-dev \
googletest \
libgtest-dev \
wget
wget && \
rm -rf /var/lib/apt/lists/*
# Install a recent version of CMake
ADD extras/packaging/gnu-linux/scripts/install-cmake.sh /opt/install-cmake.sh

View File

@ -85,7 +85,7 @@
<id>net.jami.daemon</id>
</requires>
<launchable type="desktop-id">net.jami.Jami.desktop</launchable>
<icon type="stock">jami</icon>
<icon type="stock">net.jami.Jami</icon>
<url type="homepage">https://jami.net/</url>
<url type="bugtracker">https://git.jami.net/savoirfairelinux/jami-client-qt/issues</url>
<url type="faq">https://docs.jami.net/user/faq.html</url>

View File

@ -1,14 +1,83 @@
[Desktop Entry]
Name=Jami
GenericName=Jami
Comment=Privacy-oriented voice, video, chat, and conference platform
Comment[hu]=Adatvédelem-orientált hang-, video-, csevegés- és konferenciaplatform
Comment[ru]=Jami — приложение для защищённой связи с распределённой архитектурой
Comment=Share, freely and privately
Comment[ab]=Ацеиҩшара, хақәиҭла, хала
Comment[af]=Deel, vrylik en privaat
Comment[am]=በነጻ እና በግል ያካፍሉ።
Comment[ar]=شارك بحرية وبشكل خاص
Comment[az]=Sərbəst və gizli şəkildə paylaşın
Comment[be]=Падзяліцеся свабодна і прыватна
Comment[bg]=Споделяйте, свободно и частно
Comment[bn]=শেয়ার করুন, অবাধে এবং গোপনে
Comment[ca]=Comparteix, lliurement i de forma privada
Comment[cs]=Sdílejte svobodně a soukromě
Comment[da]=Del, frit og privat
Comment[de]=Teilen, frei und privat
Comment[el]=Κοινοποιήστε, ελεύθερα και ιδιωτικά
Comment[eo]=Kunhavigu, libere kaj private
Comment[es]=Comparte, libre y privadamente
Comment[et]=Jaga, vabalt ja privaatselt
Comment[fa]=به اشتراک بگذارید، آزادانه و خصوصی
Comment[fi]=Jaa, vapaasti ja yksityisesti
Comment[fil]=Ibahagi, libre at pribado
Comment[fr]=Partagez, librement, gratuitement et en toute confidentialité
Comment[gl]=Comparte, de xeito libre e privado
Comment[he]=שתפו, באופן חופשי ופרטי
Comment[hi]=स्वतंत्र रूप से और निजी तौर पर साझा करें
Comment[hr]=Dijelite, slobodno i privatno
Comment[hu]=Megosztás, szabadon és bizalmasan
Comment[hy]=Տարածեք, ազատ և մասնավոր
Comment[id]=Berbagi, secara bebas dan pribadi
Comment[is]=Deildu, frjálslega og einslega
Comment[it]=Condividere, liberamente e privatamente
Comment[ja]=自由に、プライベートに共有
Comment[ka]=გააზიარეთ, თავისუფლად და პირადად
Comment[km]=ចែករំលែកដោយសេរី និងឯកជន
Comment[kn]=ಮುಕ್ತವಾಗಿ ಮತ್ತು ಖಾಸಗಿಯಾಗಿ ಹಂಚಿಕೊಳ್ಳಿ
Comment[ko]=자유롭고 비공개적으로 공유하세요
Comment[ky]=Бөлүшүү, эркин жана купуя
Comment[la]=Communicantes, libere et privatim
Comment[lo]=ແບ່ງ​ປັນ​, ຢ່າງ​ເສລີ​ແລະ​ເປັນ​ສ່ວນ​ຕົວ​
Comment[lt]=Dalintis, laisvai ir privačiai
Comment[lv]=Kopīgojiet, brīvi un privāti
Comment[mk]=Споделете, слободно и приватно
Comment[ml]=സ്വതന്ത്രമായും സ്വകാര്യമായും പങ്കിടുക
Comment[mn]=Чөлөөт, хувийн байдлаар хуваалцах
Comment[mr]=सामायिक करा, मुक्तपणे आणि खाजगीरित्या
Comment[ms]=Kongsi, secara bebas dan peribadi
Comment[my]=လွတ်လပ်စွာ သီးသန့်မျှဝေပါ။
Comment[ne]=स्वतन्त्र र गोप्य रूपमा सेयर गर्नुहोस्
Comment[nl]=Deel, vrij en privé
Comment[no]=Del, fritt og privat
Comment[pl]=Udostępniaj swobodnie i prywatnie
Comment[pt_BR]=Compartilhe, livre e privadamente
Comment[pt_PT]=Partilhe, livre e privadamente
Comment[ro]=Distribuie, în mod liber și privat
Comment[ru]=Делитесь, свободно и конфиденциально
Comment[si]=නිදහසේ සහ පෞද්ගලිකව බෙදා ගන්න
Comment[sk]=Zdieľajte, slobodne a súkromne
Comment[sl]=Delite brezplačno in zasebno
Comment[sq]=Shpërndaje, lirisht dhe privatisht
Comment[sr]=Делите, слободно и приватно
Comment[sv]=Dela, fritt och privat
Comment[sw]=Shiriki, kwa uhuru na kwa faragha
Comment[ta]=பகிரவும், சுதந்திரமாகவும் தனிப்பட்ட முறையிலும்
Comment[te]=ఉచితంగా మరియు ప్రైవేట్‌గా షేర్ చేయండి
Comment[th]=แบ่งปันได้อย่างอิสระและเป็นส่วนตัว
Comment[tl]=Ibahagi, libre at pribado
Comment[tr]=Özgürce ve özel olarak paylaşın
Comment[uk]=Поділіться вільно та приватно
Comment[vi]=Chia sẻ, tự do và riêng tư
Comment[zh_CN]=自由且私密地分享
Comment[zh_HK]=自由且私密地分享
Comment[zh_TW]=自由且私密地分享
Comment[zu]=Yabelana, ngokukhululekile nangasese
Exec=jami %u
Icon=jami
Icon=net.jami.Jami
StartupNotify=true
Terminal=false
Type=Application
Categories=Network;Telephony;
Categories=Chat;FileTransfer;InstantMessaging;Network;P2P;Telephony;VideoConference;
Keywords=Qt;chat;talk;im;message;voip;
MimeType=x-scheme-handler/jami;
MimeType=x-scheme-handler/jami;

File diff suppressed because it is too large Load Diff

View File

@ -33,7 +33,9 @@
def SUBMODULES = ['daemon',
'3rdparty/SortFilterProxyModel',
'3rdparty/md4c',
'3rdparty/tidy-html5']
'3rdparty/tidy-html5',
'3rdparty/zxing-cpp',
'3rdparty/hunspell']
def TARGETS = [:]
def REMOTE_HOST = env.SSH_HOST_DL_RING_CX
def REMOTE_BASE_DIR = '/srv/repository/ring'
@ -83,6 +85,10 @@ pipeline {
environment {
TARBALLS = '/var/cache/jami' // set the cache directory
BUILD_VERSION = sh(
returnStdout: true,
script: 'date +"%Y%m%d%H%M"'
).trim()
}
stages {

View File

@ -127,7 +127,9 @@ $(RELEASE_TARBALL_FILENAME): tarballs.manifest
. \
./3rdparty/SortFilterProxyModel \
./3rdparty/md4c \
./3rdparty/tidy-html5; do \
./3rdparty/tidy-html5 \
./3rdparty/zxing-cpp \
./3rdparty/hunspell; do \
(cd "$$m" && git archive --prefix "$$m/" HEAD \
| tar xf - -C $(TMPDIR)/$(RELEASE_DIRNAME)); \
done
@ -165,15 +167,12 @@ DISTRIBUTIONS := \
ubuntu_20.04 \
ubuntu_22.04 \
ubuntu_24.04 \
ubuntu_24.10 \
fedora_37 \
fedora_38 \
fedora_39 \
fedora_40 \
ubuntu_25.04 \
fedora_41 \
fedora_42 \
alma_9 \
opensuse-leap_15.4 \
opensuse-leap_15.5 \
alma_10 \
opensuse-leap_15.6 \
snap
IS_SHELL_INTERACTIVE := $(shell [ -t 0 ] && echo yes)
@ -192,6 +191,7 @@ $(1)-docker-image-name := jami-packaging-$(1)
$(1)-docker-image-file := .docker-image-$$($(1)-docker-image-name)
$(1)-docker-run-command := docker run \
--rm --privileged --security-opt apparmor=docker-default \
-e BUILD_VERSION=${BUILD_VERSION} \
-e RELEASE_VERSION="$(RELEASE_VERSION)" \
-e RELEASE_DIRNAME="$(RELEASE_DIRNAME)" \
-e RELEASE_TARBALL_FILENAME="$(RELEASE_TARBALL_FILENAME)" \
@ -251,7 +251,7 @@ define guix-pack-command
guix pack -C xz -f $(1) -m $(CURDIR)/extras/packaging/gnu-linux/guix/guix-pack-manifest.scm -v3 \
-S /usr/bin/jami=bin/jami \
-S /usr/share/applications/net.jami.Jami.desktop=share/applications/net.jami.Jami.desktop \
-S /usr/share/icons/hicolor/scalable/apps/jami.svg=share/icons/hicolor/scalable/apps/jami.svg \
-S /usr/share/icons/hicolor/scalable/apps/net.jami.Jami.svg=share/icons/hicolor/scalable/apps/net.jami.Jami.svg \
-S /usr/share/icons/hicolor/48x48/apps/jami.png=share/icons/hicolor/48x48/apps/jami.png \
-S /usr/share/metainfo/net.jami.Jami.metainfo.xml=share/metainfo/net.jami.Jami.metainfo.xml \
-S /usr/share/swcatalog/xml/jami.xml=share/swcatalog/xml/jami.xml \

View File

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

View File

@ -70,9 +70,8 @@ RUN dnf install -y \
libdrm \
gperf \
bison \
clang \
clang-devel \
llvm-devel \
clang16-devel \
llvm16-devel \
nodejs \
flex \
gstreamer1 gstreamer1-devel \
@ -96,7 +95,6 @@ RUN dnf install -y \
perl-English \
libxshmfence-devel \
ninja-build \
clang \
cmake \
fmt-devel \
python3-html5lib \

View File

@ -11,14 +11,6 @@ RUN apt-get update && \
libdbus-1-dev \
wget
# As of January 2024, the default compiler on Debian unstable is GCC 13.2.0, which
# is unable to build one of Qt 6.6.1's dependencies, see:
# https://github.com/qt/qtquick3d-assimp/commit/253f8bfa621a9fa6cd2c36291cdaa8c60c99322c
# The linked commit above fixes the problem and is included in more recent versions of Qt.
# For now, we use GCC 12 as a temporary workaround:
ADD extras/packaging/gnu-linux/scripts/install-gcc-debian.sh /opt/install-gcc-debian.sh
RUN /opt/install-gcc-debian.sh 12
ADD extras/packaging/gnu-linux/scripts/prebuild-package-debian.sh /opt/prebuild-package-debian.sh
COPY extras/packaging/gnu-linux/rules/debian-qt/control /tmp/builddeps/debian/control

View File

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

View File

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

View File

@ -1,4 +1,4 @@
FROM fedora:39
FROM fedora:42
RUN dnf clean all
RUN dnf update -y
@ -6,12 +6,10 @@ RUN dnf update -y
RUN dnf install -y dnf-command\(builddep\) rpmdevtools && \
dnf install -y mock
RUN dnf groupinstall -y "X Software Development"
RUN dnf group install -y x-software-development
RUN dnf install -y \
git \
rpm-build \
tar \
make \
autoconf \
automake \
@ -22,13 +20,10 @@ RUN dnf install -y \
libcurl-devel \
libtool \
mesa-libgbm-devel \
mesa-dri-drivers \
dbus-devel \
expat-devel \
pcre-devel \
yaml-cpp-devel \
libXext-devel \
libXfixes-devel \
yasm \
speex-devel \
gsm-devel \
@ -37,16 +32,15 @@ RUN dnf install -y \
astyle \
uuid-c++-devel \
gettext-devel \
gcc-c++ \
gcc14 \
gcc14-c++ \
which \
alsa-lib-devel \
systemd-devel \
libuuid-devel \
uuid-devel \
gnutls-devel \
nettle-devel \
opus-devel \
patch \
jsoncpp-devel \
libnatpmp-devel \
webkitgtk4-devel \
@ -64,28 +58,20 @@ RUN dnf install -y \
qrencode-devel \
libargon2-devel \
libsndfile-devel \
libdrm \
gperf \
bison \
clang \
clang-devel \
llvm-devel \
clang18-devel \
llvm18-devel \
nodejs \
flex \
gstreamer1 gstreamer1-devel \
gstreamer1-plugins-base-devel \
gstreamer1-plugins-good \
gstreamer1-plugins-bad-free-devel \
nss-devel \
libxcb* \
libxkb* \
libX11-devel \
vulkan-devel \
libXrender-devel \
xcb-util-* \
xz \
xkeyboard-config \
libnotify \
wget \
libstdc++-static \
sqlite-devel \
@ -93,13 +79,19 @@ RUN dnf install -y \
perl-English \
libxshmfence-devel \
ninja-build \
clang \
cmake \
fmt-devel \
python3.10 \
cups-devel \
pipewire-devel
# Use GCC 14 instead of GCC 15 (the default on Fedora 42)
# because Qt 6.6.3 fails to build when using the latter.
RUN rm /usr/bin/gcc /usr/bin/g++ /usr/bin/c++ && \
ln -s /usr/bin/gcc-14 /usr/bin/gcc && \
ln -s /usr/bin/g++-14 /usr/bin/g++ && \
ln -s /usr/bin/g++-14 /usr/bin/c++
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
CMD ["/opt/build-package-rpm.sh"]

View File

@ -1,122 +0,0 @@
FROM opensuse/leap:15.4
RUN zypper refresh
RUN zypper --non-interactive install -y \
dnf \
dnf-command\(builddep\) \
rpmdevtools \
Mesa-dri-devel Mesa-dri \
git \
gcc10 \
gcc10-c++ \
rpm-build \
tar \
make \
autoconf \
automake \
nasm \
speexdsp-devel \
libpulse-devel \
libcanberra-devel \
libcurl-devel \
libtool \
pcre-devel \
yaml-cpp-devel \
libXext-devel \
libXfixes-devel \
yasm \
speex-devel \
libgsm-devel \
chrpath \
check \
astyle \
gettext-devel \
which \
alsa-lib-devel \
systemd-devel \
libuuid-devel \
uuid-devel \
libopus-devel \
patch \
jsoncpp-devel \
webkit2gtk3-devel \
libcryptopp-devel \
libva-devel \
libvdpau-devel \
msgpack-devel \
clutter-devel \
openssl-devel \
clutter-gtk-devel \
libnma-devel \
libcryptopp-devel \
libexpat-devel \
gnome-icon-theme-symbolic \
libgsm-devel \
gtk3-devel \
libappindicator-devel \
sqlite-devel \
ffmpeg-4-libavutil-devel \
gtk3-devel\
qrencode-devel \
python310 \
python3-python-dateutil \
python3-html5lib \
libsndfile-devel \
libdrm \
gperf \
bison \
flex \
ffmpeg ffmpeg-devel \
nodejs18 \
mozilla-nss-devel \
python-xml \
python3-six \
python3-importlib-metadata \
libxcb* \
libxkb* \
libX11-devel \
libXrender-devel \
libfreetype6 \
xcb-util-image-devel \
xcb-util-keysyms-devel \
xcb-util-renderutil-devel \
xcb-util-wm-devel \
xorg-x11-devel \
xz \
xkeyboard-config \
libnotify \
argon2-devel \
libxshmfence-devel \
xproto-devel \
xcb-proto-devel \
xcb-* \
xorg-* \
vulkan-devel \
ninja \
gstreamer-devel \
gstreamer-plugins-good \
gstreamer-plugins-bad-devel \
gstreamer-plugins-base-devel \
cmake \
wget \
pipewire-devel
# openSUSE Leap 15.4 comes with Python 3.6 by default,
# but we need at least 3.7 to compile Qt 6.6.1
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.10 /usr/bin/python3
RUN update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-10 50
RUN update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 50
ADD extras/packaging/gnu-linux/scripts/build-package-rpm.sh /opt/build-package-rpm.sh
ENV CC=gcc
ENV CXX=g++
# Setting this variable so that FFmpeg gets built without pipewiregrab
# (see daemon/contrib/bootstrap and daemon/contrib/src/ffmpeg/rules.mak)
# We rely on PipeWire for screen sharing on Wayland, but the version available on openSUSE Leap 15.4 is too old.
ENV DISABLE_PIPEWIRE=true
CMD ["/opt/build-package-rpm.sh"]

View File

@ -1,10 +1,9 @@
FROM opensuse/leap:15.5
FROM opensuse/leap:15.6
RUN zypper --gpg-auto-import-keys refresh
RUN zypper --non-interactive install -y \
dnf \
dnf-command\(builddep\) \
rpmdevtools \
Mesa-dri-devel Mesa-dri \
git \
@ -29,11 +28,11 @@ RUN zypper --non-interactive install -y \
speex-devel \
libgsm-devel \
chrpath \
check \
check-devel \
astyle \
gettext-devel \
gettext-tools \
which \
alsa-lib-devel \
alsa-devel \
systemd-devel \
libuuid-devel \
uuid-devel \
@ -47,7 +46,7 @@ RUN zypper --non-interactive install -y \
msgpack-c-devel \
msgpack-cxx-devel \
clutter-devel \
openssl-devel \
libopenssl-devel \
clutter-gtk-devel \
libnma-devel \
libcryptopp-devel \
@ -56,19 +55,19 @@ RUN zypper --non-interactive install -y \
libgsm-devel \
gtk3-devel \
libappindicator-devel \
sqlite-devel \
ffmpeg-4-libavutil-devel \
sqlite3-devel \
gtk3-devel\
qrencode-devel \
python310 \
python3-python-dateutil \
python3-html5lib \
libsndfile-devel \
libdrm \
libdrm-devel \
gperf \
bison \
flex \
ffmpeg ffmpeg-devel \
ffmpeg \
ffmpeg-devel \
nodejs20 \
mozilla-nss-devel \
python-xml \
@ -86,7 +85,7 @@ RUN zypper --non-interactive install -y \
xorg-x11-devel \
xz \
xkeyboard-config \
libnotify \
libnotify-devel \
argon2-devel \
libxshmfence-devel \
xproto-devel \
@ -103,7 +102,7 @@ RUN zypper --non-interactive install -y \
wget \
pipewire-devel
# openSUSE Leap 15.5 comes with Python 3.6 by default,
# openSUSE Leap 15.6 comes with Python 3.6 by default,
# but we need at least 3.7 to compile Qt 6.6.1
RUN rm /usr/bin/python3 && ln -s /usr/bin/python3.10 /usr/bin/python3

View File

@ -36,12 +36,6 @@ RUN curl -L $(curl -H 'X-Ubuntu-Series: 16' 'https://api.snapcraft.io/api/v1/sna
RUN mkdir -p /snap/snapcraft
RUN unsquashfs -d /snap/snapcraft/current snapcraft.snap
# Fix Python3 installation: Make sure we use the interpreter from
# the snapcraft snap:
RUN unlink /snap/snapcraft/current/usr/bin/python3
RUN ln -s /snap/snapcraft/current/usr/bin/python3.* /snap/snapcraft/current/usr/bin/python3
RUN echo /snap/snapcraft/current/lib/python3.*/site-packages >> /snap/snapcraft/current/usr/lib/python3/dist-packages/site-packages.pth
# Create a snapcraft runner
RUN mkdir -p /snap/bin
RUN echo "#!/bin/sh" > /snap/bin/snapcraft

View File

@ -1,4 +1,4 @@
FROM ubuntu:24.10
FROM ubuntu:25.04
ENV DEBIAN_FRONTEND=noninteractive
@ -20,7 +20,7 @@ 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
# library on Ubuntu 25.04 (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

View File

@ -24,7 +24,10 @@
(list
;; Minimal requirements of the daemon contrib build system.
"coreutils"
"gcc-toolchain"
;; When using GCC 15, Jami fails to link with errors like:
;; ld: CMakeFiles/jami.dir/src/app/main.cpp.o:(.rodata+0x0):
;; multiple definition of `QtPrivate::IsFloatType_v<_Float16>'
"gcc-toolchain@14"
"git-minimal"
"grep"
"gzip"
@ -42,18 +45,12 @@
"alsa-lib"
"autoconf"
"automake"
"asio"
"bash"
"bzip2"
"cmake"
"dbus"
;; Bundled because broken with GCC 7 upstream (unmaintained). When
;; attempting to use it, it would cause confusing errors such as
;; "ld: ../src/.libs/libring.a(libupnpcontrol_la-upnp_context.o): in
;; function `jami::upnp::UPnPContext::updateMappingList(bool)':
;; upnp_context.cpp:(.text+0xa4be): undefined reference to
;; `std::__cxx11::basic_ostringstream<char, std::char_traits<char>,
;; std::allocator<char> >::basic_ostringstream()'
;;"dbus-c++" ;for dbusxx-xml2cpp
;;"dhtnet" ;bundled because tightly coupled
"diffutils"
"doxygen"
"eudev" ;udev library
@ -67,6 +64,7 @@
"gsm"
"gtk-doc"
"http-parser"
"jack@0"
"jsoncpp"
"libarchive"
"libgit2"
@ -84,16 +82,24 @@
"patch"
"pcre"
"perl"
"pipewire"
;;"pjproject" ;bundled because patched
"pulseaudio"
"sdbus-c++@1"
"speex"
"speexdsp"
"webrtc-audio-processing@0"
"which"
"yaml-cpp"
"yasm"
;; For the Qt client.
"glib"
"hunspell"
"libnotify"
"libxcb"
"libxkbcommon"
"md4c"
"network-manager" ;libnm
"qrencode"
"qtbase"
@ -103,10 +109,13 @@
"qtnetworkauth"
"qtpositioning"
"qtsvg"
"qwindowkit"
"qttools"
"qtwebchannel"
"qtwebengine"
"tidy-html"
"vulkan-headers"
"zxing-cpp"
;; For tests and debugging.
"file"

View File

@ -261,7 +261,7 @@ Build-Depends: debhelper (>= 9),
gperf,
khronos-api,
# libasound2-dev [linux-any],
libavcodec-dev (>= 7:3.4.8~),
libavcodec-dev (>= 7:3.4.8~) | libavcodec-extra-dev (>= 7:3.4.8~),
libavformat-dev (>= 7:3.4.8~),
libavutil-dev (>= 7:3.4.8~),
libcap-dev [linux-any],

View File

@ -30,7 +30,7 @@ Build-Depends: debhelper (>= 9),
libspeex-dev,
libspeexdsp-dev,
uuid-dev,
libavcodec-dev,
libavcodec-dev | libavcodec-extra-dev,
libavutil-dev,
libavformat-dev,
libswscale-dev,

View File

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

View File

@ -74,7 +74,7 @@ override_dh_auto_build:
--disable-gsm \
--disable-speexdsp \
--disable-natpmp \
--enable-gnutls $(BUNDLED_PKGS) && \
$(BUNDLED_PKGS) && \
make list && \
make -j$(NO_CPUS) V=1
cd daemon && \
@ -91,6 +91,7 @@ override_dh_auto_build:
mkdir build && \
cd build && \
cmake \
-DBUILD_VERSION=$(BUILD_VERSION) \
-DCMAKE_INSTALL_PREFIX=/usr \
-DLIBJAMI_BUILD_DIR=$(CURDIR)/daemon/src \
-DENABLE_LIBWRAP=true \

View File

@ -49,7 +49,7 @@ BuildRequires: libXfixes-devel
BuildRequires: libuuid-devel
BuildRequires: libva-devel
BuildRequires: libvdpau-devel
BuildRequires: pcre-devel
BuildRequires: (pcre-devel or pcre2-devel)
BuildRequires: pipewire-devel
BuildRequires: uuid-devel
BuildRequires: yaml-cpp-devel

View File

@ -31,6 +31,7 @@ URL: https://jami.net/
Source: jami-libqt-%{version}.tar.xz
Patch0: 0001-fix-gcc14.patch
Patch1: 0002-qtwebengine-add-missing-chromium-dependencies.patch
Patch2: 0003-fix-embree-linking-errors.patch
%global gst 0.10
%if 0%{?fedora} || 0%{?rhel} > 7
@ -68,6 +69,7 @@ This package contains Qt libraries for Jami.
%setup -n qt-everywhere-src-%{version}
%patch -P 0 -p1
%patch -P 1 -p1
%patch -P 2 -p1
%build
echo "Building Qt using %{job_count} parallel jobs"

View File

@ -1,16 +1,7 @@
%define name jami
%define version RELEASE_VERSION
%define release 0
# The AppStream 1.0 spec says that the catalog file must be put in /usr/share/swcatalog/xml
# (see https://www.freedesktop.org/software/appstream/docs/chap-CatalogData.html).
#
# However, openSUSE Leap still uses the legacy path /usr/share/app-info/xmls as of version 15.5.
%if 0%{?sle_version} && 0%{?sle_version} <= 150500
%define appstream_catalog_dir /share/app-info/xmls
%else
%define appstream_catalog_dir /share/swcatalog/xml
%endif
# Exclude vendored Qt6 from dependency generator
%define __requires_exclude ^libQt6.*$
@ -82,6 +73,7 @@ cd %{_builddir}/jami-%{version} && \
-DAPPSTREAM_CATALOG_DIR=%{appstream_catalog_dir} \
-DWITH_DAEMON_SUBMODULE=true \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_VERSION=${BUILD_VERSION} \
..
make -C %{_builddir}/jami-%{version}/build %{_smp_mflags} V=2
@ -93,7 +85,7 @@ DESTDIR=%{buildroot} make -C %{_builddir}/jami-%{version}/build install V=2
%{_bindir}/jami
%{_datadir}/applications/net.jami.Jami.desktop
%{_datadir}/jami/net.jami.Jami.desktop
%{_datadir}/icons/hicolor/scalable/apps/jami.svg
%{_datadir}/icons/hicolor/scalable/apps/net.jami.Jami.svg
%{_datadir}/icons/hicolor/48x48/apps/jami.png
%{_datadir}/pixmaps/jami.xpm
%{_datadir}/metainfo/net.jami.Jami.metainfo.xml

View File

@ -0,0 +1,29 @@
From 709d0b0cf45b920f63960a70725138dbaf7ec721 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois-Simon=20Fauteux-Chapleau?=
<francois-simon.fauteux-chapleau@savoirfairelinux.com>
Date: Wed, 18 Jun 2025 15:53:55 -0400
Subject: [PATCH] Fix embree linking errors
Patch taken from:
https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=37bd373cd33c36f8dd44e71be25fa6ea24cf4588
---
qtquick3d/src/3rdparty/embree/CMakeLists.txt | 3 +++
1 file changed, 3 insertions(+)
diff --git a/qtquick3d/src/3rdparty/embree/CMakeLists.txt b/qtquick3d/src/3rdparty/embree/CMakeLists.txt
index cf27196de2..332bbd17ca 100644
--- a/qtquick3d/src/3rdparty/embree/CMakeLists.txt
+++ b/qtquick3d/src/3rdparty/embree/CMakeLists.txt
@@ -62,6 +62,9 @@ if (IOS)
endif()
# Use SSE2 only, ignore AVX/SSE4.2 for now
+if (TEST_architecture_arch STREQUAL x86_64)
+ qt_internal_extend_target(BundledEmbree COMPILE_OPTIONS -mno-avx -mno-sse4.2)
+endif()
qt_internal_extend_target(BundledEmbree DEFINES
EMBREE_TARGET_SSE2
__SSE2__
--
2.34.1

View File

@ -270,7 +270,7 @@ parts:
ls
snapcraftctl pull
sed -i -E 's|(tmpName) << (PACKAGE_NAME << "_shm_")|\1 << "snap.jami." << \2|' ./daemon/src/media/video/sinkclient.cpp
sed -i -E 's|^Icon=.*|Icon=${SNAP}/usr/share/icons/hicolor/scalable/apps/jami.svg|' extras/data/net.jami.Jami.desktop
sed -i -E 's|^Icon=.*|Icon=${SNAP}/usr/share/icons/hicolor/scalable/apps/net.jami.Jami.svg|' extras/data/net.jami.Jami.desktop
override-build: |
$SNAPCRAFT_PART_BUILD/extras/packaging/gnu-linux/scripts/install-pipewire-from-source.sh
@ -293,7 +293,8 @@ parts:
cmake .. -DENABLE_LIBWRAP=true \
-DLIBJAMI_BUILD_DIR=$SNAPCRAFT_PART_BUILD/daemon/src \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_VERSION=BUILD_VERSION_PLACEHOLDER
make -j$SNAPCRAFT_PARALLEL_BUILD_COUNT
DESTDIR=$SNAPCRAFT_PART_INSTALL make install
build-packages:

View File

@ -47,7 +47,11 @@ if [ ! -f "${qt_deb_path}" ] || [ "${FORCE_REBUILD_QT}" = "true" ]; then
# HACK: For now on ubuntu 24.04 there is no python3.10 package
# So create a PyEnv environment to install the required packages
if cat /etc/os-release | grep -Eq "24.04"; then
# NOTE: We use this on Ubuntu 25.04 and Debian 13 ("trixie") too
# because otherwise we get a ModuleNotFoundError when building
# Qt 6.6.1 (specifically the chromium submodule in QtWebEngine)
# due to the version of python used (3.13) being too recent.
if cat /etc/os-release | grep -Eq "24.04|25.04|trixie"; then
apt-get install git gcc make python3-pip libssl-dev curl libreadline-dev -y
curl https://pyenv.run | bash
export PYENV_ROOT="$HOME/.pyenv"

View File

@ -101,20 +101,14 @@ if [ ! -f "${RPM_PATH}" ]; then
# Cache the built Qt RPM package.
if [[ "${DISTRIBUTION:0:4}" == "rhel" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el8.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_36" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc36.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_37" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc37.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_38" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc38.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_39" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc39.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_40" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc40.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_41" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc41.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "fedora_42" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.fc42.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "alma_9" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el9.x86_64.rpm "${RPM_PATH}"
elif [[ "${DISTRIBUTION}" == "alma_10" ]]; then
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-$QT_MAJOR_MINOR_PATCH-*.el10.x86_64.rpm "${RPM_PATH}"
else
cp /root/rpmbuild/RPMS/x86_64/jami-libqt-*.rpm "${RPM_PATH}"
fi
@ -138,7 +132,7 @@ rpmbuild --define "debug_package %{nil}" -ba jami-libclient.spec
rpmbuild --define "debug_package %{nil}" -ba jami-qt.spec
# Build the Qt client.
rpmbuild --define "debug_package %{nil}" -ba jami.spec
rpmbuild --define "debug_package %{nil}" --define "BUILD_VERSION ${BUILD_VERSION}" -ba jami.spec
# Move the built packages to the output directory.
mv /root/rpmbuild/RPMS/*/* /opt/output

View File

@ -29,6 +29,9 @@ cp -r extras/packaging/gnu-linux/rules/snap/${SNAP_PKG_NAME}/snapcraft.yaml .
# set the version and tarball filename
sed -i "s/RELEASE_VERSION/${RELEASE_VERSION}/g" snapcraft.yaml
# set the build version of the app
sed -i "s/BUILD_VERSION_PLACEHOLDER/${BUILD_VERSION}/g" snapcraft.yaml
snapcraft # requires snapcraft >= 4.8
# move the built snap to output

View File

@ -80,9 +80,6 @@ EOF
find ./extras/packaging/gnu-linux/packages -type f -name '*.ddeb' -print0 | xargs -0 -I{} mv {} {}.deb
for package in ./extras/packaging/gnu-linux/packages/${DISTRIBUTION}*/*.deb; do
echo "## signing: ${package} ##"
dpkg-sig -k ${KEYID} --sign builder ${package}
echo "## including ${package} ##"
package_name=$(dpkg -I ${package} | grep -m 1 Package: | awk '{print $2}')
package_arch=$(dpkg -I ${package} | grep -m 1 Architecture: | awk '{print $2}')

View File

@ -1,25 +0,0 @@
From 161d28abb6784115ad71fcb6977e112e9d5756d4 Mon Sep 17 00:00:00 2001
From: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
Date: Tue, 23 Jan 2024 15:38:34 -0500
Subject: [PATCH] fix-fedora-fc-build
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0fb89c8..3a6ad6d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -65,7 +65,7 @@ if(NOT TARGET qmsetup::library)
)
# Find package again
- find_package(qmsetup REQUIRED PATHS ${_package_path})
+ find_package(qmsetup REQUIRED PATHS ${_package_path} ${qmsetup_cmake_path})
# Update import path
set(qmsetup_DIR ${_package_path} CACHE PATH "" FORCE)
--
2.34.1

View File

@ -0,0 +1,32 @@
From 56830725e641705e0113a068ee58df7029202439 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, 2 Apr 2025 20:54:02 -0400
Subject: [PATCH] fix qm_install_package function
---
cmake/modules/private/InstallPackage.cmake | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/qmsetup/cmake/modules/private/InstallPackage.cmake b/qmsetup/cmake/modules/private/InstallPackage.cmake
index 70174bc..f067de5 100644
--- a/qmsetup/cmake/modules/private/InstallPackage.cmake
+++ b/qmsetup/cmake/modules/private/InstallPackage.cmake
@@ -101,6 +101,7 @@ function(qm_install_package _name)
execute_process(
COMMAND ${CMAKE_COMMAND} -S ${_src_dir} -B ${_build_dir}
${_extra_args} ${_build_type}
+ "-DCMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}"
"-DCMAKE_INSTALL_PREFIX=${_install_dir}" ${FUNC_CONFIGURE_ARGS}
OUTPUT_FILE ${_log_file}
ERROR_FILE ${_log_file}
@@ -150,4 +151,4 @@ function(qm_install_package _name)
if(FUNC_RESULT_PATH)
set(${FUNC_RESULT_PATH} ${_install_cmake_dir} PARENT_SCOPE)
endif()
-endfunction()
\ No newline at end of file
+endfunction()
--
2.34.1

View File

@ -211,6 +211,8 @@ def init_submodules():
"3rdparty/SortFilterProxyModel",
"3rdparty/md4c",
"3rdparty/tidy-html5",
"3rdparty/zxing-cpp",
"3rdparty/hunspell",
]
if execute_cmd(["git", "submodule", "update", "--init" ] + submodules,
False):
@ -261,7 +263,7 @@ def cmake_build(config_str, env_vars, cmake_build_dir):
return True
def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None):
def build(config_str, qt_dir, tests, build_version, enable_crash_reports, crash_report_url=None):
"""Use cmake to build the project."""
print("Building with Qt at " + qt_dir)
@ -292,6 +294,9 @@ def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None
else:
cmake_options.append("-DENABLE_CRASHREPORTS=OFF")
if build_version:
cmake_options.append("-DBUILD_VERSION=" + build_version)
# Make sure the build directory exists.
if not os.path.exists(build_dir):
os.makedirs(build_dir)
@ -305,11 +310,11 @@ def build(config_str, qt_dir, tests, enable_crash_reports, crash_report_url=None
sys.exit(1)
def deploy_runtimes(config_str, qt_dir):
def deploy_runtimes(qt_dir):
"""Deploy the dependencies to the runtime directory."""
print("Deploying runtime dependencies")
runtime_dir = os.path.join(repo_root_dir, "x64", config_str)
runtime_dir = os.path.join(repo_root_dir, "x64", "Release")
stamp_file = os.path.join(runtime_dir, ".deploy.stamp")
if os.path.exists(stamp_file):
return
@ -322,8 +327,8 @@ def deploy_runtimes(config_str, qt_dir):
shutil.copy(os.path.join(rel_path, src), runtime_dir)
print("Copying libjami dependencies")
install_file("contrib/build/openssl/libcrypto-1_1-x64.dll", daemon_dir)
install_file("contrib/build/openssl/libssl-1_1-x64.dll", daemon_dir)
install_file("contrib/build/openssl/libcrypto-3-x64.dll", daemon_dir)
install_file("contrib/build/openssl/libssl-3-x64.dll", daemon_dir)
# Ringtone files (ul,ogg,wav,opus files in the daemon ringtone dir).
print("Copying ringtones")
@ -468,6 +473,8 @@ def parse_args():
help='Sets the Qt root path')
parser.add_argument(
"-a", "--arch", default="x64", help="Sets the build architecture")
parser.add_argument(
"--build-version", help="Sets the build version string used for defining app build version")
parser.add_argument(
"-t", "--tests", action="store_true", help="Build and run tests")
parser.add_argument(
@ -550,10 +557,11 @@ def main():
def do_build(do_tests):
if not parsed_args.skip_build:
build(config_str, parsed_args.qt, do_tests,
parsed_args.build_version,
parsed_args.enable_crash_reports,
parsed_args.crash_report_url)
if not parsed_args.skip_deploy:
deploy_runtimes(config_str, parsed_args.qt)
deploy_runtimes(parsed_args.qt)
if parsed_args.subcommand == "pack":
do_build(False)

View File

@ -52,7 +52,7 @@ for ARCH in "${ARCHS[@]}"; do
# force to build every contrib
for dir in "$DAEMON"/contrib/src/*/; do
PKG=$(basename -- "$dir")
if [ "$PKG" != "sdbus-cpp" ] && [ "$PKG" != "natpmp" ] &&
if [ "$PKG" != "sdbus-cpp" ] && [ "$PKG" != "freetype" ] &&
[ "$PKG" != "portaudio" ] && [ "$PKG" != "pthreads" ] &&
[ "$PKG" != "lttng-ust" ] && [ "$PKG" != "openssl" ] &&
[ "$PKG" != "media-sdk" ] && [ "$PKG" != "jack" ] &&

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 622 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 653 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 KiB

View File

@ -0,0 +1,382 @@
{
"af_ZA": {
"nativeName": "Afrikaans (Suid-Afrika)",
"path": "af_ZA/af_ZA"
},
"an_ES": {
"nativeName": "aragonés (España)",
"path": "an_ES/an_ES"
},
"ar": {
"nativeName": "العربية",
"path": "ar/ar"
},
"as_IN": {
"nativeName": "অসমীয়া (भारत)",
"path": "as_IN/as_IN"
},
"be-official": {
"nativeName": "беларуская",
"path": "be_BY/be-official"
},
"bg_BG": {
"nativeName": "български",
"path": "bg_BG/bg_BG"
},
"bn_BD": {
"nativeName": "বাঙ্গালি (বাংলাদেশ)",
"path": "bn_BD/bn_BD"
},
"bn_IN": {
"nativeName": "বাঙ্গালি (ভারত)",
"path": "bn_BD/bn_IN"
},
"bo": {
"nativeName": "བོད་སྐད་",
"path": "bo/bo"
},
"br_FR": {
"nativeName": "breton (France)",
"path": "br_FR/br_FR"
},
"bs_BA": {
"nativeName": "bosanski",
"path": "bs_BA/bs_BA"
},
"cs_CZ": {
"nativeName": "čeština",
"path": "cs_CZ/cs_CZ"
},
"da_DK": {
"nativeName": "dansk",
"path": "da_DK/da_DK"
},
"de_AT_frami": {
"nativeName": "Deutsch (Österreich)",
"path": "de/de_AT_frami"
},
"de_CH_frami": {
"nativeName": "Deutsch (Schweiz)",
"path": "de/de_CH_frami"
},
"de_DE_frami": {
"nativeName": "Deutsch (Deutschland)",
"path": "de/de_DE_frami"
},
"el_GR": {
"nativeName": "Ελληνικά",
"path": "el_GR/el_GR"
},
"en_AU": {
"nativeName": "English (Australia)",
"path": "en/en_AU"
},
"en_CA": {
"nativeName": "English (Canada)",
"path": "en/en_CA"
},
"en_GB": {
"nativeName": "English (British)",
"path": "en/en_GB"
},
"en_US": {
"nativeName": "English (American)",
"path": "en/en_US"
},
"en_ZA": {
"nativeName": "English (Suid-Afrika)",
"path": "en/en_ZA"
},
"eo": {
"nativeName": "esperanto",
"path": "eo/eo"
},
"es_AR": {
"nativeName": "español (Argentina)",
"path": "es/es_AR"
},
"es_BO": {
"nativeName": "español (Bolivia)",
"path": "es/es_BO"
},
"es_CL": {
"nativeName": "español (Chile)",
"path": "es/es_CL"
},
"es_CO": {
"nativeName": "español (Colombia)",
"path": "es/es_CO"
},
"es_CR": {
"nativeName": "español (Costa Rica)",
"path": "es/es_CR"
},
"es_CU": {
"nativeName": "español (Cuba)",
"path": "es/es_CU"
},
"es_DO": {
"nativeName": "español (República Dominicana)",
"path": "es/es_DO"
},
"es_EC": {
"nativeName": "español (Ecuador)",
"path": "es/es_EC"
},
"es_ES": {
"nativeName": "español (España)",
"path": "es/es_ES"
},
"es_GQ": {
"nativeName": "español (Guinea Ecuatorial)",
"path": "es/es_GQ"
},
"es_GT": {
"nativeName": "español (Guatemala)",
"path": "es/es_GT"
},
"es_HN": {
"nativeName": "español (Honduras)",
"path": "es/es_HN"
},
"es_MX": {
"nativeName": "español (México)",
"path": "es/es_MX"
},
"es_NI": {
"nativeName": "español (Nicaragua)",
"path": "es/es_NI"
},
"es_PA": {
"nativeName": "español (Panamá)",
"path": "es/es_PA"
},
"es_PE": {
"nativeName": "español (Perú)",
"path": "es/es_PE"
},
"es_PH": {
"nativeName": "español (Pilipinas)",
"path": "es/es_PH"
},
"es_PR": {
"nativeName": "español (Puerto Rico)",
"path": "es/es_PR"
},
"es_PY": {
"nativeName": "español (Paraguai)",
"path": "es/es_PY"
},
"es_SV": {
"nativeName": "español (El Salvador)",
"path": "es/es_SV"
},
"es_US": {
"nativeName": "español (United States)",
"path": "es/es_US"
},
"es_UY": {
"nativeName": "español (Uruguay)",
"path": "es/es_UY"
},
"es_VE": {
"nativeName": "español (Venezuela)",
"path": "es/es_VE"
},
"et_EE": {
"nativeName": "eesti",
"path": "et_EE/et_EE"
},
"fa-IR": {
"nativeName": "فارسی",
"path": "fa_IR/fa-IR"
},
"fr": {
"nativeName": "français",
"path": "fr_FR/fr"
},
"gd_GB": {
"nativeName": "Gàidhlig",
"path": "gd_GB/gd_GB"
},
"gl_ES": {
"nativeName": "galego",
"path": "gl/gl_ES"
},
"gu_IN": {
"nativeName": "ગુજરાતી",
"path": "gu_IN/gu_IN"
},
"he_IL": {
"nativeName": "עברית",
"path": "he_IL/he_IL"
},
"hi_IN": {
"nativeName": "हिन्दी",
"path": "hi_IN/hi_IN"
},
"hr_HR": {
"nativeName": "hrvatski",
"path": "hr_HR/hr_HR"
},
"hu_HU": {
"nativeName": "magyar",
"path": "hu_HU/hu_HU"
},
"id_ID": {
"nativeName": "Indonesian",
"path": "id/id_ID"
},
"is": {
"nativeName": "íslenska",
"path": "is/is"
},
"it_IT": {
"nativeName": "italiano",
"path": "it_IT/it_IT"
},
"kmr_Latn": {
"nativeName": "Northern Kurdish",
"path": "kmr_Latn/kmr_Latn"
},
"kn_IN": {
"nativeName": "ಕನ್ನಡ",
"path": "kn_IN/kn_IN"
},
"ko_KR": {
"nativeName": "한국어",
"path": "ko_KR/ko_KR"
},
"lo_LA": {
"nativeName": "ລາວ",
"path": "lo_LA/lo_LA"
},
"lt": {
"nativeName": "lietuvių",
"path": "lt_LT/lt"
},
"lv_LV": {
"nativeName": "latviešu",
"path": "lv_LV/lv_LV"
},
"mn_MN": {
"nativeName": "монгол",
"path": "mn_MN/mn_MN"
},
"mr_IN": {
"nativeName": "मराठी",
"path": "mr_IN/mr_IN"
},
"nb_NO": {
"nativeName": "norsk bokmål",
"path": "no/nb_NO"
},
"ne_NP": {
"nativeName": "नेपाली",
"path": "ne_NP/ne_NP"
},
"nl_NL": {
"nativeName": "Nederlands",
"path": "nl_NL/nl_NL"
},
"nn_NO": {
"nativeName": "norsk nynorsk",
"path": "no/nn_NO"
},
"oc_FR": {
"nativeName": "occitan",
"path": "oc_FR/oc_FR"
},
"or_IN": {
"nativeName": "ଓଡ଼ିଆ",
"path": "or_IN/or_IN"
},
"pa_IN": {
"nativeName": "ਪੰਜਾਬੀ",
"path": "pa_IN/pa_IN"
},
"pl_PL": {
"nativeName": "polski",
"path": "pl_PL/pl_PL"
},
"pt_BR": {
"nativeName": "português (Brasil)",
"path": "pt_BR/pt_BR"
},
"pt_PT": {
"nativeName": "português europeu (Portugal)",
"path": "pt_PT/pt_PT"
},
"ro_RO": {
"nativeName": "română",
"path": "ro/ro_RO"
},
"ru_RU": {
"nativeName": "русский",
"path": "ru_RU/ru_RU"
},
"sa_IN": {
"nativeName": "संस्कृत भाषा",
"path": "sa_IN/sa_IN"
},
"si_LK": {
"nativeName": "සිංහල",
"path": "si_LK/si_LK"
},
"sk_SK": {
"nativeName": "slovenčina",
"path": "sk_SK/sk_SK"
},
"sl_SI": {
"nativeName": "slovenščina",
"path": "sl_SI/sl_SI"
},
"sq_AL": {
"nativeName": "shqip",
"path": "sq_AL/sq_AL"
},
"sr": {
"nativeName": "српски",
"path": "sr/sr"
},
"sr-Latn": {
"nativeName": "srpski",
"path": "sr/sr-Latn"
},
"sv_FI": {
"nativeName": "svenska (Finland)",
"path": "sv_SE/sv_FI"
},
"sv_SE": {
"nativeName": "svenska (Sverige)",
"path": "sv_SE/sv_SE"
},
"sw_TZ": {
"nativeName": "Kiswahili",
"path": "sw_TZ/sw_TZ"
},
"ta_IN": {
"nativeName": "தமிழ்",
"path": "ta_IN/ta_IN"
},
"te_IN": {
"nativeName": "తెలుగు",
"path": "te_IN/te_IN"
},
"th_TH": {
"nativeName": "ไทย",
"path": "th_TH/th_TH"
},
"tr_TR": {
"nativeName": "Türkçe",
"path": "tr_TR/tr_TR"
},
"uk_UA": {
"nativeName": "українська",
"path": "uk_UA/uk_UA"
},
"vi_VN": {
"nativeName": "Tiếng Việt",
"path": "vi/vi_VN"
}
}

View File

@ -37,9 +37,12 @@ QtObject {
readonly property bool isHidden: visibility === Window.Hidden ||
visibility === Window.Minimized
// Used to store if a OngoingCallPage component is fullscreened.
// Used to store if a CallStackView component is fullscreened.
property bool isCallFullscreen: false
// Used to store if a WebEngineView component is fullscreened.
property bool isWebFullscreen: false
// QWK: Provide spacing for widgets that may be occluded by the system buttons.
property QtObject qwkSystemButtonSpacing: QtObject {
id: qwkSystemButtonSpacing
@ -150,9 +153,8 @@ QtObject {
// Adds an item to the fullscreen item stack. Automatically puts
// the main window in fullscreen mode if needed. Callbacks should be used
// to perform component-specific tasks upon successful transitions.
function pushFullScreenItem(item, prevParent, pushedCb, removedCb) {
if (item === null || item === undefined
|| priv.fullScreenItems.length >= 3) {
function pushFullScreenItem(item, removedCb=undefined) {
if (!item || priv.fullScreenItems.length >= 3) {
return
}
@ -162,15 +164,13 @@ QtObject {
// Add the item to our list and reparent it to appContainer.
priv.fullScreenItems.push({
"item": item,
"prevParent": prevParent,
"prevParent": item.parent,
"prevAnchorsFill": item.anchors.fill,
"removedCb": removedCb
})
item.parent = appContainer
item.anchors.fill = item.parent
if (pushedCb) {
pushedCb()
}
item.anchors.fill = appContainer
// Reevaluate isCallFullscreen.
priv.fullScreenItemsChanged()
@ -178,34 +178,37 @@ QtObject {
// Remove an item if specified, or by default, the top item. Automatically
// resets the main window to windowed mode if no items remain in the stack.
function popFullScreenItem(obj=null) {
function popFullScreenItem(obj = undefined) {
// Remove the item and reparent it to its original parent.
if (obj === null) {
obj = priv.fullScreenItems.pop()
if (obj === undefined) {
obj = priv.fullScreenItems.pop();
} else {
const index = priv.fullScreenItems.indexOf(obj);
if (index > -1) {
priv.fullScreenItems.splice(index, 1);
}
}
if (obj !== undefined) {
if (obj && typeof obj === 'object') {
if (obj.item !== appWindow) {
obj.item.anchors.fill = obj.prevAnchorsFill
obj.item.parent = obj.prevParent
if (obj.removedCb) {
obj.removedCb()
// Clear anchors first, then set parent, then reset anchors.
obj.item.anchors.fill = undefined;
obj.item.parent = obj.prevParent;
obj.item.anchors.fill = obj.prevAnchorsFill;
// Call removed callback if it's a function.
if (typeof obj.removedCb === 'function') {
obj.removedCb();
}
}
// Reevaluate isCallFullscreen.
priv.fullScreenItemsChanged()
priv.fullScreenItemsChanged();
}
// Only leave fullscreen mode if our window isn't in fullscreen
// mode already.
// Only leave fullscreen mode if our window isn't in fullscreen mode already.
if (priv.fullScreenItems.length === 0 && priv.windowedVisibility !== Window.Hidden) {
// Simply recall the last visibility state.
visibility = priv.windowedVisibility
visibility = priv.windowedVisibility;
}
}
@ -247,8 +250,17 @@ QtObject {
// When fullScreenItems is changed, we can recompute isCallFullscreen.
onFullScreenItemsChanged: {
isCallFullscreen = fullScreenItems
.filter(o => o.item instanceof OngoingCallPage)
.filter(o => o.item.objectName === "callViewLoader")
.length
isWebFullscreen = WITH_WEBENGINE ? fullScreenItems
.filter(o => o.item && (
o.item.objectName === JamiQmlUtils.webEngineNames.mediaPreview ||
o.item.objectName === JamiQmlUtils.webEngineNames.videoPreview ||
o.item.objectName === JamiQmlUtils.webEngineNames.map ||
o.item.objectName === JamiQmlUtils.webEngineNames.general ||
o.item.objectName === JamiQmlUtils.webEngineNames.emojiPicker
))
.length : 0
}
// Listen for a hangup combined with a fullscreen call state and
@ -258,7 +270,7 @@ QtObject {
function onHasCallChanged() {
if (!CallAdapter.hasCall && isCallFullscreen) {
priv.fullScreenItems.forEach(o => {
if (o.item instanceof OngoingCallPage) {
if (o.item.objectName === "callViewLoader") {
popFullScreenItem(o)
return
}

View File

@ -19,18 +19,15 @@ import QtQuick.Window
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Enums 1.1
import net.jami.Helpers 1.1
import net.jami.Constants 1.1
import "mainview"
import "mainview/components"
import "wizardview"
import "commoncomponents"
import QWindowKit
ApplicationWindow {
@ -40,18 +37,24 @@ ApplicationWindow {
property bool isRTL: UtilsAdapter.isRTL
LayoutMirroring.enabled: isRTL
LayoutMirroring.childrenInherit: isRTL
property var raiseWhenCalled: AppSettingsManager.getValue(Settings.RaiseWhenCalled)
onActiveFocusItemChanged: {
focusOverlay.margin = -5;
if (activeFocusItem && ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason))) {
if (activeFocusItem.focusOnChild) {
focusOverlay.parent = activeFocusItem.parent;
} else if (activeFocusItem.dontShowFocusState) {
focusOverlay.parent = null;
if (activeFocusItem) {
const goodReasonToChangeFocus = activeFocusItem instanceof ItemDelegate || ((activeFocusItem.focusReason === Qt.TabFocusReason) || (activeFocusItem.focusReason === Qt.BacktabFocusReason));
if (goodReasonToChangeFocus) {
if (activeFocusItem.focusOnChild) {
focusOverlay.parent = activeFocusItem.parent;
} else if (activeFocusItem.dontShowFocusState) {
focusOverlay.parent = null;
} else {
if (activeFocusItem.showFocusMargin)
focusOverlay.margin = 0;
focusOverlay.parent = activeFocusItem;
}
} else {
if (activeFocusItem.showFocusMargin)
focusOverlay.margin = 0;
focusOverlay.parent = activeFocusItem;
focusOverlay.parent = null;
}
} else {
focusOverlay.parent = null;
@ -63,7 +66,7 @@ ApplicationWindow {
sourceComponent: GenericErrorsRow {
id: genericError
text: CurrentAccount.enabled ? JamiStrings.noNetworkConnectivity : JamiStrings.disabledAccount
height: visible? JamiTheme.qwkTitleBarHeight : 0
height: visible ? JamiTheme.qwkTitleBarHeight : 0
}
}
@ -87,9 +90,11 @@ ApplicationWindow {
appContainer: fullscreenContainer
}
// Used to manage dynamic view loading and unloading.
property ViewManager viewManager: ViewManager {}
property ViewManager viewManager: ViewManager {
}
// Used to manage the view stack and the current view.
property ViewCoordinator viewCoordinator: ViewCoordinator {}
property ViewCoordinator viewCoordinator: ViewCoordinator {
}
// Used to prevent the window from being visible until the
// window geometry has been restored and the view stack has
@ -199,7 +204,6 @@ ApplicationWindow {
if (useFrameless) {
windowAgent.setup(appWindow);
}
mainViewLoader.active = true;
// Dbus error handler for Linux.
@ -216,10 +220,14 @@ ApplicationWindow {
"confirmLabel": JamiStrings.send,
"rejectLabel": JamiStrings.dontSend,
"textHAlign": Text.AlignLeft,
"textMaxWidth": 400,
"textMaxWidth": 400
});
dlg.accepted.connect(function () {
crashReporter.uploadLastReport();
});
dlg.rejected.connect(function () {
crashReporter.clearReports();
});
dlg.accepted.connect(function () { crashReporter.uploadLastReport(); });
dlg.rejected.connect(function () { crashReporter.clearReports(); });
}
}
@ -289,11 +297,31 @@ ApplicationWindow {
}
}
Connections {
target: UtilsAdapter
function onRaiseWhenCalledChanged() {
raiseWhenCalled = AppSettingsManager.getValue(Settings.RaiseWhenCalled);
}
}
Connections {
target: CallAdapter
function onCallStatusChanged(index, accountId, convUid) {
//If we are starting a call with raiseWhenCalled activated
if (raiseWhenCalled && index === Call.Status.INCOMING_RINGING) {
appWindow.raise();
appWindow.requestActivate();
layoutManager.restoreApp();
}
}
}
Connections {
target: MainApplication
function onAboutToQuit() {
cleanupMainView()
cleanupMainView();
}
function onCloseRequested() {
@ -331,7 +359,7 @@ ApplicationWindow {
});
}
function presentUpdateConfirmInstallDialog(switchToBeta=false) {
function presentUpdateConfirmInstallDialog(switchToBeta = false) {
return viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.updateDialogTitle,
"infoText": switchToBeta ? JamiStrings.confirmBeta : JamiStrings.updateFound,
@ -382,7 +410,7 @@ ApplicationWindow {
presentUpdateInfoDialog(JamiStrings.updateNotFound);
} else {
// Show a dialog describing that an update were found, and offering to install it.
presentUpdateConfirmInstallDialog()
presentUpdateConfirmInstallDialog();
}
}
@ -393,4 +421,20 @@ ApplicationWindow {
}
onClosing: appWindow.close()
// Capture the inputs to the main window while the File Dialog is open
// This is used to mitigate modality issues on Ubuntu 22.04 systems that use wayland.
Loader {
active: JamiQmlUtils.openFileDialogCount > 0
sourceComponent: Popup {
modal: true
visible: true
closePolicy: Popup.NoAutoClose
width: appWindow.width
height: appWindow.height
background: Rectangle {
color: "#80808080" // Semi-transparent grey
}
}
}
}

View File

@ -49,13 +49,13 @@ QtObject {
// right side when not in RTL and should represent the main or content-type view.
readonly property var visibleViews: {
if (!currentView)
return []
return [];
if (isDualPane) {
if (isInSinglePaneMode)
return [currentView.rightPaneItem]
return [currentView.leftPaneItem, currentView.rightPaneItem]
return [currentView.rightPaneItem];
return [currentView.leftPaneItem, currentView.rightPaneItem];
}
return [currentView]
return [currentView];
}
// Aggregate this info and expose it as a single string for convenience.
// JSON indented by 2 spaces.
@ -64,12 +64,12 @@ QtObject {
currentViewName: currentViewName,
isDualPane: isDualPane,
isInSinglePaneMode: isInSinglePaneMode,
visibleViews: visibleViews.map(function(view) {
return view && view.objectName || null;
}),
visibleViewWidths: visibleViews.map(function(view) {
return view && view.width || null;
}),
visibleViews: visibleViews.map(function (view) {
return view && view.objectName || null;
}),
visibleViewWidths: visibleViews.map(function (view) {
return view && view.width || null;
})
};
return JSON.stringify(info, null, 2);
}
@ -96,11 +96,12 @@ QtObject {
}
// Create, present, and return a dialog object.
function presentDialog(parent, path, props = {}) {
function presentDialog(parent, path, props = {}, singleInstance = false) {
// Open the dialog once the object is created
return viewManager.createUniqueView(path, parent, function (obj) {
let createFunc = singleInstance ? viewManager.createView : viewManager.createUniqueView;
return createFunc(path, parent, function (obj, viewName) {
const doneCb = function () {
viewManager.destroyView(path);
viewManager.destroyView(viewName);
};
if (obj.closed !== undefined) {
obj.closed.connect(doneCb);

View File

@ -59,7 +59,7 @@ QtObject {
if (views.hasOwnProperty(viewName)) {
// an instance of the view already exists
if (cb !== null) {
cb(views[viewName])
cb(views[viewName], viewName)
}
return views[viewName]
}
@ -76,7 +76,7 @@ QtObject {
viewName.replace(/^.*[\\\/]/, '').replace(/\.[^/.]+$/, "")
viewPaths[friendlyName] = viewName
if (cb !== null) {
cb(obj)
cb(obj , viewName)
}
return views[viewName]
}
@ -103,6 +103,7 @@ QtObject {
function destroyView(path) {
// The view may already have been destroyed.
if (!views.hasOwnProperty(path)) {
console.warn("View not found:", path, "Available views:", Object.keys(views))
return false
}
views[path].destroy()

View File

@ -22,8 +22,11 @@
#include "systemtray.h"
#include "lrcinstance.h"
#include "accountlistmodel.h"
#include "wizardviewstepmodel.h"
#include "global.h"
#include "api/account.h"
#include <QtConcurrent/QtConcurrent>
#include <QThreadPool>
AccountAdapter::AccountAdapter(AppSettingsManager* settingsManager,
SystemTray* systemTray,
@ -111,7 +114,10 @@ AccountAdapter::createJamiAccount(const QVariantMap& settings)
&lrcInstance_->accountModel(),
&lrc::api::AccountModel::accountAdded,
[this, registeredName, settings](const QString& accountId) {
lrcInstance_->accountModel().setAvatar(accountId, settings["avatar"].toString(), true,1);
lrcInstance_->accountModel().setAvatar(accountId,
settings["avatar"].toString(),
true,
1);
Utils::oneShotConnect(&lrcInstance_->accountModel(),
&lrc::api::AccountModel::accountDetailsChanged,
[this](const QString& accountId) {
@ -159,8 +165,9 @@ AccountAdapter::createJamiAccount(const QVariantMap& settings)
connectFailure();
auto futureResult = QtConcurrent::run([this, settings] {
QThreadPool::globalInstance()->start([this, settings] {
lrcInstance_->accountModel().createNewAccount(lrc::api::profile::Type::JAMI,
{},
settings["alias"].toString(),
settings["archivePath"].toString(),
settings["password"].toString(),
@ -206,14 +213,14 @@ AccountAdapter::createSIPAccount(const QVariantMap& settings)
connectFailure();
auto futureResult = QtConcurrent::run([this, settings] {
QThreadPool::globalInstance()->start([this, settings] {
lrcInstance_->accountModel().createNewAccount(lrc::api::profile::Type::SIP,
{},
settings["alias"].toString(),
settings["archivePath"].toString(),
"",
"",
settings["username"].toString(),
{});
settings["username"].toString());
});
}
@ -250,7 +257,7 @@ AccountAdapter::createJAMSAccount(const QVariantMap& settings)
connectFailure();
auto futureResult = QtConcurrent::run([this, settings] {
QThreadPool::globalInstance()->start([this, settings] {
lrcInstance_->accountModel().connectToAccountManager(settings["username"].toString(),
settings["password"].toString(),
settings["manager"].toString());
@ -293,7 +300,7 @@ AccountAdapter::setCurrAccDisplayName(const QString& text)
void
AccountAdapter::setCurrentAccountAvatarFile(const QString& source)
{
auto futureResult = QtConcurrent::run([this, source]() {
QThreadPool::globalInstance()->start([this, source]() {
QPixmap image;
if (!image.load(source)) {
qWarning() << "Not a valid image file";
@ -308,7 +315,7 @@ AccountAdapter::setCurrentAccountAvatarFile(const QString& source)
void
AccountAdapter::setCurrentAccountAvatarBase64(const QString& data)
{
auto futureResult = QtConcurrent::run([this, data]() {
QThreadPool::globalInstance()->start([this, data]() {
auto accountId = lrcInstance_->get_currentAccountId();
lrcInstance_->accountModel().setAvatar(accountId, data, true, 1);
});
@ -339,9 +346,73 @@ AccountAdapter::exportToFile(const QString& accountId,
void
AccountAdapter::setArchivePasswordAsync(const QString& accountID, const QString& password)
{
auto futureResult = QtConcurrent::run([this, accountID, password] {
QThreadPool::globalInstance()->start([this, accountID, password] {
auto config = lrcInstance_->accountModel().getAccountConfig(accountID);
config.archivePassword = password;
lrcInstance_->accountModel().setAccountConfig(accountID, config);
});
}
void
AccountAdapter::startImportAccount()
{
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::INIT);
wizardModel->set_deviceLinkDetails({});
// This will create an account with the ARCHIVE_URL configured to start the import process.
importAccountId_ = lrcInstance_->accountModel().createDeviceImportAccount();
}
void
AccountAdapter::provideAccountAuthentication(const QString& password)
{
if (importAccountId_.isEmpty()) {
qWarning() << "No import account to provide password to";
return;
}
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::IN_PROGRESS);
Utils::oneShotConnect(
&lrcInstance_->accountModel(),
&lrc::api::AccountModel::accountAdded,
[this](const QString& accountId) {
Q_EMIT lrcInstance_->accountListChanged();
Q_EMIT accountAdded(accountId,
lrcInstance_->accountModel().getAccountList().indexOf(accountId));
},
this,
&AccountAdapter::accountCreationFailed);
connectFailure();
QThreadPool::globalInstance()->start([this, password] {
lrcInstance_->accountModel().provideAccountAuthentication(importAccountId_, password);
});
}
QString
AccountAdapter::getImportErrorMessage(QVariantMap details)
{
QString errorString = details.value("error").toString();
if (!errorString.isEmpty() && errorString != "none") {
auto error = lrc::api::account::mapLinkDeviceError(errorString.toStdString());
return lrc::api::account::getLinkDeviceString(error);
}
return "";
}
void
AccountAdapter::cancelImportAccount()
{
auto wizardModel = qApp->property("WizardViewStepModel").value<WizardViewStepModel*>();
wizardModel->set_deviceAuthState(lrc::api::account::DeviceAuthState::INIT);
wizardModel->set_deviceLinkDetails({});
// Remove the account if it was created
lrcInstance_->accountModel().removeAccount(importAccountId_);
importAccountId_.clear();
}

View File

@ -81,6 +81,13 @@ public:
const bool& state);
Q_INVOKABLE QStringList getDefaultModerators(const QString& accountId);
// New import account / link device functions
// import: (note: Listen for: DeviceAuthStateChanged)
Q_INVOKABLE void startImportAccount();
Q_INVOKABLE void provideAccountAuthentication(const QString& password = {});
Q_INVOKABLE QString getImportErrorMessage(QVariantMap details);
Q_INVOKABLE void cancelImportAccount();
Q_SIGNALS:
// Trigger other components to reconnect account related signals.
void accountStatusChanged(QString accountId);
@ -98,6 +105,9 @@ private:
QMetaObject::Connection registeredNameSavedConnection_;
// The account ID of the last used import account.
QString importAccountId_;
AppSettingsManager* settingsManager_;
SystemTray* systemTray_;
};

View File

@ -34,8 +34,12 @@ AppSettingsManager::AppSettingsManager(QObject* parent)
{
for (int i = 0; i < static_cast<int>(Settings::Key::COUNT__); ++i) {
auto key = static_cast<Settings::Key>(i);
if (!settings_->contains(Settings::toString(key)))
setValue(key, Settings::defaultValue(key));
auto strKey= Settings::toString(key);
// If the setting is written in the settings file and is equal to the default value,
// remove it from the settings file.
// This allow us to change default values without risking to remove user settings
if ((settings_->contains(strKey)) && (settings_->value(strKey) == Settings::defaultValue(key)))
settings_->remove(strKey);
}
}

View File

@ -63,6 +63,8 @@ extern const QString defaultDownloadPath;
X(WindowState, QWindow::AutomaticVisibility) \
X(EnableExperimentalSwarm, false) \
X(LANG, "SYSTEM") \
X(SpellLang, {}) \
X(EnableSpellCheck, true) \
X(PluginStoreEndpoint, "https://plugins.jami.net") \
X(PositionShareDuration, 15) \
X(PositionShareLimit, true) \
@ -74,7 +76,8 @@ extern const QString defaultDownloadPath;
X(PttKeys, 32) \
X(UseFramelessWindow, USE_FRAMELESS_WINDOW_DEFAULT) \
X(EnableCrashReporting, true) \
X(EnableAutomaticCrashReporting, false)
X(EnableAutomaticCrashReporting, false) \
X(RaiseWhenCalled, false)
#if APPSTORE
#define KEYS COMMON_KEYS
#else

View File

@ -18,7 +18,7 @@
#include "appversionmanager.h"
#include "lrcinstance.h"
#include "version.h"
#include "version_info.h"
#include <QProcess>
#include <QTimer>
@ -73,14 +73,14 @@ struct AppVersionManager::Impl : public QObject
Q_EMIT parent_.updateCheckReplyReceived(false);
return;
}
auto currentVersion = QString(VERSION_STRING).toULongLong();
auto currentVersion = BUILD_VERSION_STRING.toULongLong();
auto latestVersion = latestVersionString.toULongLong();
const QString channelStr = isBeta ? "beta" : "stable";
const auto newVersionFound = latestVersion > currentVersion;
qInfo().noquote() << "--------- Version info ------------"
<< QString("\n - Current: %1 (%2)").arg(currentVersion).arg(channelStr);
qInfo().noquote() << "--------- Version info ------------";
qInfo().noquote() << QString("\tCurrent: \t%1 (%2)").arg(currentVersion).arg(channelStr);
if (newVersionFound) {
qDebug() << " - Latest: " << latestVersion;
qInfo().noquote() << QString("\tLatest: \t%1").arg(latestVersion);
Q_EMIT parent_.updateCheckReplyReceived(true, true);
} else if (!quiet) {
Q_EMIT parent_.updateCheckReplyReceived(true, false);

View File

@ -345,9 +345,11 @@ AvAdapter::shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned heig
}
void
AvAdapter::shareWindow(const QString& windowProcessId, const QString& windowId)
AvAdapter::shareWindow(const QString& windowProcessId, const QString& windowId, const int fps)
{
auto resource = lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId, windowId);
auto resource = lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId,
windowId,
fps);
auto callId = lrcInstance_->getCurrentCallId();
muteCamera_ = !isCapturing();
@ -356,7 +358,10 @@ AvAdapter::shareWindow(const QString& windowProcessId, const QString& windowId)
}
QString
AvAdapter::getSharingResource(int screenId, const QString& windowProcessId, const QString& windowId)
AvAdapter::getSharingResource(int screenId,
const QString& windowProcessId,
const QString& windowId,
const int fps)
{
if (screenId == -1) {
const auto arrangementRect = getAllScreensBoundingRect();
@ -387,7 +392,7 @@ AvAdapter::getSharingResource(int screenId, const QString& windowProcessId, cons
rect.height()
* screen->devicePixelRatio());
} else if (!windowId.isEmpty()) {
return lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId, windowId);
return lrcInstance_->getCurrentCallModel()->getDisplay(windowProcessId, windowId, fps);
}
return "";

View File

@ -96,7 +96,9 @@ protected:
Q_INVOKABLE void shareScreenArea(unsigned x, unsigned y, unsigned width, unsigned height);
// Select window to display (all platforms except Wayland).
Q_INVOKABLE void shareWindow(const QString& windowProcessId, const QString& windowId);
Q_INVOKABLE void shareWindow(const QString& windowProcessId,
const QString& windowId,
const int fps = -1);
#ifdef Q_OS_LINUX
// Share a window on Wayland.
@ -110,7 +112,8 @@ protected:
// Returns the screensharing resource
Q_INVOKABLE QString getSharingResource(int screenId = -2,
const QString& windowProcessId = "",
const QString& key = "");
const QString& key = "",
const int fps = -1);
Q_INVOKABLE void getListWindows();

View File

@ -22,6 +22,7 @@
#include "lrcinstance.h"
#include <QImage>
#include <QRegularExpression>
class AsyncAvatarImageResponseRunnable : public AsyncImageResponseRunnable
{
@ -69,6 +70,16 @@ public:
image = Utils::accountPhoto(lrcInstance_, imageId, requestedSize_);
} else if (type == "contact") {
image = Utils::contactPhoto(lrcInstance_, imageId, requestedSize_);
} else if (type == "temporaryAccount") {
// Check if imageId is a SHA-1 hash (jamiId or registered name)
static const QRegularExpression sha1Pattern("^[0-9a-fA-F]{40}$");
if (sha1Pattern.match(imageId).hasMatch()) {
// If we only have a jamiId use default avatar
image = Utils::fallbackAvatar("jami:" + imageId, QString(), requestedSize_);
} else {
// For registered usernames, use fallbackAvatar avatar with the name
image = Utils::fallbackAvatar(QString(), imageId, requestedSize_);
}
} else {
qWarning() << Q_FUNC_INFO << "Missing valid prefix in the image url";
return;

View File

@ -249,7 +249,7 @@ CallAdapter::onCallEnded(const QString& callId)
}
void
CallAdapter::onCallStatusChanged(const QString& callId, int code)
CallAdapter::onCallStatusChanged(const QString& accountId, const QString& callId, int code)
{
Q_UNUSED(code)
@ -468,11 +468,14 @@ CallAdapter::onShowIncomingCallView(const QString& accountId, const QString& con
showNotification(accountId, convInfo.uid);
return;
}
if (!accountProperties.denySecondCall) {
lrcInstance_->selectConversation(convInfo.uid, accountId);
}
} else {
// finally, in this case, the conversation isn't selected yet
// and there are no other special conditions, so just select the conversation
lrcInstance_->selectConversation(convInfo.uid, accountId);
}
// finally, in this case, the conversation isn't selected yet
// and there are no other special conditions, so just select the conversation
lrcInstance_->selectConversation(convInfo.uid, accountId);
}
void
@ -563,7 +566,7 @@ CallAdapter::connectCallModel(const QString& accountId)
connect(accInfo.callModel.get(),
&CallModel::callStatusChanged,
this,
QOverload<const QString&, int>::of(&CallAdapter::onCallStatusChanged),
QOverload<const QString&, const QString&, int>::of(&CallAdapter::onCallStatusChanged),
Qt::UniqueConnection);
connect(accInfo.callModel.get(),

View File

@ -118,7 +118,7 @@ public Q_SLOTS:
void onShowCallView(const QString& accountId, const QString& convUid);
void onAccountChanged();
void onCallStatusChanged(const QString& accountId, const QString& callId);
void onCallStatusChanged(const QString& callId, int code);
void onCallStatusChanged(const QString& accountId, const QString& callId, int code);
void onCallAddedToConference(const QString& callId, const QString& conversationId, const QString& confId);
void onCallStarted(const QString& callId);
void onCallEnded(const QString& callId);

View File

@ -135,7 +135,7 @@ PendingConferenceesListModel::connectSignals()
callsStatusChanged_ = connect(currentCallModel,
&CallModel::callStatusChanged,
this,
[this](const QString&, int) {
[this](const QString&, const QString&, int) {
Q_EMIT dataChanged(index(0, 0),
index(rowCount() - 1),
{Role::CallStatus});
@ -401,6 +401,16 @@ CallOverlayModel::eventFilter(QObject* object, QEvent* event)
}
}
}
// Tab or BackTab key events should trigger a signal that we can use to
// prevent the overlay from fading and to allow the user to navigate
// through the controls.
if (event->type() == QEvent::KeyPress && (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Tab)
|| (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Backtab)) {
Q_EMIT focusKeyPressed();
// Don't absorb the event so that the focus can be changed
// to the next or previous control.
return false;
}
#ifndef HAVE_GLOBAL_PTT
else if (event->type() == QEvent::KeyPress && listener_->getPttState()) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);

View File

@ -140,6 +140,7 @@ public:
Q_SIGNALS:
void mouseMoved(QQuickItem* item);
void focusKeyPressed();
void pttKeyPressed();
void pttKeyReleased();

View File

@ -28,7 +28,8 @@ Item {
enum Mode {
Account,
Contact,
Conversation
Conversation,
TemporaryAccount
}
property int mode: Avatar.Mode.Account
property alias sourceSize: image.sourceSize
@ -45,6 +46,8 @@ Item {
return 'contact';
case Avatar.Mode.Conversation:
return 'conversation';
case Avatar.Mode.TemporaryAccount:
return 'temporaryAccount';
}
}

View File

@ -56,11 +56,11 @@ Popup {
id: container
property color color: JamiTheme.secondaryBackgroundColor
leftPadding: popupMargins
bottomPadding: action1.visible || action2.visible ? 10 :popupMargins
bottomPadding: action1.visible || action2.visible ? 10 : popupMargins
background: Rectangle {
id: bgRect
radius: 5
color: container.color
layer.enabled: true
@ -78,8 +78,10 @@ Popup {
contentItem: ColumnLayout {
id: contentLayout
JamiPushButton {
JamiPushButton { QWKSetParentHitTestVisible {}
id: closeButton
Accessible.role: Accessible.Button
Accessible.name: JamiStrings.close
visible: closeButtonVisible
@ -99,6 +101,7 @@ Popup {
Label {
id: titleText
Layout.leftMargin: popupMargins
Layout.rightMargin: popupMargins
Layout.bottomMargin: 20
Layout.topMargin: closeButtonVisible ? 0 : 30
@ -115,9 +118,9 @@ Popup {
id: flickable
Layout.fillHeight: true
Layout.preferredHeight: Math.min(contentHeight, root.height)
Layout.preferredWidth: contentItem.childrenRect.width
Layout.preferredWidth: contentItem.childrenRect.width + ScrollBar.vertical.width
Layout.leftMargin: popupMargins
Layout.rightMargin: popupMargins
Layout.alignment: Qt.AlignCenter
@ -126,11 +129,13 @@ Popup {
contentItem.children: Loader {
id: containerSubContentLoader
}
ScrollBar.horizontal.visible: false
}
DialogButtonBox {
id: buttonBox
Layout.alignment: Qt.AlignRight
spacing: 1.5
@ -179,7 +184,7 @@ Popup {
color: JamiTheme.transparentColor
// Color animation for overlay when pop up is shown.
ColorAnimation on color {
ColorAnimation on color {
to: JamiTheme.popupOverlayColor
duration: 500
}

View File

@ -23,12 +23,12 @@ import net.jami.Adapters 1.1
import net.jami.Constants 1.1
SBSMessageBase {
id: root
id: rootDelegate
property var confId: ConfId
property var currentCallId: CurrentCall.id
component JoinCallButton: MaterialButton {
visible: root.isActive && root.currentCallId !== root.confId
visible: rootDelegate.isActive && rootDelegate.currentCallId !== rootDelegate.confId
toolTipText: JamiStrings.joinCall
color: JamiTheme.blackColor
background.opacity: hovered ? 0.2 : 0.1
@ -40,6 +40,20 @@ SBSMessageBase {
textRightPadding: 9
}
Accessible.role: Accessible.StaticText
Accessible.name: {
let name = isOutgoing ? JamiStrings.inReplyToYou : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
return name + ": " + callLabel.text + " " + formattedDay;
}
Accessible.description: {
let status = "";
if (bubble.isEdited)
status += JamiStrings.edited + " ";
return status + (readers.length > 0 ? JamiStrings.readBy + " " + readers.map(function (uri) {
return UtilsAdapter.getBestNameForUri(CurrentAccount.id, uri);
}).join(", ") : "");
}
property bool isRemoteImage
isOutgoing: Author === CurrentAccount.uri
@ -48,17 +62,17 @@ SBSMessageBase {
formattedTime: MessagesAdapter.getFormattedTime(Timestamp)
bubble.border.color: CurrentConversation.color
bubble.border.width: root.isActive ? 1.5 : 0
bubble.border.width: rootDelegate.isActive ? 1.5 : 0
bubble.color: JamiTheme.messageInBgColor
bubble.opacity: 1
Connections {
target: CurrentConversation
enabled: root.isActive
enabled: rootDelegate.isActive
function onActiveCallsChanged() {
root.isActive = LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1;
if (root.isActive) {
rootDelegate.isActive = LRCInstance.indexOfActiveCall(rootDelegate.confId, ActionUri, DeviceId) !== -1;
if (rootDelegate.isActive) {
bubble.mask.border.color = CurrentConversation.color;
bubble.mask.border.width = 1.5;
bubble.mask.z = -2;
@ -66,8 +80,8 @@ SBSMessageBase {
}
}
property bool isActive: LRCInstance.indexOfActiveCall(root.confId, ActionUri, DeviceId) !== -1
visible: isActive || root.confId === "" || Duration > 0
property bool isActive: LRCInstance.indexOfActiveCall(rootDelegate.confId, ActionUri, DeviceId) !== -1
visible: isActive || rootDelegate.confId === "" || Duration > 0
property var baseColor: JamiTheme.messageInBgColor
@ -76,7 +90,7 @@ SBSMessageBase {
id: msg
anchors.right: isOutgoing ? parent.right : undefined
spacing: 10
visible: root.visible
visible: rootDelegate.visible
Image {
id: statusIcon
@ -84,10 +98,10 @@ SBSMessageBase {
width: 10
height: 10
verticalAlignment: Qt.AlignVCenter
visible: !root.isActive
visible: !rootDelegate.isActive
source: {
if (root.isOutgoing) {
if (rootDelegate.isOutgoing) {
if (Duration > 0)
return "qrc:/icons/outgoing-call.svg";
else
@ -104,12 +118,11 @@ SBSMessageBase {
effect: ColorOverlay {
color: {
if (Duration > 0)
return UtilsAdapter.luma(root.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
return JamiTheme.redColor
return UtilsAdapter.luma(rootDelegate.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
return JamiTheme.redColor;
}
}
}
}
Text {
@ -120,11 +133,11 @@ SBSMessageBase {
bottomPadding: 8
Layout.fillWidth: true
Layout.rightMargin: root.isActive && root.currentCallId !== root.confId ? 0 : root.timeWidth + 16
Layout.leftMargin: root.isActive ? 10 : -5 /* spacing is 10 and we want 5px with icon */
Layout.rightMargin: rootDelegate.isActive && rootDelegate.currentCallId !== rootDelegate.confId ? 0 : rootDelegate.timeWidth + 16
Layout.leftMargin: rootDelegate.isActive ? 10 : -5 /* spacing is 10 and we want 5px with icon */
text: {
if (root.isActive)
if (rootDelegate.isActive)
return JamiStrings.startedACall;
return Body;
}
@ -136,7 +149,7 @@ SBSMessageBase {
renderType: Text.NativeRendering
textFormat: Text.MarkdownText
color: UtilsAdapter.luma(root.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
color: UtilsAdapter.luma(rootDelegate.baseColor) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
}
JoinCallButton {
@ -146,7 +159,7 @@ SBSMessageBase {
Layout.bottomMargin: 4
text: JamiStrings.joinWithAudio
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId, true)
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, rootDelegate.confId, true)
}
JoinCallButton {
@ -156,20 +169,20 @@ SBSMessageBase {
Layout.topMargin: 4
Layout.bottomMargin: 4
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, root.confId)
onClicked: MessagesAdapter.joinCall(ActionUri, DeviceId, rootDelegate.confId)
Layout.rightMargin: 4
}
}
]
opacity: 0
Behavior on opacity {
Behavior on opacity {
NumberAnimation {
duration: 100
}
}
Component.onCompleted: {
bubble.timestampItem.visible = !root.isActive || root.currentCallId === root.confId;
bubble.timestampItem.visible = !rootDelegate.isActive || rootDelegate.currentCallId === rootDelegate.confId;
opacity = 1;
}
}

View File

@ -21,8 +21,8 @@ import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
Column {
id: root
Control {
id: rootDelegate
property bool showTime: false
property bool showDay: false
@ -36,21 +36,41 @@ Column {
height: timestampItem.height + textLabel.height
spacing: 0
Item {
Accessible.name: {
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
return name + ": " + Body + " " + formattedTime + " " + formattedDay;
}
Accessible.description: {
let status = "";
if (IsLastSent)
status += JamiStrings.sent + " ";
return status;
}
background: Rectangle {
id: focusIndicator
visible: rootDelegate.activeFocus
border.color: JamiTheme.tintedBlue
border.width: 2
radius: 10
color: "transparent"
z: 1
}
contentItem: Item {
anchors.horizontalCenter: parent.horizontalCenter
height: timestampItem.height + textLabel.height
TimestampInfo {
id: timestampItem
showDay: root.showDay
showTime: root.showTime
formattedTime: root.formattedTime
formattedDay: root.formattedDay
showDay: rootDelegate.showDay
showTime: rootDelegate.showTime
formattedTime: rootDelegate.formattedTime
formattedDay: rootDelegate.formattedDay
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
}
Label {
@ -67,7 +87,7 @@ Column {
}
}
opacity: 0
Behavior on opacity {
Behavior on opacity {
NumberAnimation {
duration: 100
}

View File

@ -24,20 +24,32 @@ import net.jami.Constants 1.1
import net.jami.Adapters 1.1
Loader {
id: root
id: rootDelegate
property var mediaInfo
property bool showTime
property bool showDay
property int timestamp: Timestamp
property string formattedTime: MessagesAdapter.getFormattedTime(root.timestamp)
property string formattedDay: MessagesAdapter.getFormattedDay(root.timestamp)
property string formattedTime: MessagesAdapter.getFormattedTime(rootDelegate.timestamp)
property string formattedDay: MessagesAdapter.getFormattedDay(rootDelegate.timestamp)
property int seq: MsgSeq.single
property string author: Author
property string body: Body
property var tid: TID
property int transferStatus: TransferStatus
Accessible.name: {
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
return JamiStrings.dataTransfer + name + ": " + JamiStrings.status + TransferStatus + Body + " " + formattedTime + " " + formattedDay;
}
Accessible.description: {
let status = "";
if (IsLastSent)
status += JamiStrings.sent + " ";
return status;
}
onTidChanged: {
if (tid === "") {
sourceComponent = deletedMsgComp;
@ -48,7 +60,7 @@ Loader {
sourceComponent = deletedMsgComp;
return;
} else if (transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED) {
mediaInfo = MessagesAdapter.getMediaInfo(root.body);
mediaInfo = MessagesAdapter.getMediaInfo(rootDelegate.body);
if (Object.keys(mediaInfo).length !== 0 && WITH_WEBENGINE) {
sourceComponent = localMediaMsgComp;
return;
@ -74,13 +86,13 @@ Loader {
id: deletedItem
isOutgoing: Author === CurrentAccount.uri
showTime: root.showTime
seq: root.seq
showTime: rootDelegate.showTime
seq: rootDelegate.seq
author: Author
readers: Readers
timestamp: root.timestamp
formattedTime: root.formattedTime
formattedDay: root.formattedTime
timestamp: rootDelegate.timestamp
formattedTime: rootDelegate.formattedTime
formattedDay: rootDelegate.formattedTime
extraHeight: 0
textContentWidth: textEditId.width
textContentHeight: textEditId.height
@ -93,7 +105,7 @@ Loader {
bottomPadding: 6
topPadding: 6
leftPadding: 10
text: UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMedia
text: JamiStrings.deletedMedia.arg(UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author))
horizontalAlignment: Text.AlignLeft
width: Math.min((2 / 3) * parent.width, implicitWidth + 18, innerContent.width - senderMargin + 18)
@ -122,21 +134,35 @@ Loader {
id: dataTransferItem
transferId: Id
property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
property bool canOpen: root.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
property real maxMsgWidth: root.width - senderMargin - 2 * hPadding - avatarBlockWidth - buttonsLoader.width - 24 - 6 - 24
property var transferStats: MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus)
property bool canOpen: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_FINISHED || isOutgoing
property real maxMsgWidth: rootDelegate.width - senderMargin - 2 * hPadding - avatarBlockWidth - buttonsLoader.width - 24 - 6 - 24
// Timer to update the translation bar
Loader {
id: timerLoader
active: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
sourceComponent: Timer {
interval: 1000 // Update every second
running: true
repeat: true
onTriggered: {
transferStats = MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus);
}
}
}
isOutgoing: Author === CurrentAccount.uri
showTime: root.showTime
seq: root.seq
showTime: rootDelegate.showTime
seq: rootDelegate.seq
author: Author
location: Body
transferName: TransferName
readers: Readers
timestamp: root.timestamp
formattedTime: root.formattedTime
formattedDay: root.formattedTime
extraHeight: progressBar.visible ? 18 : 0
timestamp: rootDelegate.timestamp
formattedTime: rootDelegate.formattedTime
formattedDay: rootDelegate.formattedTime
extraHeight: progressBar.visible ? 25 : 0
innerContent.children: [
RowLayout {
@ -164,7 +190,7 @@ Loader {
Layout.margins: 8
sourceComponent: {
switch (root.transferStatus) {
switch (rootDelegate.transferStatus) {
case Interaction.TransferStatus.TRANSFER_CREATED:
case Interaction.TransferStatus.TRANSFER_FINISHED:
iconSource = JamiResources.link_black_24dp_svg;
@ -211,10 +237,11 @@ Loader {
normalColor: JamiTheme.chatviewBgColor
imageColor: JamiTheme.chatviewButtonColor
onClicked: {
if (root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
return MessagesAdapter.cancelFile(transferId);
if (rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING) {
MessagesAdapter.cancelFile(transferId);
} else {
return MessagesAdapter.acceptFile(transferId);
buttonsLoader.iconSource = JamiResources.connecting_black_24dp_svg;
MessagesAdapter.acceptFile(transferId);
}
}
}
@ -272,7 +299,7 @@ Loader {
ProgressBar {
id: progressBar
visible: root.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
visible: rootDelegate.transferStatus === Interaction.TransferStatus.TRANSFER_ONGOING
height: visible * implicitHeight
value: transferStats.progress / transferStats.totalSize
width: transferItem.width
@ -290,15 +317,15 @@ Loader {
isOutgoing: Author === CurrentAccount.uri
transferId: Id
property var transferStats: MessagesAdapter.getTransferStats(transferId, root.transferStatus)
showTime: root.showTime
seq: root.seq
property var transferStats: MessagesAdapter.getTransferStats(transferId, rootDelegate.transferStatus)
showTime: rootDelegate.showTime
seq: rootDelegate.seq
author: Author
location: Body
transferName: TransferName
readers: Readers
formattedTime: MessagesAdapter.getFormattedTime(root.timestamp)
formattedDay: MessagesAdapter.getFormattedDay(root.timestamp)
formattedTime: MessagesAdapter.getFormattedTime(rootDelegate.timestamp)
formattedDay: MessagesAdapter.getFormattedDay(rootDelegate.timestamp)
property real contentWidth

View File

@ -44,10 +44,9 @@ BaseModalDialog {
button2.text: JamiStrings.optionCancel
button2Role: DialogButtonBox.RejectRole
button2.onClicked: close();
button2.onClicked: close()
button1.contentColorProvider: JamiTheme.deleteRedButton
BusyIndicator {
id: busyInd
running: false
@ -68,7 +67,7 @@ BaseModalDialog {
id: labelDeletion
Layout.alignment: Qt.AlignLeft
Layout.maximumWidth: root.width - 4*JamiTheme.preferredMarginSize
Layout.maximumWidth: root.width - 4 * JamiTheme.preferredMarginSize
Layout.bottomMargin: 5
color: JamiTheme.textColor
@ -238,14 +237,14 @@ BaseModalDialog {
radius: 5
RowLayout{
RowLayout {
id: warningLayout
anchors.centerIn: parent
anchors.margins: 15
width: parent.width
Image{
Image {
id: warningIcon
Layout.fillWidth: true
@ -261,7 +260,7 @@ BaseModalDialog {
Layout.fillWidth: true
Layout.margins: 15
text: JamiStrings.deleteAccountInfos
text: JamiStrings.deleteAccountInfo
font.pointSize: JamiTheme.textFontSize
font.kerning: true

View File

@ -0,0 +1,370 @@
/*
* Copyright (C) 2025 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Qt5Compat.GraphicalEffects
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import "../mainview/components"
import "../settingsview/components"
import SortFilterProxyModel 0.2
// Search bar for filtering dictionaries
ColumnLayout {
id: root
spacing: 0
property int checkBoxWidth: 24
Component.onCompleted: Qt.callLater(dictionarySearchBar.setTextAreaFocus)
RowLayout {
id: headerLayout
width: parent.width
Layout.preferredHeight: childrenRect.height
// Header title
Searchbar {
id: dictionarySearchBar
focus: true
Layout.fillWidth: true
Layout.preferredHeight: 55
placeHolderText: JamiStrings.searchTextLanguages
Accessible.name: JamiStrings.searchTextLanguages
Accessible.role: Accessible.EditableText
Accessible.description: JamiStrings.searchAvailableTextLanguages
onSearchBarTextChanged: function (text) {
dictionaryProxyModel.combinedFilterPattern = text;
dictionaryProxyModel.invalidate();
}
}
Label {
text: JamiStrings.showInstalledDictionaries
color: JamiTheme.faddedLastInteractionFontColor
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
Layout.rightMargin: 0
Layout.preferredHeight: 16
Layout.alignment: Qt.AlignVCenter
}
// Checkbox to filter installed dictionaries
CheckBox {
id: showInstalledOnlyCheckbox
Accessible.name: JamiStrings.showInstalledDictionaries
Accessible.role: Accessible.CheckBox
Accessible.description: JamiStrings.showInstalledDictionariesDescription
checked: false
indicator: Image {
anchors.centerIn: parent
layer {
enabled: true
effect: ColorOverlay {
color: JamiTheme.tintedBlue
}
mipmap: false
smooth: true
}
width: checkBoxWidth
height: checkBoxWidth
source: showInstalledOnlyCheckbox.checked ? JamiResources.check_box_24dp_svg : JamiResources.check_box_outline_blank_24dp_svg
}
Layout.preferredWidth: 55
Layout.preferredHeight: 55
Layout.rightMargin: 0
}
}
// Connect to listen for download failure and pop a simple dialog to inform the user
Connections {
target: SpellCheckAdapter
function onDownloadFailed(locale) {
viewCoordinator.presentDialog(appWindow, "commoncomponents/SimpleMessageDialog.qml", {
"title": JamiStrings.error,
"infoText": JamiStrings.spellCheckDownloadFailed.arg(locale),
"buttonTitles": [JamiStrings.optionOk],
"buttonStyles": [SimpleMessageDialog.ButtonStyle.TintedBlue],
"buttonRoles": [DialogButtonBox.AcceptRole]
});
}
}
JamiListView {
id: spellCheckDictionaryListView
width: parent.width
Layout.fillHeight: true
model: SortFilterProxyModel {
id: dictionaryProxyModel
sourceModel: SpellCheckAdapter.getDictionaryListModel()
property string combinedFilterPattern
filters: AllOf {
AnyOf {
// Filter by dictionary name
RegExpFilter {
roleName: "Locale"
pattern: dictionaryProxyModel.combinedFilterPattern
caseSensitivity: Qt.CaseInsensitive
}
// Filter by native name
RegExpFilter {
roleName: "NativeName"
pattern: dictionaryProxyModel.combinedFilterPattern
caseSensitivity: Qt.CaseInsensitive
}
}
ValueFilter {
roleName: "Installed"
value: true
enabled: showInstalledOnlyCheckbox.checked
}
}
sorters: [
// Sort by locale alphabetically
RoleSorter {
roleName: "Locale"
sortOrder: Qt.AscendingOrder
}
]
}
readonly property int itemMargins: 20
topMargin: itemMargins / 2
bottomMargin: itemMargins / 2
spacing: 8
clip: true
delegate: ItemDelegate {
id: dictionaryDelegate
width: spellCheckDictionaryListView.width
height: Math.max(JamiTheme.preferredFieldHeight, contentLayout.implicitHeight + 32)
background: Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - spellCheckDictionaryListView.itemMargins
height: parent.height
color: JamiTheme.backgroundColor
radius: JamiTheme.primaryRadius
border.color: "transparent"
border.width: 1
}
RowLayout {
id: contentLayout
anchors.fill: parent
anchors.margins: 16
spacing: 16
// Dictionary info
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 16
spacing: 2
Text {
id: dictionaryName
Layout.fillWidth: true
text: model.NativeName || ""
color: JamiTheme.textColor
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
font.weight: Font.Medium
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
Text {
id: dictionaryLocale
Layout.fillWidth: true
text: model.Locale || ""
color: JamiTheme.faddedLastInteractionFontColor
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 2
elide: Text.ElideRight
visible: text !== ""
verticalAlignment: Text.AlignVCenter
}
}
// Installation status and action
Item {
Layout.preferredWidth: 100
Layout.preferredHeight: 32
Layout.alignment: Qt.AlignVCenter
Layout.rightMargin: 16
// Install button for available dictionaries
MaterialButton {
id: installButton
anchors.centerIn: parent
width: 100
height: 32
Accessible.name: dictionaryName.text + " " + JamiStrings.install
Accessible.role: Accessible.Button
text: JamiStrings.install
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 1
font.weight: Font.Medium
focusPolicy: Qt.StrongFocus
KeyNavigation.tab: {
try {
if (model.index < dictionaryProxyModel.count - 1) {
var nextItem = spellCheckDictionaryListView.itemAtIndex(model.index + 1);
if (nextItem) {
var nextButton = nextItem.findChild("installButton") || nextItem.findChild("uninstallButton");
return nextButton || null;
}
}
} catch (e) {
console.debug("KeyNavigation error handled:", e);
}
return null;
}
onFocusChanged: {
if (focus) {
spellCheckDictionaryListView.positionViewAtIndex(model.index, ListView.Contain);
}
}
onClicked: {
if (model.Locale) {
SpellCheckAdapter.installDictionary(model.Locale);
}
}
visible: !model.Downloading && !model.Installed && model.Locale !== undefined && model.Locale !== ""
}
// Uninstall button for installed dictionaries (not system dictionaries)
MaterialButton {
id: uninstallButton
anchors.centerIn: parent
width: 100
height: 32
Accessible.name: dictionaryName.text + " " + JamiStrings.uninstall
Accessible.role: Accessible.Button
text: JamiStrings.uninstall
color: "#ff6666"
hoveredColor: "#ff9999"
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 1
font.weight: Font.Medium
focusPolicy: Qt.StrongFocus
KeyNavigation.tab: {
try {
if (model.index < dictionaryProxyModel.count - 1) {
var nextItem = spellCheckDictionaryListView.itemAtIndex(model.index + 1);
if (nextItem) {
var nextButton = nextItem.findChild("installButton") || nextItem.findChild("uninstallButton");
return nextButton || null;
}
}
} catch (e) {
console.debug("KeyNavigation error handled:", e);
}
return null;
}
onFocusChanged: {
if (focus) {
spellCheckDictionaryListView.positionViewAtIndex(model.index, ListView.Contain);
}
}
onClicked: {
if (model.Locale) {
SpellCheckAdapter.uninstallDictionary(model.Locale);
}
}
visible: !model.Downloading && model.Installed && !model.IsSystem && model.Locale !== undefined && model.Locale !== ""
}
// System dictionary indicator
Text {
anchors.centerIn: parent
text: JamiStrings.systemDictionary
color: JamiTheme.faddedLastInteractionFontColor
font.pixelSize: JamiTheme.settingsDescriptionPixelSize - 2
visible: model.IsSystem
}
// Downloading status indicator
BusyIndicator {
anchors.centerIn: parent
visible: model.Downloading
running: model.Downloading
width: 24
height: 24
// Use a custom animation for better UX
Behavior on running {
NumberAnimation {
duration: 300
easing.type: Easing.InOutQuad
}
}
}
}
}
}
// Empty state for when no dictionaries are found
Item {
anchors.fill: parent
visible: dictionaryProxyModel.count === 0
ColumnLayout {
anchors.centerIn: parent
spacing: 16
width: parent.width * 0.8
// Big books emoji
Text {
Layout.alignment: Qt.AlignHCenter
text: "📚"
font.pixelSize: 48
opacity: 0.3
}
Text {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
text: dictionarySearchBar.textContent.length > 0 ? JamiStrings.noDictionariesFoundFor.arg(dictionarySearchBar.textContent) : JamiStrings.noDictionariesAvailable
color: JamiTheme.faddedLastInteractionFontColor
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2025 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import QtQuick.Controls
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import "../commoncomponents/contextmenu"
BaseModalDialog {
id: root
objectName: "dictionaryManagerDialog"
title: JamiStrings.dictionaryManager
popupContent: DictionaryInstallView {
Accessible.name: JamiStrings.dictionaryManager
Accessible.role: Accessible.PopupMenu
width: 400
height: 500
}
}

View File

@ -59,7 +59,7 @@ BaseModalDialog {
Layout.fillWidth: true
elide: Text.ElideRight
text: modelData.body === "" ? JamiStrings.deletedMessage : modelData.body
text: modelData.body === "" ? JamiStrings.deletedMessage.arg(UtilsAdapter.getBestNameForUri(CurrentAccount.id, modelData.author)) : modelData.body
color: JamiTheme.textColor
}
}

View File

@ -21,7 +21,7 @@ import net.jami.Adapters 1.1
import net.jami.Constants 1.1
Column {
id: root
id: rootDelegate
property bool showTime: false
property bool showDay: false
@ -34,6 +34,18 @@ Column {
spacing: 2
topPadding: 12
bottomPadding: 12
Accessible.name: {
let name = UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
return name + ": " + Body + " " + formattedTime + " " + formattedDay;
}
Accessible.description: {
let status = "";
if (IsLastSent)
status += JamiStrings.sent + " ";
return status;
}
ColumnLayout {
width: parent.width
@ -42,10 +54,10 @@ Column {
TimestampInfo {
id: timestampItem
showDay: root.showDay
showTime: root.showTime
formattedTime: root.formattedTime
formattedDay: root.formattedDay
showDay: rootDelegate.showDay
showTime: rootDelegate.showTime
formattedTime: rootDelegate.formattedTime
formattedDay: rootDelegate.formattedDay
Layout.alignment: Qt.AlignHCenter
}
@ -60,7 +72,7 @@ Column {
}
opacity: 0
Behavior on opacity {
Behavior on opacity {
NumberAnimation {
duration: 100
}

View File

@ -28,6 +28,10 @@ Control {
property string title: ""
property string description: ""
Accessible.role: Accessible.StaticText
Accessible.name: title
Accessible.description: description
width: 190
height: infos.implicitHeight

View File

@ -27,6 +27,14 @@ FileDialog {
signal fileAccepted(string file)
signal filesAccepted(var files)
Component.onCompleted: {
JamiQmlUtils.openFileDialogCount++;
}
Component.onDestruction: {
JamiQmlUtils.openFileDialogCount--;
}
onAccepted: {
switch (fileMode) {
case FileDialog.OpenFile:

View File

@ -40,6 +40,9 @@ Flickable {
orientation: Qt.Horizontal
}
// HACK: remove after migration to Qt 6.7+
boundsBehavior: Flickable.StopAtBounds
Keys.onLeftPressed: horizontalScrollBar.decrease()
Keys.onRightPressed: horizontalScrollBar.increase()
Keys.onUpPressed: verticalScrollBar.decrease()

View File

@ -32,7 +32,7 @@ Item {
property bool validated: false
property bool outsideClic: false
property bool justChanged: false
property bool clic : false
property bool clic: false
height: getHeight()
function getHeight() {
@ -45,7 +45,6 @@ Item {
if (usernameTextEdit.editMode) {
usernameTextEdit.editMode = false;
}
}
}
@ -57,10 +56,16 @@ Item {
RoundedBorderRectangle {
id: leftRect
fillColor: JamiTheme.jamiIdBackgroundColor
Layout.preferredWidth: usernameTextEdit.visible ? childrenRect.width + JamiTheme.pushButtonMargins : childrenRect.width
Layout.preferredHeight: childrenRect.height
radius: {
radius: isRTL ? {
"tl": 0,
"tr": 5,
"br": 5,
"bl": 0
} : {
"tl": 5,
"tr": 0,
"br": 0,
@ -105,7 +110,7 @@ Item {
dynamicText = '';
}
}
Label{
Label {
id: usernameLabel
visible: !usernameTextEdit.editMode
@ -118,7 +123,7 @@ Item {
Layout.fillHeight: true
elide: Text.ElideRight
color: JamiTheme.tintedBlue
font.pixelSize : text.length > 16 ? JamiTheme.jamiIdSmallFontSize : JamiTheme.bigFontSize
font.pixelSize: text.length > 16 ? JamiTheme.jamiIdSmallFontSize : JamiTheme.bigFontSize
property string registeredName: CurrentAccount.registeredName
property string infohash: CurrentAccount.uri
text: (btnId.clicked && registeredName) ? registeredName : infohash
@ -132,7 +137,12 @@ Item {
Layout.preferredWidth: childrenRect.width + 2 * JamiTheme.pushButtonMargins
Layout.preferredHeight: leftRect.height
radius: {
radius: isRTL ? {
"tl": 5,
"tr": 0,
"br": 0,
"bl": 5
} : {
"tl": 0,
"tr": 5,
"br": 5,
@ -228,10 +238,14 @@ Item {
toolTipText: JamiStrings.identifierURI
onClicked: {
if (clicked) {
usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.uri} );
usernameTextEdit.staticText = Qt.binding(function () {
return CurrentAccount.uri;
});
btnId.toolTipText = JamiStrings.identifierRegisterName;
} else {
usernameTextEdit.staticText = Qt.binding(function() {return CurrentAccount.registeredName} );
usernameTextEdit.staticText = Qt.binding(function () {
return CurrentAccount.registeredName;
});
btnId.toolTipText = JamiStrings.identifierURI;
}
clicked = !clicked;

View File

@ -34,6 +34,9 @@ ListView {
attachedFlickableMoving: root.moving
}
// HACK: remove after migration to Qt 6.7+
boundsBehavior: Flickable.StopAtBounds
Keys.onUpPressed: verticalScrollBar.decrease()
Keys.onDownPressed: verticalScrollBar.increase()
}

View File

@ -15,8 +15,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Enums 1.1
import net.jami.Models 1.1
import "contextmenu"
import "../mainview"
import "../mainview/components"
ContextMenuAutoLoader {
id: root
@ -27,21 +32,19 @@ ContextMenuAutoLoader {
property var selectionEnd
property bool customizePaste: false
property bool selectOnly: false
property bool spellCheckEnabled: false
property var suggestionList
property var menuItemsLength
property var language
signal contextMenuRequirePaste
property list<GeneralMenuItem> menuItems: [
GeneralMenuItem {
id: copy
SpellLanguageContextMenu {
id: spellLanguageContextMenu
active: spellCheckEnabled
}
canTrigger: true
isActif: lineEditObj.selectedText.length
itemName: JamiStrings.copy
hasIcon: false
onClicked: {
lineEditObj.copy();
}
},
property list<GeneralMenuItem> menuItems: [
GeneralMenuItem {
id: cut
@ -49,9 +52,16 @@ ContextMenuAutoLoader {
isActif: lineEditObj.selectedText.length && !selectOnly
itemName: JamiStrings.cut
hasIcon: false
onClicked: {
lineEditObj.cut();
}
onClicked: lineEditObj.cut()
},
GeneralMenuItem {
id: copy
canTrigger: true
isActif: lineEditObj.selectedText.length
itemName: JamiStrings.copy
hasIcon: false
onClicked: lineEditObj.copy()
},
GeneralMenuItem {
id: paste
@ -65,9 +75,77 @@ ContextMenuAutoLoader {
else
lineEditObj.paste();
}
},
GeneralMenuItem {
id: textLanguage
canTrigger: spellCheckEnabled && SpellCheckAdapter.installedDictionaryCount > 0
itemName: JamiStrings.textLanguage
hasIcon: false
onClicked: {
spellLanguageContextMenu.openMenu();
}
},
GeneralMenuItem {
id: manageLanguages
itemName: JamiStrings.dictionaryManager
canTrigger: spellCheckEnabled
hasIcon: false
onClicked: {
viewCoordinator.presentDialog(appWindow, "commoncomponents/DictionaryManagerDialog.qml");
}
}
]
ListView {
model: ListModel {
id: suggestionListModel
}
Instantiator {
model: suggestionListModel
delegate: GeneralMenuItem {
id: suggestion
canTrigger: true
isActif: true
itemName: model.name
bold: true
hasIcon: false
onClicked: {
replaceWord(model.name);
}
}
onObjectAdded: {
menuItems.push(object);
}
onObjectRemoved: {
menuItems.splice(menuItemsLength, suggestionList.length);
}
}
}
function removeItems() {
suggestionListModel.clear();
suggestionList.length = 0;
}
function addMenuItem(wordList) {
menuItemsLength = menuItems.length; // Keep initial number of items for easier removal
suggestionList = wordList;
for (var i = 0; i < suggestionList.length; ++i) {
suggestionListModel.append({
"name": suggestionList[i]
});
}
}
function replaceWord(word) {
lineEditObj.remove(selectionStart, selectionEnd);
lineEditObj.insert(lineEditObj.cursorPosition, word);
}
function openMenuAt(mouseEvent) {
if (lineEditObj.selectedText.length === 0 && selectOnly)
return;
@ -85,6 +163,12 @@ ContextMenuAutoLoader {
function onOpened() {
lineEditObj.select(selectionStart, selectionEnd);
}
function onClosed() {
if (!suggestionList || suggestionList.length === 0) {
return;
}
removeItems();
}
}
Component.onCompleted: menuItemsToLoad = menuItems

View File

@ -20,14 +20,11 @@ import QtQuick.Layouts
import QtQuick.Controls
import Qt.labs.platform
import Qt5Compat.GraphicalEffects
import net.jami.Models 1.1
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import "../mainview/components"
BaseModalDialog {
id: root
@ -36,26 +33,27 @@ BaseModalDialog {
property real buttonSize: 36
property real imageSize: 25
signal focusOnPreviousItem
signal focusOnNextItem
signal imageValidated
signal imageTemporaryValidated
signal imageRemoved
signal imageTemporaryRemoved
function startBooth() {
recordBox.openRecorder(true)
recordBox.openRecorder(true);
}
function stopBooth(){
recordBox.closeRecorder()
function stopBooth() {
recordBox.closeRecorder();
}
function focusOnNextPhotoBoothItem () {
takePhotoButton.forceActiveFocus()
function focusOnNextPhotoBoothItem() {
takePhotoButton.forceActiveFocus();
}
function focusOnPreviousPhotoBoothItem () {
importButton.forceActiveFocus()
function focusOnPreviousPhotoBoothItem() {
importButton.forceActiveFocus();
}
title: JamiStrings.selectImage
@ -69,171 +67,165 @@ BaseModalDialog {
isPhoto: true
visible: false
onValidatePhoto: function(photo) {
if (!root.newItem)
AccountAdapter.setCurrentAccountAvatarBase64(photo)
else{
onValidatePhoto: function (photo) {
if (!root.newItem) {
AccountAdapter.setCurrentAccountAvatarBase64(photo);
imageTemporaryValidated();
} else {
UtilsAdapter.setTempCreationImageFromString(photo, imageId);
imageValidated();
}
root.close()
root.close();
}
}
popupContent: RowLayout {
id: buttonsRowLayout
id: buttonsRowLayout
spacing: 18
spacing: 18
JamiPushButton {
id: takePhotoButton
JamiPushButton {
id: takePhotoButton
Accessible.name: objectName
objectName: "takePhotoButton"
objectName: "takePhotoButton"
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignHCenter
height: buttonSize
width: buttonSize
height: buttonSize
width: buttonSize
enabled: VideoDevices.listSize !== 0
hoverEnabled: enabled
enabled: VideoDevices.listSize !== 0
hoverEnabled: enabled
normalColor: "transparent"
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
toolTipText: JamiStrings.takePhoto
source: JamiResources.add_a_photo_black_24dp_svg
normalColor: "transparent"
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
toolTipText: JamiStrings.takePhoto
source: JamiResources.add_a_photo_black_24dp_svg
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter ||
keyEvent.key === Qt.Key_Return) {
clicked()
keyEvent.accepted = true
} else if (keyEvent.key === Qt.Key_Up) {
root.focusOnPreviousItem()
keyEvent.accepted = true
}
}
KeyNavigation.tab: {
if (clearButton.visible)
return clearButton
return importButton
}
KeyNavigation.down: KeyNavigation.tab
onClicked: {
recordBox.parent = buttonsRowLayout
startBooth()
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
clicked();
keyEvent.accepted = true;
} else if (keyEvent.key === Qt.Key_Up) {
root.focusOnPreviousItem();
keyEvent.accepted = true;
}
}
JamiPushButton {
id: importButton
KeyNavigation.tab: {
if (clearButton.visible)
return clearButton;
return importButton;
}
KeyNavigation.down: KeyNavigation.tab
objectName: "photoboothViewImportButton"
onClicked: {
recordBox.parent = buttonsRowLayout;
startBooth();
}
}
Layout.alignment: Qt.AlignHCenter
visible: parent.visible
JamiPushButton {
id: importButton
height: buttonSize
width: buttonSize
objectName: "photoboothViewImportButton"
normalColor: "transparent"
source: JamiResources.add_photo_alternate_black_24dp_svg
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
toolTipText: JamiStrings.importFromFile
Layout.alignment: Qt.AlignHCenter
visible: parent.visible
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter ||
keyEvent.key === Qt.Key_Return) {
clicked()
keyEvent.accepted = true
} else if (keyEvent.key === Qt.Key_Down ||
keyEvent.key === Qt.Key_Tab) {
clearButton.forceActiveFocus()
keyEvent.accepted = true
}
height: buttonSize
width: buttonSize
Accessible.name: objectName
normalColor: "transparent"
source: JamiResources.add_photo_alternate_black_24dp_svg
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
toolTipText: JamiStrings.importFromFile
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
clicked();
keyEvent.accepted = true;
} else if (keyEvent.key === Qt.Key_Down || keyEvent.key === Qt.Key_Tab) {
clearButton.forceActiveFocus();
keyEvent.accepted = true;
}
}
KeyNavigation.up: takePhotoButton
KeyNavigation.up: takePhotoButton
onClicked: {
stopBooth()
var dlg = viewCoordinator.presentDialog(
appWindow,
"commoncomponents/JamiFileDialog.qml",
{
title: JamiStrings.selectProfilePicture,
fileMode: JamiFileDialog.OpenFile,
folder: StandardPaths.writableLocation(
StandardPaths.PicturesLocation),
nameFilters: [JamiStrings.imageFiles,
JamiStrings.allFiles]
})
dlg.fileAccepted.connect(function(file) {
var filePath = UtilsAdapter.getAbsPath(file)
onClicked: {
stopBooth();
var dlg = viewCoordinator.presentDialog(appWindow, "commoncomponents/JamiFileDialog.qml", {
title: JamiStrings.selectProfilePicture,
fileMode: JamiFileDialog.OpenFile,
folder: StandardPaths.writableLocation(StandardPaths.PicturesLocation),
nameFilters: [JamiStrings.imageFiles, JamiStrings.allFiles]
});
dlg.fileAccepted.connect(function (file) {
var filePath = UtilsAdapter.getAbsPath(file);
if (!root.newItem) {
AccountAdapter.setCurrentAccountAvatarFile(filePath)
AccountAdapter.setCurrentAccountAvatarFile(filePath);
imageTemporaryValidated();
} else {
UtilsAdapter.setTempCreationImageFromFile(filePath, root.imageId);
imageValidated();
}
root.close()
})
root.close();
});
}
}
JamiPushButton {
id: clearButton
objectName: "photoboothViewClearButton"
Layout.alignment: Qt.AlignHCenter
height: buttonSize
width: buttonSize
normalColor: "transparent"
source: JamiResources.remove_circle_outline_black_24dp_svg
toolTipText: JamiStrings.removeImage
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
visible: {
if (!newItem && LRCInstance.currentAccountAvatarSet)
return true;
if (newItem && UtilsAdapter.tempCreationImage(imageId).length !== 0)
return true;
return false;
}
KeyNavigation.up: importButton
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter || keyEvent.key === Qt.Key_Return) {
clicked();
importButton.forceActiveFocus();
keyEvent.accepted = true;
} else if (keyEvent.key === Qt.Key_Down || keyEvent.key === Qt.Key_Tab) {
btnCancel.forceActiveFocus();
keyEvent.accepted = true;
}
}
JamiPushButton {
id: clearButton
objectName: "photoboothViewClearButton"
Layout.alignment: Qt.AlignHCenter
height: buttonSize
width: buttonSize
normalColor: "transparent"
source: JamiResources.remove_circle_outline_black_24dp_svg
toolTipText: JamiStrings.removeImage
imageColor: hovered ? JamiTheme.textColor : JamiTheme.buttonTintedGreyHovered
visible: {
if (!newItem && LRCInstance.currentAccountAvatarSet)
return true
if (newItem && UtilsAdapter.tempCreationImage(imageId).length !== 0)
return true
return false
}
KeyNavigation.up: importButton
Keys.onPressed: function (keyEvent) {
if (keyEvent.key === Qt.Key_Enter ||
keyEvent.key === Qt.Key_Return) {
clicked()
importButton.forceActiveFocus()
keyEvent.accepted = true
} else if (keyEvent.key === Qt.Key_Down ||
keyEvent.key === Qt.Key_Tab) {
btnCancel.forceActiveFocus()
keyEvent.accepted = true
}
}
onClicked: {
if (!root.newItem)
AccountAdapter.setCurrentAccountAvatarBase64()
else {
UtilsAdapter.setTempCreationImageFromString("", imageId);
imageRemoved();
}
visible = false
stopBooth()
root.close()
onClicked: {
if (!root.newItem) {
AccountAdapter.setCurrentAccountAvatarBase64();
imageTemporaryRemoved();
} else {
UtilsAdapter.setTempCreationImageFromString("", imageId);
imageRemoved();
}
visible = false;
stopBooth();
root.close();
}
}
}
}

View File

@ -37,12 +37,16 @@ Row {
SystemButton {
id: minButton
Accessible.name: JamiStrings.minimize
Accessible.role: Accessible.Button
source: JamiResources.window_bar_minimize_svg
onClicked: appWindow.showMinimized()
}
SystemButton {
id: maxButton
Accessible.name: JamiStrings.maximize
Accessible.role: Accessible.Button
source: appWindow.visibility === Window.Maximized ?
JamiResources.window_bar_restore_svg :
JamiResources.window_bar_maximize_svg
@ -53,6 +57,8 @@ Row {
SystemButton {
id: closeButton
Accessible.name: JamiStrings.closeApplication
Accessible.role: Accessible.Button
source: JamiResources.window_bar_close_svg
baseColor: "#e81123"
onClicked: appWindow.close()

View File

@ -24,6 +24,7 @@ import net.jami.Constants 1.1
Control {
id: root
Accessible.role: Accessible.StaticText
property alias avatarBlockWidth: avatarBlock.width
property alias innerContent: innerContent
@ -64,6 +65,7 @@ Control {
property bool bigMsg
property bool timeUnderBubble: false
property var type: Type
property var shouldBeVisible: msgRowlayout.msgHovered || root.activeFocus || reply.activeFocus || more.activeFocus || share.activeFocus
// If the ListView attached properties are not available,
// then the root delegate is likely a Loader.
@ -81,6 +83,16 @@ Control {
rightPadding: hPadding
leftPadding: hPadding
background: Rectangle {
id: focusIndicator
visible: rootDelegate.activeFocus
radius: 4
border.color: JamiTheme.tintedBlue
border.width: 2
color: "transparent"
z: 1
}
contentItem: ColumnLayout {
id: mainColumnLayout
@ -142,6 +154,7 @@ Control {
RowLayout {
id: replyToLayout
spacing: replyItem.isSelf ? 2 : 4
Layout.alignment: isOutgoing ? Qt.AlignRight : Qt.AlignLeft
property var replyUserName: UtilsAdapter.getBestNameForUri(CurrentAccount.id, ReplyToAuthor)
@ -152,7 +165,7 @@ Control {
text: textMetricsUsername1.elidedText
TextMetrics {
id: textMetricsUsername1
text: isOutgoing ? JamiStrings.inReplyTo : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + JamiStrings.repliedTo
text: isOutgoing ? JamiStrings.inReplyTo : JamiStrings.repliedTo.arg(UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author))
elideWidth: 200
elide: Qt.ElideMiddle
}
@ -185,7 +198,7 @@ Control {
text: textMetricsUsername2.elidedText
TextMetrics {
id: textMetricsUsername2
text: replyItem.isSelf ? JamiStrings.inReplyToMe : replyToLayout.replyUserName
text: replyItem.isSelf ? JamiStrings.inReplyToYou : replyToLayout.replyUserName
elideWidth: 200
elide: Qt.ElideMiddle
}
@ -300,7 +313,7 @@ Control {
anchors.verticalCenter: parent.verticalCenter
anchors.right: isOutgoing ? optionButtonItem.right : undefined
anchors.left: !isOutgoing ? optionButtonItem.left : undefined
visible: msgRowlayout.msgHovered
visible: shouldBeVisible
source: JamiResources.more_vert_24dp_svg
width: optionButtonItem.width / 4
height: optionButtonItem.height
@ -310,7 +323,7 @@ Control {
function setBindings() {
more.isOpen = false;
visible = Qt.binding(() => msgRowlayout.msgHovered);
visible = Qt.binding(() => shouldBeVisible);
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
}
@ -355,7 +368,7 @@ Control {
anchors.rightMargin: 5
anchors.right: isOutgoing ? more.left : undefined
anchors.left: !isOutgoing ? more.right : undefined
visible: msgRowlayout.msgHovered
visible: shouldBeVisible
onClicked: {
MessagesAdapter.editId = "";
@ -379,13 +392,14 @@ Control {
anchors.rightMargin: 5
anchors.right: isOutgoing ? reply.left : undefined
anchors.left: !isOutgoing ? reply.right : undefined
visible: msgRowlayout.msgHovered
visible: shouldBeVisible
property bool isOpen: false
property var obj: undefined
function setBindings() { // when the popup is closed, setBindings is called to reset the icon's visual settings
share.isOpen = false;
visible = Qt.binding(() => msgRowlayout.msgHovered);
visible = Qt.binding(() => shouldBeVisible);
imageColor = Qt.binding(() => hovered ? JamiTheme.chatViewFooterImgHoverColor : JamiTheme.chatViewFooterImgColor);
normalColor = Qt.binding(() => JamiTheme.primaryBackgroundColor);
}
@ -688,7 +702,7 @@ Control {
readers: root.readers
}
Component {
Component {
id: selfReadIconComp
Avatar {
width: JamiTheme.avatarReadReceiptSize

View File

@ -23,7 +23,7 @@ import QtQuick.Layouts
Rectangle {
property alias name: label.text
property bool stretchParent: false
property string tag: parent.toString()
property string tag: parent.toString() + " (w:" + width + ", h: " + height + ")"
signal moveX(real dx)
signal moveY(real dy)
property real ox: 0

View File

@ -50,11 +50,14 @@ ComboBox {
contentItem: Text {
text: {
if (index < 0)
if (index < 0 || !model)
return '';
var currentItem = root.delegateModel.items.get(index);
const value = currentItem.model[root.textRole];
return value === undefined ? '' : value.toString();
if (root.textRole && model[root.textRole] !== undefined) {
return model[root.textRole].toString();
}
return model.display !== undefined ? model.display.toString() : '';
}
color: hovered ? JamiTheme.comboboxTextColorHovered : JamiTheme.textColor
@ -80,7 +83,7 @@ ComboBox {
source: popup.visible ? JamiResources.expand_less_24dp_svg : JamiResources.expand_more_24dp_svg
color: JamiTheme.comboboxIconColor
color: root.enabled ? JamiTheme.comboboxIconColor : "grey"
}
contentItem: Text {
@ -92,7 +95,7 @@ ComboBox {
anchors.rightMargin: root.indicator.width * 2
font.pixelSize: JamiTheme.settingsDescriptionPixelSize
text: root.displayText
color: JamiTheme.comboboxTextColor
color: root.enabled ? JamiTheme.comboboxTextColor : "grey"
font.weight: Font.Medium
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
@ -104,7 +107,11 @@ ComboBox {
color: JamiTheme.transparentColor
implicitWidth: 120
implicitHeight: contentItem.implicitHeight + JamiTheme.buttontextHeightMargin
border.color: popup.visible ? JamiTheme.comboboxBorderColorActive : JamiTheme.comboboxBorderColor
border.color: root.enabled ?
(popup.visible ?
JamiTheme.comboboxBorderColorActive :
JamiTheme.comboboxBorderColor) :
"grey"
border.width: root.visualFocus ? 2 : 1
radius: 5
}

View File

@ -22,6 +22,7 @@ import "contextmenu"
BaseContextMenu {
id: root
property var modelList
signal audioRecordMessageButtonClicked
signal videoRecordMessageButtonClicked
@ -31,35 +32,63 @@ BaseContextMenu {
GeneralMenuItem {
id: audioMessage
Accessible.role: Accessible.MenuItem
Accessible.name: itemName
focusPolicy: Qt.StrongFocus
Keys.onReturnPressed: clicked()
canTrigger: true
iconSource: JamiResources.message_audio_black_24dp_svg
itemName: JamiStrings.leaveAudioMessage
onClicked: {
root.audioRecordMessageButtonClicked();
root.close()
}
KeyNavigation.tab: videoMessage
KeyNavigation.backtab: shareLocation
},
GeneralMenuItem {
id: videoMessage
Accessible.role: Accessible.MenuItem
Accessible.name: itemName
focusPolicy: Qt.StrongFocus
Keys.onReturnPressed: clicked()
canTrigger: true
iconSource: JamiResources.message_video_black_24dp_svg
itemName: JamiStrings.leaveVideoMessage
isActif: VideoDevices.listSize !== 0
onClicked: {
root.videoRecordMessageButtonClicked();
root.close()
}
KeyNavigation.tab: shareLocation
KeyNavigation.backtab: audioMessage
},
GeneralMenuItem {
id: shareLocation
Accessible.role: Accessible.MenuItem
Accessible.name: itemName
focusPolicy: Qt.StrongFocus
Keys.onReturnPressed: clicked()
canTrigger: true
iconSource: JamiResources.localisation_sharing_send_pin_svg
itemName: JamiStrings.shareLocation
onClicked: {
root.showMapClicked();
root.close()
}
KeyNavigation.tab: audioMessage
KeyNavigation.backtab: videoMessage
}
]

View File

@ -35,7 +35,7 @@ BaseModalDialog {
property var buttonStyles: []
property string infoText: ""
property var innerContentData: []
property int buttonRoles: []
property var buttonRoles: []
function openWithParameters(title, info = "") {
root.title = title;

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2020-2025 Savoir-faire Linux Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick
import net.jami.Adapters 1.1
import net.jami.Constants 1.1
import net.jami.Models 1.1
import net.jami.Enums 1.1
import "contextmenu"
import "../mainview"
import "../mainview/components"
import SortFilterProxyModel 0.2
ContextMenuAutoLoader {
id: root
signal languageChanged
function openMenuAt(mouseEvent) {
x = mouseEvent.x;
y = mouseEvent.y;
root.openMenu();
}
onOpenRequested: {
// Create the menu items from the installed dictionaries
menuItemsToLoad = generateMenuItems();
}
function generateMenuItems() {
var menuItems = [];
// Create new menu items
var dictionaries = SpellCheckAdapter.getInstalledDictionaries();
var keys = Object.keys(dictionaries);
for (var i = 0; i < keys.length; ++i) {
const locale = keys[i];
const nativeName = dictionaries[keys[i]];
var menuItem = Qt.createComponent("qrc:/commoncomponents/contextmenu/GeneralMenuItem.qml", Component.PreferSynchronous);
if (menuItem.status !== Component.Ready) {
console.error("Error loading component:", menuItem.errorString());
continue;
}
let menuItemObject = menuItem.createObject(root, {
"parent": root,
"canTrigger": true,
"isActif": true,
"itemName": nativeName,
"hasIcon": false,
"content": locale,
"bold": UtilsAdapter.getAppValue(Settings.SpellLang) === locale
});
if (menuItemObject === null) {
console.error("Error creating menu item:", menuItem.errorString());
continue;
}
menuItemObject.clicked.connect(function () {
const locale = menuItemObject.content;
SpellCheckAdapter.setDictionary(locale);
});
// Log the object pointer
menuItems.push(menuItemObject);
}
return menuItems;
}
}

View File

@ -24,27 +24,38 @@ import net.jami.Constants 1.1
import net.jami.Enums 1.1
SBSMessageBase {
id: root
id: rootDelegate
Accessible.role: Accessible.StaticText
Accessible.name: {
let name = isOutgoing ? JamiStrings.inReplyToYou : UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author);
return name + ": " + Body + " " + formattedTime;
}
Accessible.description: {
let status = "";
if (bubble.isEdited)
status += JamiStrings.edited + " ";
return status + (readers.length > 0 ? JamiStrings.readBy + " " + readers.map(function (uri) {
return UtilsAdapter.getBestNameForUri(CurrentAccount.id, uri);
}).join(", ") : "");
}
property bool isRemoteImage
property bool isEmojiOnly: IsEmojiOnly
property string colorUrl: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark
property string colorText: UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark
Connections {
target: bubble
function onColorChanged(color) {
root.colorUrl = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark;
root.colorText = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
rootDelegate.colorUrl = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewLinkColorLight : JamiTheme.chatviewLinkColorDark;
rootDelegate.colorText = UtilsAdapter.luma(bubble.color) ? JamiTheme.chatviewTextColorLight : JamiTheme.chatviewTextColorDark;
// Update parsed body with correct colors
if (Body !== "")
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), root.colorUrl, bubble.color);
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), rootDelegate.colorUrl, bubble.color);
}
}
isOutgoing: Author === CurrentAccount.uri
author: Author
readers: Readers
@ -56,7 +67,7 @@ SBSMessageBase {
textContentWidth: textEditId.width
textContentHeight: textEditId.height
bigMsg: textContentWidth >= (2 / 3) * root.maxMsgWidth || extraContent.active
bigMsg: textContentWidth >= (2 / 3) * rootDelegate.maxMsgWidth || extraContent.active
innerContent.children: [
TextEdit {
@ -66,16 +77,16 @@ SBSMessageBase {
topPadding: bubble.isDeleted ? 6 : 10
bottomPadding: bubble.isDeleted ? 6 : 10
anchors.right: isOutgoing ? parent.right : undefined
anchors.rightMargin: isOutgoing && !isEmojiOnly && !bigMsg ? root.timeWidth + root.editedWidth : 0
anchors.rightMargin: isOutgoing && !isEmojiOnly && !bigMsg ? rootDelegate.timeWidth + rootDelegate.editedWidth : 0
text: {
if (Body !== "" && ParsedBody.length === 0) {
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), root.colorUrl, bubble.color);
MessagesAdapter.parseMessage(Id, Body, UtilsAdapter.getAppValue(Settings.DisplayHyperlinkPreviews), rootDelegate.colorUrl, bubble.color);
return "";
}
if (ParsedBody !== "")
return ParsedBody;
bubble.isDeleted = true;
return UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author) + " " + JamiStrings.deletedMessage ;
return JamiStrings.deletedMessage.arg(UtilsAdapter.getBestNameForUri(CurrentAccount.id, Author));
}
horizontalAlignment: Text.AlignLeft
@ -85,11 +96,11 @@ SBSMessageBase {
width: {
if (extraContent.active)
Math.max(extraContent.width, Math.min((2 / 3) * root.maxMsgWidth, implicitWidth - avatarBlockWidth, extraContent.minSize) - senderMargin);
Math.max(extraContent.width, Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth - avatarBlockWidth, extraContent.minSize) - senderMargin);
else if (isEmojiOnly)
Math.min((2 / 3) * root.maxMsgWidth, implicitWidth, innerContent.width - senderMargin - (innerContent.width - senderMargin) % (JamiTheme.chatviewEmojiSize + 2));
Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth, innerContent.width - senderMargin - (innerContent.width - senderMargin) % (JamiTheme.chatviewEmojiSize + 2));
else
Math.min((2 / 3) * root.maxMsgWidth, implicitWidth + 5, innerContent.width - senderMargin + 5);
Math.min((2 / 3) * rootDelegate.maxMsgWidth, implicitWidth + 5, innerContent.width - senderMargin + 5);
}
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
@ -99,11 +110,11 @@ SBSMessageBase {
renderType: Text.NativeRendering
textFormat: Text.RichText
clip: true
onLinkHovered: root.hoveredLink = hoveredLink
onLinkHovered: rootDelegate.hoveredLink = hoveredLink
onLinkActivated: Qt.openUrlExternally(new URL(hoveredLink))
readOnly: true
color: (ParsedBody !== "") ? getBaseColor() : (UtilsAdapter.luma(bubble.color) ? "white" : "dark")
opacity:(ParsedBody !== "") ? 1 : 0.5
opacity: (ParsedBody !== "") ? 1 : 0.5
function getBaseColor() {
var baseColor;
@ -136,7 +147,6 @@ SBSMessageBase {
selectOnly: parent.readOnly
}
},
Loader {
id: extraContent
@ -154,7 +164,7 @@ SBSMessageBase {
HoverHandler {
target: previewContent
onHoveredChanged: {
root.hoveredLink = hovered ? LinkPreviewInfo.url : "";
rootDelegate.hoveredLink = hovered ? LinkPreviewInfo.url : "";
}
cursorShape: Qt.PointingHandCursor
}
@ -208,7 +218,7 @@ SBSMessageBase {
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
renderType: Text.NativeRendering
textFormat: TextEdit.RichText
color: root.colorText
color: rootDelegate.colorText
visible: LinkPreviewInfo.title.length > 0
text: LinkPreviewInfo.title
lineHeight: 1.3
@ -221,9 +231,9 @@ SBSMessageBase {
renderType: Text.NativeRendering
textFormat: TextEdit.RichText
visible: LinkPreviewInfo.description.length > 0
font.underline: root.hoveredLink
font.underline: rootDelegate.hoveredLink
text: LinkPreviewInfo.description
color: root.colorUrl
color: rootDelegate.colorUrl
lineHeight: 1.3
}
Label {
@ -233,7 +243,7 @@ SBSMessageBase {
wrapMode: Label.WrapAtWordBoundaryOrAnywhere
renderType: Text.NativeRendering
textFormat: TextEdit.RichText
color: root.colorText
color: rootDelegate.colorText
text: LinkPreviewInfo.domain
lineHeight: 1.3
}
@ -243,7 +253,7 @@ SBSMessageBase {
]
opacity: 0
Behavior on opacity {
Behavior on opacity {
NumberAnimation {
duration: 100
}

View File

@ -44,11 +44,15 @@ Menu {
function loadMenuItems(menuItems) {
root.addItem(menuTopBorder);
// Establish the preferred width of the menu by taking the maximum width of the items
for (var j = 0; j < menuItems.length; ++j) {
var currentItemWidth = menuItems[j].itemPreferredWidth;
if (currentItemWidth !== JamiTheme.menuItemsPreferredWidth && currentItemWidth > menuPreferredWidth && menuItems[j].canTrigger)
menuPreferredWidth = currentItemWidth;
}
// Add the items to the menu
for (var i = 0; i < menuItems.length; ++i) {
if (menuItems[i].canTrigger) {
menuItems[i].parentMenu = root;

View File

@ -27,11 +27,14 @@ Loader {
property int contextMenuItemPreferredHeight: 0
property int contextMenuSeparatorPreferredHeight: 0
signal openRequested
active: false
visible: false
function openMenu() {
openRequested();
root.active = true;
root.sourceComponent = menuComponent;
}

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