mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
Merge branch 'master' into search
This commit is contained in:
commit
01281e87cb
25
.travis.yml
25
.travis.yml
|
@ -103,16 +103,22 @@ matrix:
|
|||
cache:
|
||||
directories:
|
||||
- /opt/build-windows/x86_64
|
||||
- stage: "macOS and AppImage"
|
||||
- stage: "macOS, AppImage and Flatpak"
|
||||
os: osx
|
||||
osx_image: xcode7.3
|
||||
env: JOB=build-osx
|
||||
- stage: "macOS and AppImage"
|
||||
- stage: "macOS, AppImage and Flatpak"
|
||||
os: linux
|
||||
env: JOB=APPIMAGE
|
||||
script: ./appimage/build-appimage.sh
|
||||
services:
|
||||
- docker
|
||||
- stage: "macOS, AppImage and Flatpak"
|
||||
os: linux
|
||||
env: JOB=FLATPAK
|
||||
script: ./flatpak/build-flatpak.sh
|
||||
services:
|
||||
- docker
|
||||
|
||||
script: "./.travis/$JOB.sh"
|
||||
|
||||
|
@ -121,13 +127,26 @@ deploy:
|
|||
- provider: releases
|
||||
api_key:
|
||||
secure: "BRbzTWRvadALRQSTihMKruOj64ydxusMUS9FQR//qFlS345ZYfYta43W//4LcWWDKtj6IvA6DRqNdabgWnpbpxpnm9gVftGUdOKlU3niPZhwsMkB2M12QHUnAP6DVOfGPvdciBV+6mu73SSxniEcrYjZ1CrRX7mknmehPpVKxNk="
|
||||
file: ./output/qTox-"$TRAVIS_TAG".AppImage
|
||||
file_glob: true
|
||||
file: ./output/*
|
||||
on:
|
||||
condition: $JOB == APPIMAGE
|
||||
repo: qTox/qTox
|
||||
tags: true
|
||||
skip_cleanup: true
|
||||
|
||||
# Linux Flatpak
|
||||
- provider: releases
|
||||
api_key:
|
||||
secure: "BRbzTWRvadALRQSTihMKruOj64ydxusMUS9FQR//qFlS345ZYfYta43W//4LcWWDKtj6IvA6DRqNdabgWnpbpxpnm9gVftGUdOKlU3niPZhwsMkB2M12QHUnAP6DVOfGPvdciBV+6mu73SSxniEcrYjZ1CrRX7mknmehPpVKxNk="
|
||||
file_glob: true
|
||||
file: ./output/*
|
||||
on:
|
||||
condition: $JOB == FLATPAK
|
||||
repo: qTox/qTox
|
||||
tags: true
|
||||
skip_cleanup: true
|
||||
|
||||
# osx binary
|
||||
- provider: releases
|
||||
api_key:
|
||||
|
|
|
@ -35,6 +35,7 @@ sudo apt-get install -y --force-yes \
|
|||
libgdk-pixbuf2.0-dev \
|
||||
libglib2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libkdeui5 \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
|
@ -170,7 +171,8 @@ build_qtox() {
|
|||
cmake -H. -B"$BUILDDIR" \
|
||||
-DSMILEYS=DISABLED \
|
||||
-DENABLE_STATUSNOTIFIER=False \
|
||||
-DENABLE_GTK_SYSTRAY=False
|
||||
-DENABLE_GTK_SYSTRAY=False \
|
||||
-DSPELL_CHECK=OFF
|
||||
|
||||
bdir
|
||||
|
||||
|
|
179
CHANGELOG.md
179
CHANGELOG.md
|
@ -1,3 +1,99 @@
|
|||
<a name=""></a>
|
||||
## v1.16.3 (2018-07-18)
|
||||
|
||||
This point release fixes flatpak build. No feature changes.
|
||||
|
||||
|
||||
|
||||
<a name=""></a>
|
||||
## v1.16.2 (2018-07-15)
|
||||
|
||||
This point release fixes dialog spam from receiving invalid filenames and logs
|
||||
spam. No feature changes.
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **logging:** only log toxcore messages above TRACE level ([4dc74201](https://github.com/qTox/qTox/commit/4dc7420162e69095942b392048c309e6246d6b21))
|
||||
* **ui:** don't emit filename change windows for every chat ([c1701345](https://github.com/qTox/qTox/commit/c1701345455ad5b253beeaa3d487daa01b8b1b21))
|
||||
|
||||
|
||||
|
||||
<a name=""></a>
|
||||
## v1.16.1 (2018-07-04)
|
||||
|
||||
This point release fixes our deployment of Flapak and AppImage on Github. No
|
||||
feature changes.
|
||||
|
||||
#### Features
|
||||
|
||||
* **deploy:** upload Flatpak bundle to Github releases ([59b5578c](https://github.com/qTox/qTox/commit/59b5578c7bffc56f6227c60bfcb38f97d39ec8d9))
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* **deploy:** fix file path in AppImage deployment ([64602f38](https://github.com/qTox/qTox/commit/64602f38f154a3f3d2429146ae5d370b2202d1b8))
|
||||
|
||||
|
||||
|
||||
<a name=""></a>
|
||||
## v1.16.0 (2018-07-02)
|
||||
|
||||
The most notable additions in this release are a new fullscreen mode for
|
||||
video calls, a new call end sound and support for more camera resolutions. To
|
||||
distribute qTox in a more user friendly manner we now publish Flatpak and
|
||||
AppImage packages.
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* remove full screen btn from audio group chat ([0d3f061b](https://github.com/qTox/qTox/commit/0d3f061ba80d9f3f8a971d2b8e11a7d9b59d180a))
|
||||
* local toxcore install with bootstrap.sh ([9ca38750](https://github.com/qTox/qTox/commit/9ca3875079adf175f31f568e45aabc37e3409000), closes [#5199](https://github.com/qTox/qTox/issues/5199))
|
||||
* simple_make.sh script ([ead2152d](https://github.com/qTox/qTox/commit/ead2152d6f0d15f7e662975fb3ed8525109794c3))
|
||||
* Fix PR #5182. Eliminating the 'new' operator at ToxOptionsWrapper ([9b6cd1c0](https://github.com/qTox/qTox/commit/9b6cd1c0227006308d4fe556f2b721865c2d9b21))
|
||||
* Fix usage of unitialized functions ([06ae7ead](https://github.com/qTox/qTox/commit/06ae7ead0c7c23935c1c05c75d9cb11ed516224b))
|
||||
* two crashes, uncovered by the persistent groupchat patch ([48179b6a](https://github.com/qTox/qTox/commit/48179b6a19807383e298661a21f97db3b140eb44))
|
||||
* delete double initialization callDuration ([dc1f5ea0](https://github.com/qTox/qTox/commit/dc1f5ea0a319bf4cbf05989c414ccaea898b4826))
|
||||
* **Core:** fix use after free of proxyAddrData ([26b59d31](https://github.com/qTox/qTox/commit/26b59d312375ad6391228308aabe45f0a85a1194))
|
||||
* **appimage:** build sqlcipher form source ([64a7c24b](https://github.com/qTox/qTox/commit/64a7c24b2b5ad11a6df5dbb11da6e3aa7c0fd6f3))
|
||||
* **audio:**
|
||||
* fix error introduced in 67f2605971cf43093c72f811e4df90ab70544dd6 ([40d30153](https://github.com/qTox/qTox/commit/40d30153aed223b65b596dc7d3bf17573b04f3e9))
|
||||
* connect the correct audio callbacks ([a00af087](https://github.com/qTox/qTox/commit/a00af087778c6315ef55ed77c4209cbb63a6323d))
|
||||
* close the audio device after playing a sound ([a3370173](https://github.com/qTox/qTox/commit/a3370173df24cd6880e3e3845ddbbc7c090b7aed))
|
||||
* **build:**
|
||||
* Elimination the build warnings (Wunused-variable, Wreorder) ([2cd65610](https://github.com/qTox/qTox/commit/2cd65610fcce0c3dcf8a5e9cb9f313a76167c09a))
|
||||
* correct install script nsis for win64 ([25e69572](https://github.com/qTox/qTox/commit/25e69572f89d816cfab5a8c0d1c261bae34d3cdd))
|
||||
* make qTox compile with ffmpeg 4.0 and newer ([44193176](https://github.com/qTox/qTox/commit/441931765ffe3de349b28a28bf10a006edcc9949))
|
||||
* **chatform:**
|
||||
* name in window title and close detached chats ([39968a31](https://github.com/qTox/qTox/commit/39968a313d78c727046837901e6cc3d6c31d18e0))
|
||||
* check for empty path when exporting profile ([757791ee](https://github.com/qTox/qTox/commit/757791eea4be390bb6d1cdc908d1cd3c4b18728d), closes [#5146](https://github.com/qTox/qTox/issues/5146))
|
||||
* **core:** Clean illegal chars from filenames ([ab85716f](https://github.com/qTox/qTox/commit/ab85716f00acfe00ff8035670919dd548d7f7f83))
|
||||
* **docs:** update toxcore build instructions ([b00cbc1d](https://github.com/qTox/qTox/commit/b00cbc1d6f3a7f8406e4a96e732c534068fde22c))
|
||||
* **file:** don't clean the filenames of avatar transfer ([2a8ab03e](https://github.com/qTox/qTox/commit/2a8ab03e46dd08efc4051a01bea56fe6a4c38a11))
|
||||
* **history:** don't save both action prefix and displayed name ([dfd2de83](https://github.com/qTox/qTox/commit/dfd2de836eae605e02a1afb270620dd9274f6385))
|
||||
* **leak:** Fix few memory leaks ([daaa5518](https://github.com/qTox/qTox/commit/daaa5518dd7c02c2de45690daa3f592206fc4023))
|
||||
* **login:** start login screen on profile select by -p option ([1af3ad69](https://github.com/qTox/qTox/commit/1af3ad69e884bc4e74a4fcdd452a6aff10bffd62))
|
||||
* **settings:**
|
||||
* automatically disable UDP when a proxy is set ([977b7fc9](https://github.com/qTox/qTox/commit/977b7fc9a02b2b44164ffb77ab35f4cdfae90542))
|
||||
* prevent segfault on wrong proxy settings ([dfd5232e](https://github.com/qTox/qTox/commit/dfd5232e2fb727685a20804d7ca3b932ea239332))
|
||||
* **simple_make:** correct variable initialization ([1537f83e](https://github.com/qTox/qTox/commit/1537f83e85ff28dd73fb66161ae2cd5eeef692d1))
|
||||
* **theme:** clear stylesheet cache on theme colour change ([8ba8ce91](https://github.com/qTox/qTox/commit/8ba8ce91f3317794b72fb4937c459dac2856d367))
|
||||
* **ui:** increase number of low res camera options ([72931514](https://github.com/qTox/qTox/commit/72931514695a8691593d6a5abd2df1e340f95002))
|
||||
* **video:** unsubscribe the video device correctly ([e55f86c6](https://github.com/qTox/qTox/commit/e55f86c6a5b0344642fcb3d7a2550df6e899a6e5))
|
||||
* **wayland:** Fix desktop file name in Qt properties ([c1caeb58](https://github.com/qTox/qTox/commit/c1caeb585a8845eaa72c7db79fb334262eafdb8f))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add ability to remove dialog from content dialog with middle click ([aae567ed](https://github.com/qTox/qTox/commit/aae567ed8e299fc0cdd700e2e0020042ee1cba11))
|
||||
* Add ability to quit group with middle click ([228c431c](https://github.com/qTox/qTox/commit/228c431c890a7e68d078b441311892c691643926))
|
||||
* Add middle mouse clicked signal for GenericChatroom ([65fc1dc2](https://github.com/qTox/qTox/commit/65fc1dc266da29e0679f2b645c31bc428f0cf575))
|
||||
* **appimage:** build appimage on TravisCI ([f7345e4d](https://github.com/qTox/qTox/commit/f7345e4db264a5681490b9094981a65cac68d317))
|
||||
* **call:** add call end sound ([65896e45](https://github.com/qTox/qTox/commit/65896e45017f8f748bc5b9db10a4400d7fd418dc))
|
||||
* **chat:**
|
||||
* add UI option to mute group peers ([2fae2a30](https://github.com/qTox/qTox/commit/2fae2a30f76978ce722c5b24236384c8052ebfc4))
|
||||
* full screen video chat ([d6df8883](https://github.com/qTox/qTox/commit/d6df8883e399b95a55c5a5870497c1dcd45a3917))
|
||||
* **core:** put c-toxcore log messages in the qTox log ([4faab075](https://github.com/qTox/qTox/commit/4faab0750d3841beeb08c7d17e85044b5013aea8))
|
||||
* **history:** load set number of messages from history ([ca32e77d](https://github.com/qTox/qTox/commit/ca32e77d7400e23a6a839f6a8d1f322bfe48bbf0))
|
||||
|
||||
|
||||
|
||||
<a name="v1.15.0"></a>
|
||||
## v1.15.0 (2018-04-18)
|
||||
|
||||
|
@ -45,88 +141,7 @@
|
|||
|
||||
|
||||
<a name=""></a>
|
||||
## (2018-03-12)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
||||
* Not quit on close if this setting is enabled ([e73dc10c](https://github.com/qTox/qTox/commit/e73dc10c7fd23b887cc5e2d5d4021bc02c8555ec))
|
||||
* add search symbol ' in history ([3e05279c](https://github.com/qTox/qTox/commit/3e05279c097b33b09cedcebae4150c839a23af35))
|
||||
* Use real channels number ([e74cc37a](https://github.com/qTox/qTox/commit/e74cc37a2d02e9d4cbd016bac9dbb7697e8445e7))
|
||||
* Allocate memory to input buffer ([900f2a1a](https://github.com/qTox/qTox/commit/900f2a1ad3b328359a0ae089e778b15280512a9d))
|
||||
* Call doAudio on timer timeout ([2353a66f](https://github.com/qTox/qTox/commit/2353a66fded32174421c9663ced5cfe4ceabe00b))
|
||||
* [un]subscribe output in avform ([8c05399e](https://github.com/qTox/qTox/commit/8c05399e418f2c0147ce2d9c7dd220a0cdc97765))
|
||||
* Correct display the call confirm window (CallConfirmWidget) ([f4fe343e](https://github.com/qTox/qTox/commit/f4fe343eca3eaf84f9ce300b59be9e83a70c204e))
|
||||
* elimination of warning '-Wreorder' ([0869d3d8](https://github.com/qTox/qTox/commit/0869d3d8fdc9e9de2f1df51c377ddba71a1ce523))
|
||||
* Use epsilon to compare float ([91dabf11](https://github.com/qTox/qTox/commit/91dabf11d31807f499d6e949373bf22762e80f5b))
|
||||
* **UI:** prevent deadlocks on logout and profile delete ([a49e3458](https://github.com/qTox/qTox/commit/a49e34589f40edfb3fc46d5700573f87d5dfe3d0))
|
||||
* **build:**
|
||||
* move Appdata file installation to /usr/share/metainfo ([5db0bdd3](https://github.com/qTox/qTox/commit/5db0bdd381f0f08c5685501702f2a2eb9d2f5674))
|
||||
* add needed ffmpeg decoder to configuration ([8973a521](https://github.com/qTox/qTox/commit/8973a5216f49e65adc48d5fada8a574db598cced))
|
||||
* Add missing dependency for openSUSE ([f7e089f7](https://github.com/qTox/qTox/commit/f7e089f7a71c41ff31d311fe7148e57b5c6fb60a))
|
||||
* **chatform:** Broaden URL matching to include unicode ([e564b85e](https://github.com/qTox/qTox/commit/e564b85e3c485b283855bfdf00dfc0ec5427fad4))
|
||||
* **chatlog:**
|
||||
* Match multi-character emoticons again ([9643e48e](https://github.com/qTox/qTox/commit/9643e48ef1d68948d52feec4e1be28c3ad61c0da))
|
||||
* parse multi-length emoji properly ([5df63f9c](https://github.com/qTox/qTox/commit/5df63f9c2e6d78f4799447b0a22cdb9fb70c3fea))
|
||||
* **chatwidget:** fix send file button not working ([af1aebfd](https://github.com/qTox/qTox/commit/af1aebfd1a7409ea821be2a616067561b62751c0))
|
||||
* **cmake:**
|
||||
* fix platform extensions for windows ([7ad68e2f](https://github.com/qTox/qTox/commit/7ad68e2f43b458cd00ca27b9cfb20abf0b9ae46c))
|
||||
* add missing dependency ([423f0956](https://github.com/qTox/qTox/commit/423f095622824a34d081fb69bddd83cddf83ca03))
|
||||
* **core:**
|
||||
* Adapt qtox to new conferences state change callback. ([1111949f](https://github.com/qTox/qTox/commit/1111949f450fb4fe63321386f7f452ee1663f07a))
|
||||
* Use new callback API for bitrate set ([d2deec7c](https://github.com/qTox/qTox/commit/d2deec7c554b3df651fe789dfb7964748329eff4))
|
||||
* Use new API for bitrate set ([2c8f03da](https://github.com/qTox/qTox/commit/2c8f03dada443e30d6189050c7cf6d42e01827c5))
|
||||
* **cpu:** Reduce CPU usage by avatar render ([8db61f96](https://github.com/qTox/qTox/commit/8db61f96ec78ac53479dd8db36eb192f6a1ddbcd))
|
||||
* **friendwidget:** Use queued connection to avoid removing 'this' ([9b4972e0](https://github.com/qTox/qTox/commit/9b4972e0459de2921370cda9de645eb64e37ecfc))
|
||||
* **group:** Show correct count of user on first creation ([0a590336](https://github.com/qTox/qTox/commit/0a590336b1467405a903464085dcdfc4474f93e6))
|
||||
* **install:** Fix gzip invalid usage ([266f63f6](https://github.com/qTox/qTox/commit/266f63f6dfb1869aa2339d48cdc9b52ece3597ce))
|
||||
* **l10n:**
|
||||
* Correction of the translation into Russian ([3fb42b75](https://github.com/qTox/qTox/commit/3fb42b75d75bf6c0240748ffff368b912b14a838))
|
||||
* Correction of the translation into Russian ([9229fdd1](https://github.com/qTox/qTox/commit/9229fdd17e013a8bd60102648a200734890c2140))
|
||||
* **smiley:** change license of classic smileys to CC BY-SA 4.0 ([da7c12e2](https://github.com/qTox/qTox/commit/da7c12e20cac1ac7340b4bb4ec89f782e2e4a159))
|
||||
* **travis:**
|
||||
* try working around Travis + gitstats issue ([4c980945](https://github.com/qTox/qTox/commit/4c98094551ff4a1e7377a206b72fedd470b8be96))
|
||||
* switch back to older Ubuntu Image ([378daeaa](https://github.com/qTox/qTox/commit/378daeaad4c5992a7acd2b650ff081d213556e10))
|
||||
* **video:**
|
||||
* improve debug message ([ff2fc18b](https://github.com/qTox/qTox/commit/ff2fc18be164fcbc89bfd46d64f4b0096a97aee5))
|
||||
* choose first available resolution in preview automatically ([81522dea](https://github.com/qTox/qTox/commit/81522deabdc3fb11fd8d3e1feb59274a96583121))
|
||||
* use float framerates also for V4L2 ([a2927de2](https://github.com/qTox/qTox/commit/a2927de27d4776b52303e07c07ce89e8dadf86c5))
|
||||
* allow not integer framerates ([db7ee65d](https://github.com/qTox/qTox/commit/db7ee65d0efbe23a45e385a148b20701e521a5c5))
|
||||
* Fix square form of a video ([8de8c14a](https://github.com/qTox/qTox/commit/8de8c14a76908cf84a322a0bfd9e2c7ad2b4fa16))
|
||||
* **widget:** Fix status pic alignment ([d9118cfc](https://github.com/qTox/qTox/commit/d9118cfc71e2b030914187df7fd9fb3d98378cf1))
|
||||
* **windows:** %APPDATA -> %APPDATA% in template ([f53b8282](https://github.com/qTox/qTox/commit/f53b82825bf76be5a6793d18f2d102ed7b222313))
|
||||
|
||||
#### Features
|
||||
|
||||
* Add the cmake option USE_CCACHE ([aa9cff31](https://github.com/qTox/qTox/commit/aa9cff315d659a7ca2010fb4791893abc8c5abdb))
|
||||
* update to the new c-toxcore 0.2.0 conferences api ([d3d81bbd](https://github.com/qTox/qTox/commit/d3d81bbdf3c198a7c1258c6ad6405c6ab61cedd4))
|
||||
* add hot keys for search ([ffb51e8a](https://github.com/qTox/qTox/commit/ffb51e8a0ea7dc3fb01f1f7650edc80b779a9be2))
|
||||
* optimise search in history ([18fa8a74](https://github.com/qTox/qTox/commit/18fa8a745bdafddc00ba2f577c36451f40edfd61))
|
||||
* add search in text in group chats ([7718734c](https://github.com/qTox/qTox/commit/7718734c9ab9705c1a1274b2a447611c1a2e22b4))
|
||||
* remove search button and add line in context menu ([8bb80c77](https://github.com/qTox/qTox/commit/8bb80c770c1d21d1bdfc03c3d0569fabe6535e8f))
|
||||
* edit load history for search ([de9c9061](https://github.com/qTox/qTox/commit/de9c9061175c97a9ee203d18a39e73f77544d5e6))
|
||||
* add text search ([b881d32d](https://github.com/qTox/qTox/commit/b881d32d1bddb7352b8d24e2442ef6277ff0d583))
|
||||
* add form for search ([863c46c7](https://github.com/qTox/qTox/commit/863c46c73d1a2fc677f9142ba8d7a2e8dc659c2a))
|
||||
* add a button to search ([47d9da98](https://github.com/qTox/qTox/commit/47d9da98cf6811a30d35a1204e5342a4f7f4bf94))
|
||||
* Prefere new line as message break ([3b52402f](https://github.com/qTox/qTox/commit/3b52402fa20d2d5418e129e5f001b626401a9ae5))
|
||||
* **UI:** new status icons for message notifications ([4288785d](https://github.com/qTox/qTox/commit/4288785d31e215bc379223577f7d4dd65664ed86))
|
||||
* **avatar:** Add outline hightlight on mouse hover ([bb26485d](https://github.com/qTox/qTox/commit/bb26485db6fed706f4ebccaffe35740394210032))
|
||||
* **groupchat:** mark blocked users with different color ([a729f2f8](https://github.com/qTox/qTox/commit/a729f2f8c00d29d2837b6e380f5af1b95c344bad))
|
||||
* **l10n:**
|
||||
* add Macedonian translation ([1a06f85d](https://github.com/qTox/qTox/commit/1a06f85d3ccc91ff6f759a38534483fa40aaaa29))
|
||||
* add Macedonian translation using Weblate ([41420331](https://github.com/qTox/qTox/commit/414203310a30720e02e06719bfcafbb8bcff9018))
|
||||
* update French translation from Weblate ([a7e90969](https://github.com/qTox/qTox/commit/a7e9096919d4c0b89f061e8b77741d517f574838))
|
||||
* update Portuguese translation from Weblate ([3bad087b](https://github.com/qTox/qTox/commit/3bad087bbff2fbff4c4d543df1f96931784c93df))
|
||||
* update Portuguese translation from Weblate ([8c3be522](https://github.com/qTox/qTox/commit/8c3be5225f484469aed43dde04f03bc588ca2c15))
|
||||
|
||||
#### Performance
|
||||
|
||||
* **widget:** don't save on setExpanded if categorywidget is unchanged Fix #4932 ([b9845e1d](https://github.com/qTox/qTox/commit/b9845e1d23eb23380f447692e3a813413e897c2d))
|
||||
|
||||
|
||||
|
||||
<a name=""></a>
|
||||
## (2018-03-12)
|
||||
## v1.14.0 (2018-03-12)
|
||||
|
||||
|
||||
#### Bug Fixes
|
||||
|
|
|
@ -12,6 +12,7 @@ option(USE_FILTERAUDIO "Enable the echo canceling backend" ON)
|
|||
# AUTOUPDATE is currently broken and thus disabled
|
||||
option(AUTOUPDATE "Enable the auto updater" OFF)
|
||||
option(USE_CCACHE "Use ccache when available" ON)
|
||||
option(SPELL_CHECK "Enable spell cheching support" ON)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Debug)
|
||||
|
@ -256,6 +257,10 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/core/toxfile.h
|
||||
src/core/toxid.cpp
|
||||
src/core/toxid.h
|
||||
src/core/toxlogger.cpp
|
||||
src/core/toxlogger.h
|
||||
src/core/toxoptions.cpp
|
||||
src/core/toxoptions.h
|
||||
src/core/toxpk.cpp
|
||||
src/core/toxpk.h
|
||||
src/core/toxstring.cpp
|
||||
|
@ -269,6 +274,11 @@ set(${PROJECT_NAME}_SOURCES
|
|||
src/model/about/aboutfriend.cpp
|
||||
src/model/about/aboutfriend.h
|
||||
src/model/about/iaboutfriend.h
|
||||
src/model/chatroom/chatroom.h
|
||||
src/model/chatroom/friendchatroom.cpp
|
||||
src/model/chatroom/friendchatroom.h
|
||||
src/model/chatroom/groupchatroom.cpp
|
||||
src/model/chatroom/groupchatroom.h
|
||||
src/model/contact.cpp
|
||||
src/model/contact.h
|
||||
src/model/friend.cpp
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
- [Filing an issue](#filing-an-issue)
|
||||
- [Must read](#must-read)
|
||||
- [Good to know](#good-to-know)
|
||||
- [Must read](#must-read)
|
||||
- [Good to know](#good-to-know)
|
||||
- [How to start contributing](#how-to-start-contributing)
|
||||
- [Before you start…](#before-you-start)
|
||||
- [Must read](#must-read)
|
||||
- [Pull request](#pull-request)
|
||||
- [How to open a pull request](#how-to-open-a-pull-reqeust)
|
||||
- [How to deal with large amounts of merge conflicts](#merge-conflicts)
|
||||
- [Git Commit Guidelines](#commit)
|
||||
- [Commit Message Format](#commit-message-format)
|
||||
- [Header](#header)
|
||||
- [Type](#type)
|
||||
- [Scope](#scope)
|
||||
- [Subject](#subject)
|
||||
- [Body](#body)
|
||||
- [Reviewing](#reviewing)
|
||||
- [Before you start…](#before-you-start)
|
||||
- [Must read](#must-read)
|
||||
- [Pull request](#pull-request)
|
||||
- [How to open a pull request](#how-to-open-a-pull-request)
|
||||
- [How to deal with large amounts of merge conflicts](#merge-conflicts)
|
||||
- [Git Commit Guidelines](#commit)
|
||||
- [Commit Message Format](#commit-message-format)
|
||||
- [Header](#header)
|
||||
- [Type](#type)
|
||||
- [Scope](#scope)
|
||||
- [Subject](#subject)
|
||||
- [Body](#body)
|
||||
- [Reviewing](#reviewing)
|
||||
- [Testing PRs](#testing-prs)
|
||||
- [Git config](#git-config)
|
||||
- [Git config](#git-config)
|
||||
- [Coding guidelines](#coding-guidelines)
|
||||
|
||||
|
||||
|
@ -122,6 +122,9 @@ git clone git@github.com:<YOUR_USER>/qTox.git
|
|||
# Add the "upstream" remote to be able to fetch from the qTox upstream repository:
|
||||
git remote add upstream https://github.com/qTox/qTox.git
|
||||
|
||||
# Fetch from the "upstream" repository
|
||||
git fetch upstream
|
||||
|
||||
# Point the local "master" branch to the "upstream" repository
|
||||
git branch master --set-upstream-to=upstream/master
|
||||
```
|
||||
|
|
|
@ -632,7 +632,7 @@ cd ..
|
|||
```bash
|
||||
git clone https://github.com/toktok/c-toxcore.git toxcore
|
||||
cd toxcore
|
||||
git checkout v0.2.1
|
||||
git checkout v0.2.3
|
||||
autoreconf -if
|
||||
./configure
|
||||
make -j$(nproc)
|
||||
|
|
166
INSTALL.md
166
INSTALL.md
|
@ -5,6 +5,7 @@
|
|||
- [Arch](#arch-easy)
|
||||
- [Fedora](#fedora-easy)
|
||||
- [Gentoo](#gentoo-easy)
|
||||
- [openSUSE](#opensuse-easy)
|
||||
- [Slackware](#slackware-easy)
|
||||
- [FreeBSD](#freebsd-easy)
|
||||
- [Install git](#install-git)
|
||||
|
@ -22,13 +23,6 @@
|
|||
- [Slackware](#slackware-other-deps)
|
||||
- [Ubuntu >=15.04](#ubuntu-other-deps)
|
||||
- [Ubuntu >=16.04](#ubuntu-other-1604-deps)
|
||||
- [toxcore dependencies](#toxcore-dependencies)
|
||||
- [Arch](#arch-toxcore)
|
||||
- [Debian](#debian-toxcore)
|
||||
- [Fedora](#fedora-toxcore)
|
||||
- [openSUSE](#opensuse-toxcore)
|
||||
- [Slackware](#slackware-toxcore)
|
||||
- [Ubuntu >=15.04](#ubuntu-toxcore)
|
||||
- [sqlcipher](#sqlcipher)
|
||||
- [Compile toxcore](#compile-toxcore)
|
||||
- [Compile qTox](#compile-qtox)
|
||||
|
@ -69,6 +63,18 @@ dependencies are missing.
|
|||
|---------|---------|
|
||||
| [Check] | >= 0.9 |
|
||||
|
||||
### Spell checking support
|
||||
|
||||
| Name | Version |
|
||||
|----------|---------|
|
||||
| [sonnet] | >= 5.45 |
|
||||
|
||||
Use `-DSPELL_CHECK=OFF` to disable it.
|
||||
|
||||
**Note:** Specified version was tested and works well. You can try to use older
|
||||
version, but in this case you may have some errors (including a complete lack
|
||||
of spell check).
|
||||
|
||||
### Linux
|
||||
|
||||
#### Auto-away support
|
||||
|
@ -155,6 +161,24 @@ To install:
|
|||
emerge qtox
|
||||
```
|
||||
|
||||
<a name="opensuse-easy" />
|
||||
|
||||
#### openSUSE
|
||||
|
||||
qTox is available in openSUSE Factory.
|
||||
|
||||
To install in openSUSE 15.0 or newer:
|
||||
|
||||
```bash
|
||||
zypper in qtox
|
||||
```
|
||||
|
||||
To install in openSUSE 42.3:
|
||||
|
||||
```bash
|
||||
zypper ar -f https://download.opensuse.org/repositories/server:/messaging/openSUSE_Leap_42.3 server:messaging
|
||||
zypper in qtox
|
||||
```
|
||||
|
||||
<a name="slackware-easy" />
|
||||
|
||||
|
@ -263,7 +287,7 @@ corresponding parts.
|
|||
#### Arch Linux
|
||||
|
||||
```bash
|
||||
sudo pacman -S --needed base-devel qt5 openal libxss qrencode ffmpeg
|
||||
sudo pacman -S --needed base-devel qt5 openal libxss qrencode ffmpeg opus libvpx libsodium
|
||||
```
|
||||
|
||||
|
||||
|
@ -275,18 +299,28 @@ sudo pacman -S --needed base-devel qt5 openal libxss qrencode ffmpeg
|
|||
|
||||
```bash
|
||||
sudo apt-get install \
|
||||
automake \
|
||||
autotools-dev \
|
||||
build-essential \
|
||||
check \
|
||||
checkinstall \
|
||||
cmake \
|
||||
ffmpeg \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libexif-dev \
|
||||
libgdk-pixbuf2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libkdeui5 \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libsodium-dev \
|
||||
libsqlcipher-dev \
|
||||
libtool \
|
||||
libvpx-dev \
|
||||
libxss-dev \
|
||||
pkg-config \
|
||||
qrencode \
|
||||
|
@ -310,20 +344,28 @@ have to compile it yourself, otherwise compiling qTox will fail.**
|
|||
sudo dnf groupinstall "Development Tools" "C Development Tools and Libraries"
|
||||
# (can also use sudo dnf install @"Development Tools")
|
||||
sudo dnf install \
|
||||
autoconf \
|
||||
automake \
|
||||
check \
|
||||
check-devel \
|
||||
ffmpeg-devel \
|
||||
gtk2-devel \
|
||||
kf5-sonnet \
|
||||
libexif-devel \
|
||||
libXScrnSaver-devel \
|
||||
libsodium-devel \
|
||||
libtool \
|
||||
libvpx-devel \
|
||||
libXScrnSaver-devel \
|
||||
openal-soft-devel \
|
||||
openssl-devel \
|
||||
opus-devel \
|
||||
qrencode-devel \
|
||||
qt-creator \
|
||||
qt-devel \
|
||||
qt-doc \
|
||||
qt5-linguist \
|
||||
qt5-qtsvg \
|
||||
qt5-qtsvg-devel \
|
||||
qt-creator \
|
||||
qt-devel \
|
||||
qt-doc \
|
||||
qtsingleapplication \
|
||||
sqlcipher \
|
||||
sqlcipher-devel
|
||||
|
@ -338,25 +380,32 @@ sudo dnf install \
|
|||
```bash
|
||||
sudo zypper install \
|
||||
libexif-devel \
|
||||
libffmpeg-devel \
|
||||
libopus-devel \
|
||||
libQt5Concurrent-devel \
|
||||
libqt5-linguist \
|
||||
libQt5Network-devel \
|
||||
libQt5OpenGL-devel \
|
||||
libQt5Xml-devel \
|
||||
libXScrnSaver-devel \
|
||||
libffmpeg-devel \
|
||||
libqt5-linguist \
|
||||
libqt5-qtbase-common-devel \
|
||||
libqt5-qtsvg-devel \
|
||||
libQt5Xml-devel \
|
||||
libsodium-devel \
|
||||
libvpx-devel \
|
||||
libXScrnSaver-devel \
|
||||
openal-soft-devel \
|
||||
patterns-openSUSE-devel_basis \
|
||||
qrencode-devel \
|
||||
sqlcipher-devel
|
||||
sqlcipher-devel \
|
||||
sonnet-devel
|
||||
```
|
||||
|
||||
<a name="slackware-other-deps" />
|
||||
|
||||
#### Slackware
|
||||
|
||||
List of all the toxcore dependencies and their SlackBuilds can be found
|
||||
here: http://slackbuilds.org/repository/14.2/network/toxcore/
|
||||
|
||||
List of all the qTox dependencies and their SlackBuilds can be found here:
|
||||
http://slackbuilds.org/repository/14.2/network/qTox/
|
||||
|
||||
|
@ -367,7 +416,11 @@ http://slackbuilds.org/repository/14.2/network/qTox/
|
|||
|
||||
```bash
|
||||
sudo apt-get install \
|
||||
automake \
|
||||
autotools-dev \
|
||||
build-essential cmake \
|
||||
check \
|
||||
checkinstall \
|
||||
libavcodec-ffmpeg-dev \
|
||||
libavdevice-ffmpeg-dev \
|
||||
libavfilter-ffmpeg-dev \
|
||||
|
@ -376,13 +429,18 @@ sudo apt-get install \
|
|||
libgdk-pixbuf2.0-dev \
|
||||
libglib2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libkdeui5 \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libsodium-dev \
|
||||
libsqlcipher-dev \
|
||||
libswresample-ffmpeg-dev \
|
||||
libswscale-ffmpeg-dev \
|
||||
libtool \
|
||||
libvpx-dev \
|
||||
libxss-dev \
|
||||
qrencode \
|
||||
qt5-default \
|
||||
|
@ -405,13 +463,17 @@ sudo apt-get install \
|
|||
libgdk-pixbuf2.0-dev \
|
||||
libglib2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libkdeui5 \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libsodium-dev \
|
||||
libsqlcipher-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libvpx-dev \
|
||||
libxss-dev \
|
||||
qrencode \
|
||||
qt5-default \
|
||||
|
@ -419,63 +481,6 @@ sudo apt-get install \
|
|||
qttools5-dev
|
||||
```
|
||||
|
||||
### toxcore dependencies
|
||||
|
||||
Install all of the toxcore dependencies.
|
||||
|
||||
<a name="arch-toxcore" />
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
```bash
|
||||
sudo pacman -S --needed opus libvpx libsodium
|
||||
```
|
||||
|
||||
<a name="debian-toxcore" />
|
||||
|
||||
#### Debian
|
||||
|
||||
```bash
|
||||
sudo apt-get install libtool autotools-dev automake checkinstall check \
|
||||
libopus-dev libvpx-dev libsodium-dev libavdevice-dev
|
||||
```
|
||||
|
||||
<a name="fedora-toxcore" />
|
||||
|
||||
#### Fedora
|
||||
|
||||
```bash
|
||||
sudo dnf install libtool autoconf automake check check-devel libsodium-devel \
|
||||
opus-devel libvpx-devel
|
||||
```
|
||||
|
||||
<a name="opensuse-toxcore" />
|
||||
|
||||
#### openSUSE
|
||||
|
||||
```bash
|
||||
sudo zypper install libsodium-devel libvpx-devel libopus-devel \
|
||||
patterns-openSUSE-devel_basis
|
||||
```
|
||||
|
||||
<a name="slackware-toxcore" />
|
||||
|
||||
#### Slackware
|
||||
|
||||
List of all the toxcore dependencies and their SlackBuilds can be found
|
||||
here: http://slackbuilds.org/repository/14.2/network/toxcore/
|
||||
|
||||
|
||||
<a name="ubuntu-toxcore" />
|
||||
|
||||
#### Ubuntu >=15.04
|
||||
|
||||
```bash
|
||||
sudo apt-get install libtool autotools-dev automake checkinstall check \
|
||||
libopus-dev libvpx-dev libsodium-dev
|
||||
```
|
||||
|
||||
|
||||
### sqlcipher
|
||||
|
||||
If you are not using an old version of Fedora, skip this section, and go
|
||||
|
@ -494,12 +499,14 @@ cd ..
|
|||
|
||||
### Compile toxcore
|
||||
|
||||
Normally you don't want to do that, `bootstrap.sh` will do it for you.
|
||||
|
||||
Provided that you have all required dependencies installed, you can simply run:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/toktok/c-toxcore.git toxcore
|
||||
cd toxcore
|
||||
git checkout v0.2.2
|
||||
git checkout v0.2.3
|
||||
cmake .
|
||||
make -j$(nproc)
|
||||
sudo make install
|
||||
|
@ -720,9 +727,9 @@ Download the MinGW installer for Windows from
|
|||
[sourceforge.net](http://sourceforge.net/projects/mingw/files/Installer/). Make
|
||||
sure to install MSYS (a set of Unix tools for Windows). The following steps
|
||||
assume that MinGW is installed at `C:\MinGW`. If you decided to choose another
|
||||
location, replace corresponding parts. Select `mingw-developer-toolkit`,
|
||||
`mingw32-base`, `mingw32-gcc-g++`, `msys-base` and `mingw32-pthreads-w32`
|
||||
packages using MinGW Installation Manager (`mingw-get.exe`). Check that the
|
||||
location, replace corresponding parts. Select `mingw-developer-toolkit`,
|
||||
`mingw32-base`, `mingw32-gcc-g++`, `msys-base` and `mingw32-pthreads-w32`
|
||||
packages using MinGW Installation Manager (`mingw-get.exe`). Check that the
|
||||
version of MinGW, corresponds to the version of the QT component!
|
||||
|
||||
#### Wget
|
||||
|
@ -750,7 +757,7 @@ second box search for the `PATH` variable and press `Edit...`. The input box
|
|||
separated with a semicolon. Extend the input box by adding
|
||||
`;C:\MinGW\bin;C:\MinGW\msys\1.0\bin;C:\Program Files (x86)\CMake 2.8\bin;C:\Program Files (x86)\GnuWin32\bin`.
|
||||
The very first semicolon must only be added if it is missing. CMake may be added
|
||||
by installer automatically. Make sure that paths containing alternative `sh`,
|
||||
by installer automatically. Make sure that paths containing alternative `sh`,
|
||||
`bash` implementations such as `C:\Program Files\OpenSSH\bin` are at the end of
|
||||
`PATH` or build may fail.
|
||||
|
||||
|
@ -815,3 +822,4 @@ Switches:
|
|||
[sqlcipher]: https://www.zetetic.net/sqlcipher/
|
||||
[toxcore]: https://github.com/TokTok/c-toxcore/
|
||||
[filteraudio]: https://github.com/irungentoo/filter_audio
|
||||
[sonnet]: https://github.com/KDE/sonnet
|
||||
|
|
|
@ -110,42 +110,16 @@ translations, on the other, it lessened problems that were happening with
|
|||
|
||||
To get translations into qTox:
|
||||
|
||||
1. Add Weblate: `git remote add weblate
|
||||
https://hosted.weblate.org/git/tox/qtox/`
|
||||
2. Fetch newest: `git fetch weblate`
|
||||
3. Check what has been changed compared to master: `git log --no-merges
|
||||
master..weblate/master`
|
||||
4. Cherry-pick from the oldest commit.
|
||||
- check if there are multiple commits from the same author for the same
|
||||
translation. If there are, cherry-pick them accordingly:
|
||||
|
||||
```
|
||||
git cherry-pick <commit1> <commit2>
|
||||
```
|
||||
|
||||
5. If there were multiple commits, squash them into a single one, leaving only
|
||||
a single `feat(l10n): …` line in the commit message.
|
||||
6. Get rid of Weblate's formatting and amend the commit using
|
||||
[`./tools/deweblate-translation-file.sh`], i.e.:
|
||||
|
||||
```
|
||||
./tools/deweblate-translation-file.sh
|
||||
```
|
||||
|
||||
7. For translations that haven't yet been cherry-picked repeat steps 4-6.
|
||||
8. Once done with cherry-picking, update all translation files, so that Weblate
|
||||
would get newest strings that changed in qTox:
|
||||
|
||||
```
|
||||
./tools/update-translation-files.sh ALL
|
||||
```
|
||||
|
||||
9. Once PR with translation gets merged, `Reset` Weblate to current `master`,
|
||||
since without reset there would be a git conflict that would prevent Weblate
|
||||
from getting new strings.
|
||||
|
||||
**It's a good idea to lock translations on Weblate while they're in merge
|
||||
process, so that no translation effort would be lost when resetting Weblate.**
|
||||
1. Go to `https://hosted.weblate.org/projects/tox/qtox/#repository` and lock
|
||||
the repository for translations.
|
||||
2. Make sure you have git setup to automatically gpg sign commits
|
||||
3. In the root of the qTox repository execute the script
|
||||
`tools/update-weblate.sh`
|
||||
4. Check what has been changed compared to master: `git diff upstream/master`
|
||||
5. Checkout a new branch with e.g. `git checkout -b update_weblate` and open
|
||||
a Pull Request for it on Github.
|
||||
6. After the Pull Request has been merged, unlock Weblate and `reset` it to
|
||||
master
|
||||
|
||||
## Adding new translations
|
||||
|
||||
|
@ -215,6 +189,12 @@ Follow steps for adding translations from Weblate up to step 5. Next:
|
|||
- Update download links on https://tox.chat to point to the new release.
|
||||
- Write a short blog post for https://github.com/qTox/blog/ and advertise the post
|
||||
on Tox IRC channels, popular Tox groups, reddit, or whatever other platforms.
|
||||
- Open a PR to update the Flatpak manifest of our [Flathub repository] with the
|
||||
changes from [`./flatpak/io.github.qtox.qTox.json`].
|
||||
- Comment to the PR with `bot, build` to execute a test build
|
||||
- After the build passed for qTox on all architectures on
|
||||
[the Flathub build bot], merge the PR into the master branch of our
|
||||
[Flathub repository].
|
||||
|
||||
|
||||
# How to become a maintainer?
|
||||
|
@ -236,3 +216,6 @@ helping for a while, ask to be added to the `qTox` organization on GitHub.
|
|||
[`./tools/deweblate-translation-file.sh`]: /tools/deweblate-translation-file.sh
|
||||
[`./tools/create-tarball.sh`]: /tools/create-tarball.sh
|
||||
[`./tools/update-versions.sh`]: /tools/update-versions.sh
|
||||
[Flathub repository]: https://github.com/flathub/io.github.qtox.qTox
|
||||
[`./flatpak/io.github.qtox.qTox.json`]: flatpak/io.github.qtox.qTox.json
|
||||
[the Flathub build bot]: https://flathub.org/builds/#/
|
||||
|
|
41
README.md
41
README.md
|
@ -45,9 +45,9 @@ while running on all major platforms.
|
|||
|
||||
Windows | Linux | OS X | FreeBSD
|
||||
--------|-------|------|--------
|
||||
**[64 bit release]**| **[Arch]**, **[Fedora]**, **[Gentoo]** | **[Latest release]** | **[Package & Port]**
|
||||
[32 bit release]| | [Building instructions] |
|
||||
[64 bit][64nightly], [32 bit][32nightly] nigthly | [Other] | |
|
||||
**[64 bit release]**| **[Arch]**, **[Fedora]**, **[Gentoo]**, **[openSUSE]** | **[Latest release]** | **[Package & Port]**
|
||||
[32 bit release]|**[AppImage]**, [Flatpak] | [Building instructions] |
|
||||
[64 bit][64nightly], [32 bit][32nightly] nigthly | [From Source] | |
|
||||
|
||||
_**Bold** options are recommended._
|
||||
|
||||
|
@ -70,6 +70,25 @@ Some of them are:
|
|||
* [Translating, it's easy]
|
||||
* [Reviewing and testing pull requests] – you don't need to be able to code to
|
||||
do that :wink:
|
||||
* Take a task from our Roadmap below
|
||||
|
||||
### Roadmap
|
||||
|
||||
Currently qTox is under a feature freeze to clean up our codebase and tools.
|
||||
During this time we want to prepare qTox for upcoming new features of toxcore.
|
||||
|
||||
The next steps are:
|
||||
|
||||
|
||||
* remove support for toxcore < 0.2.0
|
||||
* move all toxcore abstractions into their own subproject
|
||||
* write basic tests for this Core
|
||||
* format the code base
|
||||
* rework our TravisCI setup for faster PR checks
|
||||
* rethink our Issue tracker
|
||||
|
||||
The current state is tracked in the [Code cleanup] project.
|
||||
|
||||
|
||||
|
||||
### Screenshots
|
||||
|
@ -117,17 +136,17 @@ Active qTox maintainers:
|
|||
```
|
||||
7EB3 39FE 8817 47E7 01B7 D472 EBE3 6E66 A842 9B99 - Anthony Bilinski
|
||||
3103 9166 FA90 2CA5 0D05 D608 5AF9 F2E2 9107 C727 – Diadlo
|
||||
C7A2 552D 0B25 0F98 3827 742C 1332 03A3 AC39 9151 – initramfs
|
||||
CA92 21C5 389B 7C50 AA5F 7793 52A5 0775 BE13 DF17 - noavarice
|
||||
DA26 2CC9 3C0E 1E52 5AD2 1C85 9677 5D45 4B8E BF44 – sudden6
|
||||
141C 880E 8BA2 5B19 8D0F 850F 7C13 2143 C1A3 A7D4 – tox-user
|
||||
2880 C860 D95C 909D 3DA4 5C68 7E08 6DD6 6126 3264 – tux3
|
||||
BA78 83E2 2F9D 3594 5BA3 3760 5313 7C30 33F0 9008 – zetok
|
||||
```
|
||||
|
||||
Past qTox maintainers:
|
||||
|
||||
```
|
||||
C7A2 552D 0B25 0F98 3827 742C 1332 03A3 AC39 9151 – initramfs
|
||||
BA78 83E2 2F9D 3594 5BA3 3760 5313 7C30 33F0 9008 – zetok
|
||||
F365 8D0A 04A5 76A4 1072 FC0D 296F 0B76 4741 106C – agilob
|
||||
1157 616B BD86 0C53 9926 F813 9591 A163 FF9B E04C – antis81
|
||||
1D29 8BC7 25B7 BE82 65BA EAB9 3DB8 E053 15C2 20AA – Dubslow
|
||||
|
@ -140,23 +159,26 @@ AED3 1134 9C23 A123 E5C4 AA4B 139C A045 3DA2 D773
|
|||
```
|
||||
|
||||
[#qtox@freenode]: https://webchat.freenode.net/?channels=qtox
|
||||
[64 bit release]: https://github.com/qTox/qTox/releases/download/v1.15.0/setup-qtox-x86_64-release.exe
|
||||
[32 bit release]: https://github.com/qTox/qTox/releases/download/v1.15.0/setup-qtox-i686-release.exe
|
||||
[64 bit release]: https://github.com/qTox/qTox/releases/download/v1.16.3/setup-qtox-x86_64-release.exe
|
||||
[32 bit release]: https://github.com/qTox/qTox/releases/download/v1.16.3/setup-qtox-i686-release.exe
|
||||
[32nightly]: https://build.tox.chat/view/qtox/job/qTox-cmake-nightly_build_windows_x86_release/lastSuccessfulBuild/artifact/qTox-cmake-nightly_build_windows_x86_release.zip
|
||||
[64nightly]: https://build.tox.chat/view/qtox/job/qTox-cmake-nightly_build_windows_x86-64_release/lastSuccessfulBuild/artifact/qTox-cmake-nightly_build_windows_x86-64_release.zip
|
||||
[Flatpak]: https://github.com/qTox/qTox/releases/download/v1.16.1/qTox-v1.16.1.x86_64.flatpak
|
||||
[AppImage]: https://github.com/qTox/qTox/releases/download/v1.16.1/qTox-v1.16.1.x86_64.AppImage
|
||||
[Arch]: /INSTALL.md#arch
|
||||
[Building instructions]: /INSTALL.md#os-x
|
||||
[Contributing]: /CONTRIBUTING.md#how-to-start-contributing
|
||||
[easy issues]: https://github.com/qTox/qTox/labels/E-easy
|
||||
[Latest release]: https://github.com/qTox/qTox/releases/download/v1.15.0/qTox.dmg
|
||||
[Latest release]: https://github.com/qTox/qTox/releases/download/v1.16.3/qTox.dmg
|
||||
[Fedora]: /INSTALL.md#fedora
|
||||
[Gentoo]: /INSTALL.md#gentoo
|
||||
[openSUSE]: /INSTALL.md#opensuse
|
||||
[Install/Build]: /INSTALL.md
|
||||
[IRC logs]: https://github.com/qTox/qtox-irc-logs
|
||||
[issues that need help]: https://github.com/qTox/qTox/labels/help%20wanted
|
||||
[Jenkins builds]: https://build.tox.chat/
|
||||
[Mailing list]: https://lists.tox.chat
|
||||
[Other]: /INSTALL.md#linux
|
||||
[From Source]: /INSTALL.md#linux
|
||||
[qTox-dev mailing list]: https://lists.tox.chat/listinfo/qtox-dev
|
||||
[Package & Port]: /INSTALL.md#freebsd-easy
|
||||
[Report bugs]: https://github.com/qTox/qTox/wiki/Writing-Useful-Bug-Reports
|
||||
|
@ -169,3 +191,4 @@ AED3 1134 9C23 A123 E5C4 AA4B 139C A045 3DA2 D773
|
|||
[Translating, it's easy]: /translations/README.md
|
||||
[User Manual]: /doc/user_manual_en.md
|
||||
[voice it in the issues that need it]: https://github.com/qTox/qTox/labels/I-feedback-wanted
|
||||
[Code cleanup]: https://github.com/qTox/qTox/projects/3?fullscreen=true
|
||||
|
|
|
@ -22,6 +22,16 @@
|
|||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
|
||||
# usage: ./appimage/build-appimage.sh [Debug]
|
||||
#
|
||||
# If [Debug] is set to "Debug" the container will run in interactive mode and
|
||||
# stay open to poke around in the filesystem.
|
||||
|
||||
readonly DEBUG="$1"
|
||||
|
||||
# Fail out on error
|
||||
set -exo pipefail
|
||||
|
||||
# This script should be run from the root of the repository
|
||||
|
||||
if [ ! -f ./appimage/build-appimage.sh ]; then
|
||||
|
@ -35,14 +45,26 @@ fi
|
|||
|
||||
mkdir -p ./output
|
||||
|
||||
docker run --rm \
|
||||
-v $PWD:/qtox \
|
||||
-v $PWD/output:/output \
|
||||
debian:stretch-slim \
|
||||
/bin/bash -c "/qtox/appimage/build.sh"
|
||||
|
||||
if [ "$DEBUG" == "Debug" ]
|
||||
then
|
||||
echo "Execute: /qtox/appimage/build.sh to start the build script"
|
||||
echo "Execute: exit to leave the container"
|
||||
|
||||
docker run --rm -it \
|
||||
-v $PWD:/qtox \
|
||||
-v $PWD/output:/output \
|
||||
debian:stretch-slim \
|
||||
/bin/bash
|
||||
else
|
||||
docker run --rm \
|
||||
-v $PWD:/qtox \
|
||||
-v $PWD/output:/output \
|
||||
debian:stretch-slim \
|
||||
/bin/bash -c "/qtox/appimage/build.sh"
|
||||
fi
|
||||
|
||||
# use the version number in the name when building a tag on Travis CI
|
||||
if [ -n "$TRAVIS_TAG" ]
|
||||
then
|
||||
mv ./output/*.AppImage ./output/qTox-"$TRAVIS_TAG".AppImage
|
||||
mv ./output/*.AppImage ./output/qTox-"$TRAVIS_TAG".x86_64.AppImage
|
||||
fi
|
||||
|
|
30
bootstrap.sh
30
bootstrap.sh
|
@ -31,8 +31,8 @@ readonly INSTALL_DIR=libs
|
|||
readonly BASE_DIR="${SCRIPT_DIR}/${INSTALL_DIR}"
|
||||
|
||||
# versions of libs to checkout
|
||||
readonly TOXCORE_VERSION="v0.2.2"
|
||||
readonly SQLCIPHER_VERSION="v3.4.0"
|
||||
readonly TOXCORE_VERSION="v0.2.3"
|
||||
readonly SQLCIPHER_VERSION="v3.4.2"
|
||||
|
||||
# directory names of cloned repositories
|
||||
readonly TOXCORE_DIR="libtoxcore-$TOXCORE_VERSION"
|
||||
|
@ -93,32 +93,16 @@ install_toxcore() {
|
|||
"${BASE_DIR}/${TOXCORE_DIR}"
|
||||
|
||||
pushd ${BASE_DIR}/${TOXCORE_DIR}
|
||||
./autogen.sh
|
||||
|
||||
# configure
|
||||
if [[ $SYSTEM_WIDE = "false" ]]
|
||||
then
|
||||
./configure --prefix=${BASE_DIR}
|
||||
else
|
||||
./configure
|
||||
fi
|
||||
|
||||
# ensure A/V support is enabled
|
||||
if ! grep -Fxq "BUILD_AV_TRUE=''" config.log
|
||||
then
|
||||
echo "A/V support of libtoxcore is disabled but required by qTox. Aborting."
|
||||
echo "Maybe the dev-packages of libopus and libvpx are not installed?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compile
|
||||
make -j $(nproc)
|
||||
|
||||
# install
|
||||
# compile and install
|
||||
if [[ $SYSTEM_WIDE = "false" ]]
|
||||
then
|
||||
cmake . -DCMAKE_INSTALL_PREFIX=${BASE_DIR}
|
||||
make -j $(nproc)
|
||||
make install
|
||||
else
|
||||
cmake .
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
fi
|
||||
|
|
|
@ -112,6 +112,16 @@ search_dependency(LIBSWSCALE PACKAGE libswscale)
|
|||
search_dependency(SQLCIPHER PACKAGE sqlcipher)
|
||||
search_dependency(VPX PACKAGE vpx)
|
||||
|
||||
if(${SPELL_CHECK})
|
||||
find_package(KF5Sonnet)
|
||||
if(KF5Sonnet_FOUND)
|
||||
add_definitions(-DSPELL_CHECKING)
|
||||
add_dependency(KF5::SonnetUi)
|
||||
else()
|
||||
message(WARNING "Sonnet not found. Spell checking will be disabled.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Try to find cmake toxcore libraries
|
||||
if(WIN32)
|
||||
search_dependency(TOXCORE PACKAGE toxcore OPTIONAL STATIC_PACKAGE)
|
||||
|
|
55
doc/TCS_state.md
Normal file
55
doc/TCS_state.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# qTox TCS Support state
|
||||
|
||||
All section number refer to a section in the [TCS document].
|
||||
|
||||
|Symbol|Description|
|
||||
|------|-----------|
|
||||
|Y| qTox implements this point|
|
||||
|N| qTox is missing this point, add issue number|
|
||||
|U| Unknown if qTox supports this point|
|
||||
|
||||
|TCS Section | qTox State |
|
||||
|------------|------------|
|
||||
| 1.0.1 |U|
|
||||
| 1.0.2 |U|
|
||||
| 1.0.3 |U|
|
||||
| 1.0.4 |U|
|
||||
| 2.1.1 |U|
|
||||
| 2.1.2 |U|
|
||||
| 2.2.1 |U|
|
||||
| 2.2.2 |U|
|
||||
| 2.2.3 |U|
|
||||
| 2.2.4 |U|
|
||||
| 2.2.5 |U|
|
||||
| 2.2.6 |U|
|
||||
| 2.2.7 |U|
|
||||
| 2.2.8 |U|
|
||||
| 2.2.9 |U|
|
||||
| 2.2.10 |U|
|
||||
| 2.2.11 |U|
|
||||
| 3.1.1 |U|
|
||||
| 3.1.2 |U|
|
||||
| 3.2.1 |U|
|
||||
| 3.2.2 |U|
|
||||
| 3.2.3 |U|
|
||||
| 3.3.1 |U|
|
||||
| 3.3.2 |U|
|
||||
| 3.3.3 |U|
|
||||
| 3.4.1 |U|
|
||||
| 3.4.2 |U|
|
||||
| 3.3.1 |U|
|
||||
| 3.3.2 |U|
|
||||
| 3.3.3 |U|
|
||||
| 3.3.4 |U|
|
||||
| 3.3.5 |U|
|
||||
| 4.0.1 |U|
|
||||
| 4.0.2 |U|
|
||||
| 5.0.1 |U|
|
||||
| 5.0.2 |U|
|
||||
| 5.0.3 |U|
|
||||
| 5.0.4 |U|
|
||||
| 5.1.1 |U|
|
||||
| 5.1.2 |U|
|
||||
| 5.1.3 |U|
|
||||
|
||||
[TCS document]: https://tox.gitbooks.io/tox-client-standard/content/
|
46
docker/Dockerfile.debian
Normal file
46
docker/Dockerfile.debian
Normal file
|
@ -0,0 +1,46 @@
|
|||
FROM debian:stretch
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y --force-yes install \
|
||||
automake \
|
||||
autotools-dev \
|
||||
build-essential \
|
||||
check \
|
||||
checkinstall \
|
||||
cmake \
|
||||
ffmpeg \
|
||||
git \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libexif-dev \
|
||||
libgdk-pixbuf2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libsodium-dev \
|
||||
libsqlcipher-dev \
|
||||
libtool \
|
||||
libvpx-dev \
|
||||
libxss-dev \
|
||||
pkg-config \
|
||||
qrencode \
|
||||
qt5-default \
|
||||
qttools5-dev \
|
||||
qttools5-dev-tools \
|
||||
yasm
|
||||
|
||||
RUN git clone https://github.com/toktok/c-toxcore.git /toxcore
|
||||
WORKDIR /toxcore
|
||||
RUN git checkout v0.2.2 && \
|
||||
cmake . && \
|
||||
cmake --build . && \
|
||||
make install && \
|
||||
echo '/usr/local/lib/' >> /etc/ld.so.conf.d/locallib.conf && \
|
||||
ldconfig
|
||||
|
||||
COPY . /qtox
|
||||
WORKDIR /qtox
|
||||
RUN cmake . && cmake --build .
|
43
docker/Dockerfile.ubuntu
Normal file
43
docker/Dockerfile.ubuntu
Normal file
|
@ -0,0 +1,43 @@
|
|||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get -y --force-yes install \
|
||||
build-essential \
|
||||
cmake \
|
||||
git \
|
||||
libavcodec-dev \
|
||||
libavdevice-dev \
|
||||
libavfilter-dev \
|
||||
libavutil-dev \
|
||||
libexif-dev \
|
||||
libgdk-pixbuf2.0-dev \
|
||||
libglib2.0-dev \
|
||||
libgtk2.0-dev \
|
||||
libopenal-dev \
|
||||
libopus-dev \
|
||||
libqrencode-dev \
|
||||
libqt5opengl5-dev \
|
||||
libqt5svg5-dev \
|
||||
libsodium-dev \
|
||||
libsqlcipher-dev \
|
||||
libswresample-dev \
|
||||
libswscale-dev \
|
||||
libvpx-dev \
|
||||
libxss-dev \
|
||||
qrencode \
|
||||
qt5-default \
|
||||
qttools5-dev-tools \
|
||||
qttools5-dev
|
||||
|
||||
RUN git clone https://github.com/toktok/c-toxcore.git /toxcore
|
||||
WORKDIR /toxcore
|
||||
RUN git checkout v0.2.2 && \
|
||||
cmake . && \
|
||||
cmake --build . && \
|
||||
make install && \
|
||||
echo '/usr/local/lib/' >> /etc/ld.so.conf.d/locallib.conf && \
|
||||
ldconfig
|
||||
|
||||
COPY . /qtox
|
||||
WORKDIR /qtox
|
||||
RUN cmake . && cmake --build .
|
5
docker/build-debian.sh
Executable file
5
docker/build-debian.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
docker build . -f docker/Dockerfile.debian -t qtox
|
||||
cd -
|
5
docker/build-ubuntu.sh
Executable file
5
docker/build-ubuntu.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
docker build . -f docker/Dockerfile.ubuntu -t qtox
|
||||
cd -
|
7
docker/start-qtox.sh
Executable file
7
docker/start-qtox.sh
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
XSOCK=/tmp/.X11-unix
|
||||
XAUTH=/tmp/.docker.xauth
|
||||
touch $XAUTH
|
||||
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
|
||||
docker run -ti --rm -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH -e DISPLAY=$DISPLAY -e XAUTHORITY=$XAUTH qtox ./qtox
|
52
flatpak/build-flatpak.sh
Executable file
52
flatpak/build-flatpak.sh
Executable file
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0+
|
||||
#
|
||||
# Copyright © 2018 by The qTox Project Contributors
|
||||
#
|
||||
# This script should be run from the root of the repository
|
||||
|
||||
# usage: ./flatpak/build-flatpak.sh [Debug]
|
||||
#
|
||||
# If [Debug] is set to "Debug" the container will run in interactive mode and
|
||||
# stay open to poke around in the filesystem.
|
||||
|
||||
readonly DEBUG="$1"
|
||||
|
||||
# Fail out on error
|
||||
set -exo pipefail
|
||||
|
||||
if [ ! -f ./flatpak/build-flatpak.sh ]; then
|
||||
echo ""
|
||||
echo "You are attempting to run the build-flatpak.sh from a wrong directory."
|
||||
echo "If you wish to run this script, you'll have to have"
|
||||
echo "the repository root directory as the working directory."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p ./output
|
||||
|
||||
if [ "$DEBUG" == "Debug" ]
|
||||
then
|
||||
echo "Execute: /qtox/appimage/build.sh to start the build script"
|
||||
echo "Execute: exit to leave the container"
|
||||
|
||||
docker run --rm --privileged -it \
|
||||
-v $PWD:/qtox \
|
||||
-v $PWD/output:/output \
|
||||
debian:stretch-slim \
|
||||
/bin/bash
|
||||
else
|
||||
docker run --rm --privileged \
|
||||
-v $PWD:/qtox \
|
||||
-v $PWD/output:/output \
|
||||
debian:stretch-slim \
|
||||
/bin/bash -c "/qtox/flatpak/build.sh"
|
||||
fi
|
||||
|
||||
# use the version number in the name when building a tag on Travis CI
|
||||
if [ -n "$TRAVIS_TAG" ]
|
||||
then
|
||||
mv ./output/*.flatpak ./output/qTox-"$TRAVIS_TAG".x86_64.flatpak
|
||||
fi
|
56
flatpak/build.sh
Executable file
56
flatpak/build.sh
Executable file
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# SPDX-License-Identifier: GPL-3.0+
|
||||
#
|
||||
# Copyright © 2018 by The qTox Project Contributors
|
||||
|
||||
# Fail out on error
|
||||
set -exuo pipefail
|
||||
|
||||
# directory paths
|
||||
readonly QTOX_SRC_DIR="/qtox"
|
||||
readonly OUTPUT_DIR="/output"
|
||||
readonly BUILD_DIR="/build"
|
||||
readonly QTOX_BUILD_DIR="$BUILD_DIR"/qtox
|
||||
readonly FP_BUILD_DIR="$BUILD_DIR"/flatpak
|
||||
readonly APT_FLAGS="-y --no-install-recommends"
|
||||
# flatpak manifest download location
|
||||
readonly MANIFEST_FILE="flatpak/io.github.qtox.qTox.json"
|
||||
# directory containing necessary patches
|
||||
readonly PATCH_DIR="flatpak/patches"
|
||||
# use multiple cores when building
|
||||
export MAKEFLAGS="-j$(nproc)"
|
||||
|
||||
# add backports repo, needed for a recent enough flatpak
|
||||
echo "deb http://ftp.debian.org/debian stretch-backports main" > /etc/apt/sources.list.d/stretch-backports.list
|
||||
|
||||
# Get packages
|
||||
apt-get update
|
||||
apt-get install $APT_FLAGS ca-certificates git elfutils wget xz-utils patch bzip2
|
||||
|
||||
# install recent flatpak packages
|
||||
apt-get install $APT_FLAGS -t stretch-backports flatpak flatpak-builder
|
||||
|
||||
# create build directory
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# copy qtox source
|
||||
cp -r "$QTOX_SRC_DIR" "$QTOX_BUILD_DIR"
|
||||
cd "$QTOX_BUILD_DIR"
|
||||
|
||||
# create flatpak build directory
|
||||
mkdir -p "$FP_BUILD_DIR"
|
||||
cd "$FP_BUILD_DIR"
|
||||
|
||||
# Add 'https://flathub.org' remote:
|
||||
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
|
||||
|
||||
# Build the qTox flatpak
|
||||
flatpak-builder --disable-rofiles-fuse --install-deps-from=flathub --force-clean --repo=tox-repo qTox-flatpak "$QTOX_BUILD_DIR"/flatpak/io.github.qtox.qTox.json
|
||||
|
||||
# Create a bundle for distribution
|
||||
flatpak build-bundle tox-repo "$OUTPUT_DIR"/qtox.flatpak io.github.qtox.qTox
|
||||
|
||||
# Chmod since everything is root:root
|
||||
chmod 755 -R "$OUTPUT_DIR"
|
157
flatpak/io.github.qtox.qTox.json
Normal file
157
flatpak/io.github.qtox.qTox.json
Normal file
|
@ -0,0 +1,157 @@
|
|||
{
|
||||
"app-id": "io.github.qtox.qTox",
|
||||
"runtime": "org.kde.Platform",
|
||||
"sdk": "org.kde.Sdk",
|
||||
"runtime-version": "5.11",
|
||||
"command": "qtox",
|
||||
"rename-icon": "qtox",
|
||||
"finish-args": [
|
||||
"--share=network",
|
||||
"--socket=pulseaudio",
|
||||
"--socket=wayland",
|
||||
"--socket=x11",
|
||||
"--share=ipc",
|
||||
"--filesystem=xdg-desktop",
|
||||
"--filesystem=xdg-documents",
|
||||
"--filesystem=xdg-download",
|
||||
"--filesystem=xdg-music",
|
||||
"--filesystem=xdg-pictures",
|
||||
"--filesystem=xdg-videos",
|
||||
"--filesystem=/media",
|
||||
"--device=all"
|
||||
],
|
||||
"build-options": {
|
||||
"cflags": "-O3 -DSQLITE_HAS_CODEC",
|
||||
"cxxflags": "-O3"
|
||||
},
|
||||
"cleanup": [
|
||||
"/include",
|
||||
"/lib/pkgconfig",
|
||||
"/share/man"
|
||||
],
|
||||
"modules": [
|
||||
{
|
||||
"name": "libv4l2",
|
||||
"config-opts":
|
||||
[
|
||||
"--disable-libdvbv5",
|
||||
"--disable-v4l-utils",
|
||||
"--disable-qv4l2"
|
||||
],
|
||||
"sources":
|
||||
[
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://linuxtv.org/downloads/v4l-utils/v4l-utils-1.14.2.tar.bz2",
|
||||
"sha256" : "e6b962c4b1253cf852c31da13fd6b5bb7cbe5aa9e182881aec55123bae680692"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ffmpeg",
|
||||
"config-opts": [
|
||||
"--disable-everything",
|
||||
"--enable-gpl",
|
||||
"--disable-debug",
|
||||
"--enable-optimizations",
|
||||
"--enable-shared",
|
||||
"--disable-programs",
|
||||
"--disable-protocols",
|
||||
"--disable-doc",
|
||||
"--disable-avfilter",
|
||||
"--disable-avresample",
|
||||
"--disable-filters",
|
||||
"--disable-iconv",
|
||||
"--disable-network",
|
||||
"--disable-postproc",
|
||||
"--enable-libv4l2",
|
||||
"--enable-indev=v4l2",
|
||||
"--enable-libxcb",
|
||||
"--enable-indev=xcbgrab",
|
||||
"--enable-demuxer=h264",
|
||||
"--enable-demuxer=mjpeg",
|
||||
"--enable-parser=h264",
|
||||
"--enable-parser=mjpeg",
|
||||
"--enable-decoder=h264",
|
||||
"--enable-decoder=mjpeg",
|
||||
"--enable-decoder=rawvideo"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "archive",
|
||||
"url": "https://ffmpeg.org/releases/ffmpeg-4.0.1.tar.bz2",
|
||||
"sha256" : "7ee591b1e7fb66f055fa514fbd5d98e092ddb3dbe37d2e50ea5c16ab51c21670"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "sqlcipher",
|
||||
"rm-configure": true,
|
||||
"config-opts": [
|
||||
"--enable-tempstore=yes",
|
||||
"--disable-tcl"
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/sqlcipher/sqlcipher",
|
||||
"tag": "v3.4.2",
|
||||
"commit": "c6f709fca81c910ba133aaf6330c28e01ccfe5f8",
|
||||
"disable-fsckobjects" : true
|
||||
},
|
||||
{
|
||||
"type": "script",
|
||||
"dest-filename": "autogen.sh",
|
||||
"commands": [
|
||||
"AUTOMAKE=\"automake --foreign\" autoreconf -vfi"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libsodium",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/jedisct1/libsodium",
|
||||
"tag": "1.0.16",
|
||||
"commit": "675149b9b8b66ff44152553fb3ebf9858128363d"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "libqrencode",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/fukuchi/libqrencode",
|
||||
"tag": "v4.0.2",
|
||||
"commit": "59ee597f913fcfda7a010a6e106fbee2595f68e4"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "c-toxcore",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/toktok/c-toxcore",
|
||||
"tag": "v0.2.3",
|
||||
"commit": "ae7899cab8104fa3c3078a3e61ddfa58a826e39a"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "qTox",
|
||||
"buildsystem": "cmake-ninja",
|
||||
"sources": [
|
||||
{
|
||||
"type": "dir",
|
||||
"path": "/build/qtox/"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.15.0</string>
|
||||
<string>1.16.3</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>toxq</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
@ -84,7 +84,7 @@
|
|||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.15.0</string>
|
||||
<string>1.16.3</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
|
|
|
@ -32,7 +32,8 @@ then
|
|||
MAIN_DIR="${TRAVIS_BUILD_DIR}"
|
||||
QTOX_DIR="${MAIN_DIR}"
|
||||
else
|
||||
MAIN_DIR="/Users/${USER}"
|
||||
# the directory which qTox is cloned in, wherever that is
|
||||
MAIN_DIR="$(dirname $(readlink -f $0))/../.."
|
||||
QTOX_DIR="${MAIN_DIR}/qTox${SUBGIT}"
|
||||
fi
|
||||
QT_DIR="/usr/local/Cellar/qt5" # Folder name of QT install
|
||||
|
@ -70,11 +71,10 @@ build_toxcore() {
|
|||
[[ $TRAVIS != true ]] \
|
||||
&& sleep 3
|
||||
|
||||
autoreconf -if
|
||||
|
||||
mkdir _build && cd _build
|
||||
fcho "Starting cmake ..."
|
||||
#Make sure the correct version of libsodium is used
|
||||
./configure --with-libsodium-headers="${LS_DIR_VER}/include/" --with-libsodium-libs="${LS_DIR_VER}/lib/" --prefix="${LIB_INSTALL_PREFIX}"
|
||||
|
||||
cmake -DBOOTSTRAP_DAEMON=OFF -DLIBSODIUM_CFLAGS="-I${LS_DIR_VER}/include/" -DLIBSODIUM_LDFLAGS="L${LS_DIR_VER}/lib/" -DCMAKE_INSTALL_PREFIX="${LIB_INSTALL_PREFIX}" ..
|
||||
make clean &> /dev/null
|
||||
fcho "Compiling toxcore."
|
||||
make > /dev/null || exit 1
|
||||
|
@ -112,7 +112,7 @@ install() {
|
|||
if [[ $TRAVIS != true ]]
|
||||
then
|
||||
sleep 3
|
||||
brew install git wget libtool autoconf automake pkgconfig
|
||||
brew install git wget libtool cmake pkgconfig
|
||||
fi
|
||||
brew install check libvpx opus libsodium
|
||||
|
||||
|
@ -127,7 +127,7 @@ install() {
|
|||
git pull
|
||||
else
|
||||
fcho "Cloning Toxcore git ... "
|
||||
git clone --branch v0.2.2 --depth=1 https://github.com/toktok/c-toxcore "$TOXCORE_DIR"
|
||||
git clone --branch v0.2.3 --depth=1 https://github.com/toktok/c-toxcore "$TOXCORE_DIR"
|
||||
fi
|
||||
# qTox
|
||||
if [[ $TRAVIS = true ]]
|
||||
|
@ -167,7 +167,11 @@ install() {
|
|||
else
|
||||
brew install cmake
|
||||
fi
|
||||
brew install ffmpeg libexif qrencode qt5 sqlcipher openal-soft
|
||||
|
||||
# needed for kf5-sonnet
|
||||
brew tap kde-mac/kde
|
||||
|
||||
brew install ffmpeg libexif qrencode qt5 sqlcipher openal-soft kf5-sonnet
|
||||
|
||||
fcho "Cloning filter_audio ... "
|
||||
git clone --branch v0.0.1 --depth=1 https://github.com/irungentoo/filter_audio "$FILTERAUIO_DIR"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
# additional flags for apt-get, used for CI
|
||||
readonly APT_FLAGS=$1
|
||||
readonly WITHOUT_SQLCIPHER=$2
|
||||
|
||||
set -eu -o pipefail
|
||||
|
||||
apt_install() {
|
||||
local apt_packages=(
|
||||
automake
|
||||
|
@ -35,7 +35,7 @@ apt_install() {
|
|||
)
|
||||
|
||||
if [ "$WITHOUT_SQLCIPHER" != "True" ]; then
|
||||
apt_packages+=libsqlcipher-dev
|
||||
apt_packages+=("libsqlcipher-dev")
|
||||
fi
|
||||
|
||||
sudo apt-get install $APT_FLAGS "${apt_packages[@]}"
|
||||
|
|
|
@ -318,16 +318,23 @@ void OpenAL2::doOutput()
|
|||
}
|
||||
|
||||
ALdouble latency[2] = {0};
|
||||
alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency);
|
||||
if (echoCancelSupported) {
|
||||
alGetSourcedvSOFT(alProxySource, AL_SEC_OFFSET_LATENCY_SOFT, latency);
|
||||
}
|
||||
|
||||
checkAlError();
|
||||
|
||||
ALshort outBuf[AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL] = {0};
|
||||
alcMakeContextCurrent(alProxyContext);
|
||||
alcRenderSamplesSOFT(alProxyDev, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL);
|
||||
checkAlcError(alProxyDev);
|
||||
if (echoCancelSupported) {
|
||||
alcMakeContextCurrent(alProxyContext);
|
||||
alcRenderSamplesSOFT(alProxyDev, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL);
|
||||
checkAlcError(alProxyDev);
|
||||
|
||||
alcMakeContextCurrent(alOutContext);
|
||||
}
|
||||
|
||||
alcMakeContextCurrent(alOutContext);
|
||||
alBufferData(bufids[0], AL_FORMAT_MONO16, outBuf, AUDIO_FRAME_SAMPLE_COUNT_PER_CHANNEL * 2, AUDIO_SAMPLE_RATE);
|
||||
|
||||
alSourceQueueBuffers(alProxySource, 1, bufids);
|
||||
|
||||
// initialize echo canceler if supported
|
||||
|
|
|
@ -197,8 +197,14 @@ void ChatLog::mousePressEvent(QMouseEvent* ev)
|
|||
clearSelection();
|
||||
}
|
||||
|
||||
// Counts only single clicks and first click of doule click
|
||||
clickCount++;
|
||||
if (lastClickButton == ev->button()) {
|
||||
// Counts only single clicks and first click of doule click
|
||||
clickCount++;
|
||||
}
|
||||
else {
|
||||
clickCount = 1; // restarting counter
|
||||
lastClickButton = ev->button();
|
||||
}
|
||||
lastClickPos = ev->pos();
|
||||
|
||||
// Triggers on odd click counts
|
||||
|
@ -477,8 +483,14 @@ void ChatLog::mouseDoubleClickEvent(QMouseEvent* ev)
|
|||
emit selectionChanged();
|
||||
}
|
||||
|
||||
// Counts the second click of double click
|
||||
clickCount++;
|
||||
if (lastClickButton == ev->button()) {
|
||||
// Counts the second click of double click
|
||||
clickCount++;
|
||||
}
|
||||
else {
|
||||
clickCount = 1; // restarting counter
|
||||
lastClickButton = ev->button();
|
||||
}
|
||||
lastClickPos = ev->pos();
|
||||
|
||||
// Triggers on even click counts
|
||||
|
|
|
@ -155,6 +155,7 @@ private:
|
|||
AutoScrollDirection selectionScrollDir = NoDirection;
|
||||
int clickCount = 0;
|
||||
QPoint lastClickPos;
|
||||
Qt::MouseButton lastClickButton;
|
||||
|
||||
// worker vars
|
||||
int workerLastIndex = 0;
|
||||
|
|
|
@ -124,7 +124,7 @@ ChatMessage::Ptr ChatMessage::createChatInfoMessage(const QString& rawMessage,
|
|||
|
||||
msg->addColumn(new Image(QSize(18, 18), img),
|
||||
ColumnFormat(NAME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
||||
msg->addColumn(new Text("<b>" + text + "</b>", baseFont, false, ""),
|
||||
msg->addColumn(new Text("<b>" + text + "</b>", baseFont, false, text),
|
||||
ColumnFormat(1.0, ColumnFormat::VariableSize, ColumnFormat::Left));
|
||||
msg->addColumn(new Timestamp(date, Settings::getInstance().getTimestampFormat(), baseFont),
|
||||
ColumnFormat(TIME_COL_WIDTH, ColumnFormat::FixedSize, ColumnFormat::Right));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
141
src/core/core.h
141
src/core/core.h
|
@ -24,18 +24,21 @@
|
|||
#include "toxfile.h"
|
||||
#include "toxid.h"
|
||||
|
||||
#include "src/core/dhtserver.h"
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
class CoreAV;
|
||||
class ICoreSettings;
|
||||
class GroupInvite;
|
||||
class Profile;
|
||||
class QTimer;
|
||||
|
||||
enum class Status
|
||||
{
|
||||
|
@ -45,11 +48,24 @@ enum class Status
|
|||
Offline
|
||||
};
|
||||
|
||||
class Core;
|
||||
|
||||
using ToxCorePtr = std::unique_ptr<Core>;
|
||||
|
||||
class Core : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Core(QThread* coreThread, Profile& profile, const ICoreSettings* const settings);
|
||||
enum class ToxCoreErrors
|
||||
{
|
||||
BAD_PROXY,
|
||||
INVALID_SAVE,
|
||||
FAILED_TO_START,
|
||||
ERROR_ALLOC
|
||||
};
|
||||
|
||||
static ToxCorePtr makeToxCore(const QByteArray& savedata, const ICoreSettings* const settings,
|
||||
ToxCoreErrors* err = nullptr);
|
||||
static Core* getInstance();
|
||||
const CoreAV* getAv() const;
|
||||
CoreAV* getAv();
|
||||
|
@ -85,10 +101,7 @@ public:
|
|||
void sendFile(uint32_t friendId, QString filename, QString filePath, long long filesize);
|
||||
|
||||
public slots:
|
||||
void start(const QByteArray& savedata);
|
||||
void reset();
|
||||
void process();
|
||||
void bootstrapDht();
|
||||
void start();
|
||||
|
||||
QByteArray getToxSaveData();
|
||||
|
||||
|
@ -126,51 +139,23 @@ signals:
|
|||
void disconnected();
|
||||
|
||||
void friendRequestReceived(const ToxPk& friendPk, const QString& message);
|
||||
void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction);
|
||||
void friendAvatarChanged(const ToxPk& friendPk, const QPixmap& pic);
|
||||
void friendAvatarData(const ToxPk& friendPk, const QByteArray& data);
|
||||
void friendAvatarRemoved(const ToxPk& friendPk);
|
||||
|
||||
void friendAdded(uint32_t friendId, const ToxPk& friendPk);
|
||||
void requestSent(const ToxPk& friendPk, const QString& message);
|
||||
|
||||
void friendStatusChanged(uint32_t friendId, Status status);
|
||||
void friendStatusMessageChanged(uint32_t friendId, const QString& message);
|
||||
void friendUsernameChanged(uint32_t friendId, const QString& username);
|
||||
void friendTypingChanged(uint32_t friendId, bool isTyping);
|
||||
void friendAvatarChanged(uint32_t friendId, const QPixmap& pic);
|
||||
void friendAvatarRemoved(uint32_t friendId);
|
||||
|
||||
void friendRemoved(uint32_t friendId);
|
||||
|
||||
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
|
||||
|
||||
void emptyGroupCreated(int groupnumber);
|
||||
void groupInviteReceived(const GroupInvite& inviteInfo);
|
||||
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
|
||||
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
|
||||
void groupPeerlistChanged(int groupnumber);
|
||||
void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName);
|
||||
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
|
||||
void groupPeerAudioPlaying(int groupnumber, int peernumber);
|
||||
void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString());
|
||||
|
||||
void usernameSet(const QString& username);
|
||||
void statusMessageSet(const QString& message);
|
||||
void statusSet(Status status);
|
||||
void idSet(const ToxId& id);
|
||||
|
||||
void messageSentResult(uint32_t friendId, const QString& message, int messageId);
|
||||
void groupSentFailed(int groupId);
|
||||
void actionSentResult(uint32_t friendId, const QString& action, int success);
|
||||
|
||||
void receiptRecieved(int friedId, int receipt);
|
||||
|
||||
void failedToAddFriend(const ToxPk& friendPk, const QString& errorInfo = QString());
|
||||
void failedToRemoveFriend(uint32_t friendId);
|
||||
void failedToSetUsername(const QString& username);
|
||||
void failedToSetStatusMessage(const QString& message);
|
||||
void failedToSetStatus(Status status);
|
||||
void failedToSetTyping(bool typing);
|
||||
|
||||
void failedToStart();
|
||||
void badProxy();
|
||||
void avReady();
|
||||
|
||||
void fileSendStarted(ToxFile file);
|
||||
|
@ -184,11 +169,50 @@ signals:
|
|||
void fileTransferInfo(ToxFile file);
|
||||
void fileTransferRemotePausedUnpaused(ToxFile file, bool paused);
|
||||
void fileTransferBrokenUnbroken(ToxFile file, bool broken);
|
||||
void fileNameChanged();
|
||||
void fileNameChanged(const ToxPk& friendPk);
|
||||
|
||||
void saveRequest();
|
||||
|
||||
/**
|
||||
* @deprecated prefer signals using ToxPk
|
||||
*/
|
||||
|
||||
void fileAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash);
|
||||
|
||||
void friendMessageReceived(uint32_t friendId, const QString& message, bool isAction);
|
||||
void friendAdded(uint32_t friendId, const ToxPk& friendPk);
|
||||
|
||||
void friendStatusChanged(uint32_t friendId, Status status);
|
||||
void friendStatusMessageChanged(uint32_t friendId, const QString& message);
|
||||
void friendUsernameChanged(uint32_t friendId, const QString& username);
|
||||
void friendTypingChanged(uint32_t friendId, bool isTyping);
|
||||
|
||||
void friendAvatarChangedDeprecated(uint32_t friendId, const QPixmap& pic);
|
||||
void friendRemoved(uint32_t friendId);
|
||||
void friendLastSeenChanged(uint32_t friendId, const QDateTime& dateTime);
|
||||
|
||||
void emptyGroupCreated(int groupnumber);
|
||||
void groupInviteReceived(const GroupInvite& inviteInfo);
|
||||
void groupMessageReceived(int groupnumber, int peernumber, const QString& message, bool isAction);
|
||||
void groupNamelistChanged(int groupnumber, int peernumber, uint8_t change);
|
||||
void groupPeerlistChanged(int groupnumber);
|
||||
void groupPeerNameChanged(int groupnumber, int peernumber, const QString& newName);
|
||||
void groupTitleChanged(int groupnumber, const QString& author, const QString& title);
|
||||
void groupPeerAudioPlaying(int groupnumber, int peernumber);
|
||||
|
||||
void messageSentResult(uint32_t friendId, const QString& message, int messageId);
|
||||
void groupSentFailed(int groupId);
|
||||
void actionSentResult(uint32_t friendId, const QString& action, int success);
|
||||
|
||||
void receiptRecieved(int friedId, int receipt);
|
||||
|
||||
void failedToRemoveFriend(uint32_t friendId);
|
||||
|
||||
void fileSendFailed(uint32_t friendId, const QString& fname);
|
||||
|
||||
private:
|
||||
Core(QThread* coreThread);
|
||||
|
||||
static void onFriendRequest(Tox* tox, const uint8_t* cUserId, const uint8_t* cMessage,
|
||||
size_t cMessageSize, void* core);
|
||||
static void onFriendMessage(Tox* tox, uint32_t friendId, TOX_MESSAGE_TYPE type,
|
||||
|
@ -208,8 +232,8 @@ private:
|
|||
const uint8_t* cMessage, size_t length, void* vCore);
|
||||
#if TOX_VERSION_IS_API_COMPATIBLE(0, 2, 0)
|
||||
static void onGroupPeerListChange(Tox*, uint32_t groupId, void* core);
|
||||
static void onGroupPeerNameChange(Tox*, uint32_t groupId, uint32_t peerId,
|
||||
const uint8_t* name, size_t length, void* core);
|
||||
static void onGroupPeerNameChange(Tox*, uint32_t groupId, uint32_t peerId, const uint8_t* name,
|
||||
size_t length, void* core);
|
||||
#else
|
||||
static void onGroupNamelistChange(Tox* tox, uint32_t groupId, uint32_t peerId,
|
||||
TOX_CONFERENCE_STATE_CHANGE change, void* core);
|
||||
|
@ -224,28 +248,41 @@ private:
|
|||
bool checkConnection();
|
||||
|
||||
void checkEncryptedHistory();
|
||||
void makeTox(QByteArray savedata);
|
||||
void makeTox(QByteArray savedata, ICoreSettings* s);
|
||||
void makeAv();
|
||||
void loadFriends();
|
||||
void bootstrapDht();
|
||||
|
||||
void checkLastOnline(uint32_t friendId);
|
||||
|
||||
void deadifyTox();
|
||||
QString getFriendRequestErrorMessage(const ToxId& friendId, const QString& message) const;
|
||||
static void registerCallbacks(Tox* tox);
|
||||
|
||||
private slots:
|
||||
void killTimers(bool onlyStop);
|
||||
void killTimers();
|
||||
void process();
|
||||
void onStarted();
|
||||
|
||||
private:
|
||||
Tox* tox;
|
||||
CoreAV* av;
|
||||
QTimer* toxTimer;
|
||||
Profile& profile;
|
||||
QMutex messageSendMutex;
|
||||
bool ready;
|
||||
const ICoreSettings* const s;
|
||||
struct ToxDeleter
|
||||
{
|
||||
void operator()(Tox* tox)
|
||||
{
|
||||
tox_kill(tox);
|
||||
}
|
||||
};
|
||||
|
||||
static QThread* coreThread;
|
||||
using ToxPtr = std::unique_ptr<Tox, ToxDeleter>;
|
||||
ToxPtr tox;
|
||||
|
||||
std::unique_ptr<CoreAV> av;
|
||||
QTimer toxTimer;
|
||||
// recursive, since we might call our own functions
|
||||
// pointer so we can circumvent const functions
|
||||
std::unique_ptr<QMutex> coreLoopLock = nullptr;
|
||||
|
||||
std::unique_ptr<QThread> coreThread = nullptr;
|
||||
QList<DhtServer> bootstrapNodes{};
|
||||
|
||||
friend class Audio; ///< Audio can access our calls directly to reduce latency
|
||||
friend class CoreFile; ///< CoreFile can access tox* and emit our signals
|
||||
|
|
|
@ -487,7 +487,7 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i
|
|||
const Settings& s = Settings::getInstance();
|
||||
// don't play the audio if it comes from a muted peer
|
||||
if (s.getBlackList().contains(peerPk.toString())) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
CoreAV* cav = c->getAv();
|
||||
|
@ -506,12 +506,11 @@ void CoreAV::groupCallCallback(void* tox, uint32_t group, uint32_t peer, const i
|
|||
}
|
||||
|
||||
Audio& audio = Audio::getInstance();
|
||||
if (!call.getPeers()[peer]) {
|
||||
// FIXME: 0 is a valid sourceId, we shouldn't necessarily re-subscribe just because we have 0
|
||||
audio.subscribeOutput(call.getPeers()[peer]);
|
||||
if(!call.havePeer(peer)) {
|
||||
call.addPeer(peer);
|
||||
}
|
||||
|
||||
audio.playAudioBuffer(call.getPeers()[peer], data, samples, channels, sample_rate);
|
||||
audio.playAudioBuffer(call.getAlSource(peer), data, samples, channels, sample_rate);
|
||||
}
|
||||
#else
|
||||
void CoreAV::groupCallCallback(void* tox, int group, int peer, const int16_t* data,
|
||||
|
@ -536,12 +535,11 @@ void CoreAV::groupCallCallback(void* tox, int group, int peer, const int16_t* da
|
|||
}
|
||||
|
||||
Audio& audio = Audio::getInstance();
|
||||
if (!call.getPeers()[peer]) {
|
||||
// FIXME: 0 is a valid sourceId, we shouldn't necessarily re-subscribe just because we have 0
|
||||
audio.subscribeOutput(call.getPeers()[peer]);
|
||||
if(!call.havePeer(peer)) {
|
||||
call.addPeer(peer);
|
||||
}
|
||||
|
||||
audio.playAudioBuffer(call.getPeers()[peer], data, samples, channels, sample_rate);
|
||||
audio.playAudioBuffer(call.getAlSource(peer), data, samples, channels, sample_rate);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -556,9 +554,7 @@ void CoreAV::invalidateGroupCallPeerSource(int group, int peer)
|
|||
if (it == groupCalls.end()) {
|
||||
return;
|
||||
}
|
||||
Audio& audio = Audio::getInstance();
|
||||
audio.unsubscribeOutput(it->second.getPeers()[peer]);
|
||||
it->second.getPeers()[peer] = 0;
|
||||
it->second.removePeer(peer);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -700,7 +696,7 @@ bool CoreAV::isGroupCallOutputMuted(const Group* g) const
|
|||
*/
|
||||
bool CoreAV::isGroupAvEnabled(int groupId) const
|
||||
{
|
||||
Tox* tox = Core::getInstance()->tox;
|
||||
Tox* tox = Core::getInstance()->tox.get();
|
||||
TOX_ERR_CONFERENCE_GET_TYPE error;
|
||||
TOX_CONFERENCE_TYPE type = tox_conference_get_type(tox, groupId, &error);
|
||||
switch (error) {
|
||||
|
@ -752,7 +748,7 @@ bool CoreAV::isCallOutputMuted(const Friend* f) const
|
|||
void CoreAV::invalidateCallSources()
|
||||
{
|
||||
for (auto& kv : groupCalls) {
|
||||
kv.second.getPeers().clear();
|
||||
kv.second.clearPeers();
|
||||
}
|
||||
|
||||
for (auto& kv : calls) {
|
||||
|
@ -801,7 +797,8 @@ void CoreAV::callCallback(ToxAV* toxav, uint32_t friendNum, bool audio, bool vid
|
|||
return;
|
||||
}
|
||||
|
||||
auto it = self->calls.insert(std::pair<uint32_t, ToxFriendCall>(friendNum, ToxFriendCall{friendNum, video, *self}));
|
||||
auto it = self->calls.insert(
|
||||
std::pair<uint32_t, ToxFriendCall>(friendNum, ToxFriendCall{friendNum, video, *self}));
|
||||
if (it.second == false) {
|
||||
/// Hanging up from a callback is supposed to be UB,
|
||||
/// but since currently the toxav callbacks are fired from the toxcore thread,
|
||||
|
@ -923,8 +920,7 @@ void CoreAV::audioBitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t rat
|
|||
Q_ARG(uint32_t, rate), Q_ARG(void*, vSelf));
|
||||
}
|
||||
|
||||
qDebug() << "Recommended audio bitrate with" << friendNum << " is now " << rate
|
||||
<< ", ignoring it";
|
||||
qDebug() << "Recommended audio bitrate with" << friendNum << " is now " << rate << ", ignoring it";
|
||||
}
|
||||
|
||||
void CoreAV::videoBitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t rate, void* vSelf)
|
||||
|
@ -938,8 +934,7 @@ void CoreAV::videoBitrateCallback(ToxAV* toxav, uint32_t friendNum, uint32_t rat
|
|||
Q_ARG(uint32_t, rate), Q_ARG(void*, vSelf));
|
||||
}
|
||||
|
||||
qDebug() << "Recommended video bitrate with" << friendNum << " is now " << rate
|
||||
<< ", ignoring it";
|
||||
qDebug() << "Recommended video bitrate with" << friendNum << " is now " << rate << ", ignoring it";
|
||||
}
|
||||
|
||||
void CoreAV::audioFrameCallback(ToxAV*, uint32_t friendNum, const int16_t* pcm, size_t sampleCount,
|
||||
|
|
|
@ -78,8 +78,9 @@ public:
|
|||
void toggleMuteCallInput(const Friend* f);
|
||||
void toggleMuteCallOutput(const Friend* f);
|
||||
#if TOX_VERSION_IS_API_COMPATIBLE(0, 2, 0)
|
||||
static void groupCallCallback(void* tox, uint32_t group, uint32_t peer, const int16_t* data, unsigned samples,
|
||||
uint8_t channels, uint32_t sample_rate, void* core);
|
||||
static void groupCallCallback(void* tox, uint32_t group, uint32_t peer, const int16_t* data,
|
||||
unsigned samples, uint8_t channels, uint32_t sample_rate,
|
||||
void* core);
|
||||
#else
|
||||
static void groupCallCallback(void* tox, int group, int peer, const int16_t* data, unsigned samples,
|
||||
uint8_t channels, unsigned sample_rate, void* core);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#include "core.h"
|
||||
#include "corefile.h"
|
||||
#include "core.h"
|
||||
#include "toxfile.h"
|
||||
#include "toxstring.h"
|
||||
#include "src/persistence/profile.h"
|
||||
|
@ -27,8 +27,8 @@
|
|||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QThread>
|
||||
#include <QRegularExpression>
|
||||
#include <QThread>
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
|
|||
QMutexLocker mlocker(&fileSendMutex);
|
||||
|
||||
if (data.isEmpty()) {
|
||||
tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, nullptr);
|
||||
tox_file_send(core->tox.get(), friendId, TOX_FILE_KIND_AVATAR, 0, nullptr, nullptr, 0, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
|
|||
uint64_t filesize = data.size();
|
||||
|
||||
TOX_ERR_FILE_SEND error;
|
||||
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_AVATAR, filesize,
|
||||
uint32_t fileNum = tox_file_send(core->tox.get(), friendId, TOX_FILE_KIND_AVATAR, filesize,
|
||||
avatarHash, avatarHash, TOX_HASH_LENGTH, &error);
|
||||
|
||||
switch (error) {
|
||||
|
@ -112,7 +112,8 @@ void CoreFile::sendAvatarFile(Core* core, uint32_t friendId, const QByteArray& d
|
|||
file.fileKind = TOX_FILE_KIND_AVATAR;
|
||||
file.avatarData = data;
|
||||
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
|
||||
tox_file_get_file_id(core->tox, friendId, fileNum, (uint8_t*)file.resumeFileId.data(), nullptr);
|
||||
tox_file_get_file_id(core->tox.get(), friendId, fileNum, (uint8_t*)file.resumeFileId.data(),
|
||||
nullptr);
|
||||
addFile(friendId, fileNum, file);
|
||||
}
|
||||
|
||||
|
@ -122,8 +123,8 @@ void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString
|
|||
QMutexLocker mlocker(&fileSendMutex);
|
||||
|
||||
QByteArray fileName = filename.toUtf8();
|
||||
uint32_t fileNum = tox_file_send(core->tox, friendId, TOX_FILE_KIND_DATA, filesize, nullptr,
|
||||
(uint8_t*)fileName.data(), fileName.size(), nullptr);
|
||||
uint32_t fileNum = tox_file_send(core->tox.get(), friendId, TOX_FILE_KIND_DATA, filesize,
|
||||
nullptr, (uint8_t*)fileName.data(), fileName.size(), nullptr);
|
||||
if (fileNum == std::numeric_limits<uint32_t>::max()) {
|
||||
qWarning() << "sendFile: Can't create the Tox file sender";
|
||||
emit core->fileSendFailed(friendId, filename);
|
||||
|
@ -134,7 +135,8 @@ void CoreFile::sendFile(Core* core, uint32_t friendId, QString filename, QString
|
|||
ToxFile file{fileNum, friendId, fileName, filePath, ToxFile::SENDING};
|
||||
file.filesize = filesize;
|
||||
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
|
||||
tox_file_get_file_id(core->tox, friendId, fileNum, (uint8_t*)file.resumeFileId.data(), nullptr);
|
||||
tox_file_get_file_id(core->tox.get(), friendId, fileNum, (uint8_t*)file.resumeFileId.data(),
|
||||
nullptr);
|
||||
if (!file.open(false)) {
|
||||
qWarning() << QString("sendFile: Can't open file, error: %1").arg(file.file->errorString());
|
||||
}
|
||||
|
@ -154,11 +156,13 @@ void CoreFile::pauseResumeFileSend(Core* core, uint32_t friendId, uint32_t fileI
|
|||
if (file->status == ToxFile::TRANSMITTING) {
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit core->fileTransferPaused(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE,
|
||||
nullptr);
|
||||
} else if (file->status == ToxFile::PAUSED) {
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME,
|
||||
nullptr);
|
||||
} else {
|
||||
qWarning() << "pauseResumeFileSend: File is stopped";
|
||||
}
|
||||
|
@ -174,11 +178,13 @@ void CoreFile::pauseResumeFileRecv(Core* core, uint32_t friendId, uint32_t fileI
|
|||
if (file->status == ToxFile::TRANSMITTING) {
|
||||
file->status = ToxFile::PAUSED;
|
||||
emit core->fileTransferPaused(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_PAUSE,
|
||||
nullptr);
|
||||
} else if (file->status == ToxFile::PAUSED) {
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME,
|
||||
nullptr);
|
||||
} else {
|
||||
qWarning() << "pauseResumeFileRecv: File is stopped or broken";
|
||||
}
|
||||
|
@ -194,7 +200,7 @@ void CoreFile::cancelFileSend(Core* core, uint32_t friendId, uint32_t fileId)
|
|||
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
|
@ -207,7 +213,7 @@ void CoreFile::cancelFileRecv(Core* core, uint32_t friendId, uint32_t fileId)
|
|||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
|
@ -220,7 +226,7 @@ void CoreFile::rejectFileRecvRequest(Core* core, uint32_t friendId, uint32_t fil
|
|||
}
|
||||
file->status = ToxFile::STOPPED;
|
||||
emit core->fileTransferCancelled(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
removeFile(friendId, fileId);
|
||||
}
|
||||
|
||||
|
@ -238,7 +244,7 @@ void CoreFile::acceptFileRecvRequest(Core* core, uint32_t friendId, uint32_t fil
|
|||
}
|
||||
file->status = ToxFile::TRANSMITTING;
|
||||
emit core->fileTransferAccepted(*file);
|
||||
tox_file_control(core->tox, file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
tox_file_control(core->tox.get(), file->friendId, file->fileNum, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
|
||||
ToxFile* CoreFile::findFile(uint32_t friendId, uint32_t fileId)
|
||||
|
@ -277,7 +283,7 @@ void CoreFile::removeFile(uint32_t friendId, uint32_t fileId)
|
|||
|
||||
QString CoreFile::getCleanFileName(QString filename)
|
||||
{
|
||||
QRegularExpression regex("[<>:\"/\\|?*]");
|
||||
QRegularExpression regex{QStringLiteral(R"([<>:"/\\|?])")};
|
||||
filename.replace(regex, "_");
|
||||
|
||||
return filename;
|
||||
|
@ -289,60 +295,77 @@ void CoreFile::onFileReceiveCallback(Tox*, uint32_t friendId, uint32_t fileId, u
|
|||
{
|
||||
Core* core = static_cast<Core*>(vCore);
|
||||
auto filename = ToxString(fname, fnameLen);
|
||||
const auto cleanFileName = CoreFile::getCleanFileName(filename.getQString());
|
||||
const ToxPk friendPk = core->getFriendPublicKey(friendId);
|
||||
|
||||
if (kind == TOX_FILE_KIND_AVATAR) {
|
||||
const ToxPk friendPk = core->getFriendPublicKey(friendId);
|
||||
if (!filesize) {
|
||||
qDebug() << QString("Received empty avatar request %1:%2").arg(friendId).arg(fileId);
|
||||
// Avatars of size 0 means explicitely no avatar
|
||||
emit core->friendAvatarRemoved(friendId);
|
||||
core->profile.removeAvatar(friendPk);
|
||||
emit core->friendAvatarRemoved(core->getFriendPublicKey(friendId));
|
||||
return;
|
||||
} else {
|
||||
static_assert(TOX_HASH_LENGTH <= TOX_FILE_ID_LENGTH,
|
||||
"TOX_HASH_LENGTH > TOX_FILE_ID_LENGTH!");
|
||||
uint8_t avatarHash[TOX_FILE_ID_LENGTH];
|
||||
tox_file_get_file_id(core->tox, friendId, fileId, avatarHash, nullptr);
|
||||
if (core->profile.getAvatarHash(friendPk)
|
||||
== QByteArray((char*)avatarHash, TOX_HASH_LENGTH)) {
|
||||
// If it's an avatar but we already have it cached, cancel
|
||||
qDebug() << QString(
|
||||
"Received avatar request %1:%2, reject, since we have it in cache.")
|
||||
.arg(friendId)
|
||||
.arg(fileId);
|
||||
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
return;
|
||||
} else {
|
||||
// It's an avatar and we don't have it, autoaccept the transfer
|
||||
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it "
|
||||
"in cache.")
|
||||
.arg(friendId)
|
||||
.arg(fileId);
|
||||
tox_file_control(core->tox, friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
}
|
||||
tox_file_get_file_id(core->tox.get(), friendId, fileId, avatarHash, nullptr);
|
||||
QByteArray avatarBytes{static_cast<const char*>(static_cast<const void*>(avatarHash)),
|
||||
TOX_HASH_LENGTH};
|
||||
emit core->fileAvatarOfferReceived(friendId, fileId, avatarBytes);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const auto cleanFileName = CoreFile::getCleanFileName(filename.getQString());
|
||||
if (cleanFileName != filename.getQString()) {
|
||||
qDebug() << QStringLiteral("Cleaned filename");
|
||||
filename = ToxString(cleanFileName);
|
||||
emit core->fileNameChanged(friendPk);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("filename already clean");
|
||||
}
|
||||
qDebug() << QString("Received file request %1:%2 kind %3").arg(friendId).arg(fileId).arg(kind);
|
||||
}
|
||||
|
||||
if (cleanFileName != filename.getQString()) {
|
||||
qDebug() << QStringLiteral("Cleaned filename from %1 to %2").arg(filename.getQString()).arg(cleanFileName);
|
||||
filename = ToxString(cleanFileName);
|
||||
emit core->fileNameChanged();
|
||||
} else {
|
||||
qDebug() << QStringLiteral("cleanFileName: filename already clean");
|
||||
}
|
||||
|
||||
ToxFile file{fileId, friendId, filename.getBytes(), "", ToxFile::RECEIVING};
|
||||
file.filesize = filesize;
|
||||
file.fileKind = kind;
|
||||
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
|
||||
tox_file_get_file_id(core->tox, friendId, fileId, (uint8_t*)file.resumeFileId.data(), nullptr);
|
||||
tox_file_get_file_id(core->tox.get(), friendId, fileId, (uint8_t*)file.resumeFileId.data(),
|
||||
nullptr);
|
||||
addFile(friendId, fileId, file);
|
||||
if (kind != TOX_FILE_KIND_AVATAR)
|
||||
emit core->fileReceiveRequested(file);
|
||||
}
|
||||
|
||||
// TODO(sudden6): This whole method is a mess but needed to get stuff working for now
|
||||
void CoreFile::handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept)
|
||||
{
|
||||
// TODO(sudden6): evil evil evil
|
||||
auto core = Core::getInstance();
|
||||
if (!accept) {
|
||||
// If it's an avatar but we already have it cached, cancel
|
||||
qDebug() << QString("Received avatar request %1:%2, reject, since we have it in cache.")
|
||||
.arg(friendId)
|
||||
.arg(fileId);
|
||||
tox_file_control(core->tox.get(), friendId, fileId, TOX_FILE_CONTROL_CANCEL, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
// It's an avatar and we don't have it, autoaccept the transfer
|
||||
qDebug() << QString("Received avatar request %1:%2, accept, since we don't have it "
|
||||
"in cache.")
|
||||
.arg(friendId)
|
||||
.arg(fileId);
|
||||
tox_file_control(core->tox.get(), friendId, fileId, TOX_FILE_CONTROL_RESUME, nullptr);
|
||||
|
||||
ToxFile file{fileId, friendId, "<avatar>", "", ToxFile::RECEIVING};
|
||||
file.filesize = 0;
|
||||
file.fileKind = TOX_FILE_KIND_AVATAR;
|
||||
file.resumeFileId.resize(TOX_FILE_ID_LENGTH);
|
||||
tox_file_get_file_id(core->tox.get(), friendId, fileId, (uint8_t*)file.resumeFileId.data(),
|
||||
nullptr);
|
||||
addFile(friendId, fileId, file);
|
||||
}
|
||||
|
||||
void CoreFile::onFileControlCallback(Tox*, uint32_t friendId, uint32_t fileId,
|
||||
TOX_FILE_CONTROL control, void* core)
|
||||
{
|
||||
|
@ -447,9 +470,10 @@ void CoreFile::onFileRecvChunkCallback(Tox* tox, uint32_t friendId, uint32_t fil
|
|||
pic.loadFromData(file->avatarData);
|
||||
if (!pic.isNull()) {
|
||||
qDebug() << "Got" << file->avatarData.size() << "bytes of avatar data from" << friendId;
|
||||
core->profile.saveAvatar(file->avatarData,
|
||||
core->getFriendPublicKey(friendId));
|
||||
emit core->friendAvatarChanged(friendId, pic);
|
||||
emit core->friendAvatarData(core->getFriendPublicKey(friendId), file->avatarData);
|
||||
emit core->friendAvatarChanged(core->getFriendPublicKey(friendId), pic);
|
||||
// TODO(sudden6): signal below is deprecated
|
||||
emit core->friendAvatarChangedDeprecated(friendId, pic);
|
||||
}
|
||||
} else {
|
||||
emit core->fileTransferFinished(*file);
|
||||
|
|
|
@ -39,6 +39,10 @@ class CoreFile
|
|||
{
|
||||
friend class Core;
|
||||
|
||||
|
||||
public:
|
||||
static void handleAvatarOffer(uint32_t friendId, uint32_t fileId, bool accept);
|
||||
|
||||
private:
|
||||
CoreFile() = delete;
|
||||
|
||||
|
|
|
@ -28,40 +28,10 @@
|
|||
* @brief Keeps sources for users in group calls.
|
||||
*/
|
||||
|
||||
ToxCall::ToxCall(uint32_t CallId, bool VideoEnabled, CoreAV& av)
|
||||
ToxCall::ToxCall(bool VideoEnabled, CoreAV& av)
|
||||
: av{&av}
|
||||
, videoEnabled{VideoEnabled}
|
||||
{
|
||||
Audio& audio = Audio::getInstance();
|
||||
audio.subscribeInput();
|
||||
audio.subscribeOutput(alSource);
|
||||
|
||||
audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable,
|
||||
[&av, CallId](const int16_t* pcm, size_t samples, uint8_t chans,
|
||||
uint32_t rate) {
|
||||
av.sendCallAudio(CallId, pcm, samples, chans, rate);
|
||||
});
|
||||
|
||||
if (!audioInConn) {
|
||||
qDebug() << "Audio connection not working";
|
||||
}
|
||||
|
||||
if (videoEnabled) {
|
||||
videoSource = new CoreVideoSource();
|
||||
CameraSource& source = CameraSource::getInstance();
|
||||
|
||||
if (source.isNone()) {
|
||||
source.setupDefault();
|
||||
}
|
||||
source.subscribe();
|
||||
videoInConn = QObject::connect(&source, &VideoSource::frameAvailable,
|
||||
[&av, CallId](std::shared_ptr<VideoFrame> frame) {
|
||||
av.sendCallVideo(CallId, frame);
|
||||
});
|
||||
if (!videoInConn) {
|
||||
qDebug() << "Video connection not working";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -73,7 +43,6 @@ ToxCall::ToxCall(ToxCall&& other) noexcept : active{other.active},
|
|||
audioInConn{other.audioInConn},
|
||||
muteMic{other.muteMic},
|
||||
muteVol{other.muteVol},
|
||||
alSource{other.alSource},
|
||||
videoSource{other.videoSource},
|
||||
videoInConn{other.videoInConn},
|
||||
videoEnabled{other.videoEnabled},
|
||||
|
@ -82,7 +51,6 @@ ToxCall::ToxCall(ToxCall&& other) noexcept : active{other.active},
|
|||
Audio& audio = Audio::getInstance();
|
||||
audio.subscribeInput();
|
||||
other.audioInConn = QMetaObject::Connection();
|
||||
other.alSource = 0;
|
||||
other.videoInConn = QMetaObject::Connection();
|
||||
other.videoEnabled = false; // we don't need to subscribe video because other won't unsubscribe
|
||||
other.videoSource = nullptr;
|
||||
|
@ -95,7 +63,6 @@ ToxCall::~ToxCall()
|
|||
|
||||
QObject::disconnect(audioInConn);
|
||||
audio.unsubscribeInput();
|
||||
audio.unsubscribeOutput(alSource);
|
||||
if (videoEnabled) {
|
||||
QObject::disconnect(videoInConn);
|
||||
CameraSource::getInstance().unsubscribe();
|
||||
|
@ -117,9 +84,6 @@ ToxCall& ToxCall::operator=(ToxCall&& other) noexcept
|
|||
muteMic = other.muteMic;
|
||||
muteVol = other.muteVol;
|
||||
|
||||
alSource = other.alSource;
|
||||
other.alSource = 0;
|
||||
|
||||
Audio::getInstance().subscribeInput();
|
||||
|
||||
videoInConn = other.videoInConn;
|
||||
|
@ -190,19 +154,73 @@ CoreVideoSource* ToxCall::getVideoSource() const
|
|||
return videoSource;
|
||||
}
|
||||
|
||||
quint32 ToxCall::getAlSource() const
|
||||
quint32 ToxFriendCall::getAlSource() const
|
||||
{
|
||||
return alSource;
|
||||
}
|
||||
|
||||
void ToxCall::setAlSource(const quint32& value)
|
||||
void ToxFriendCall::setAlSource(const quint32& value)
|
||||
{
|
||||
alSource = value;
|
||||
}
|
||||
|
||||
ToxFriendCall::ToxFriendCall(uint32_t FriendNum, bool VideoEnabled, CoreAV& av)
|
||||
: ToxCall(FriendNum, VideoEnabled, av)
|
||||
: ToxCall(VideoEnabled, av)
|
||||
{
|
||||
// register audio
|
||||
Audio& audio = Audio::getInstance();
|
||||
audio.subscribeInput();
|
||||
audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable,
|
||||
[&av, FriendNum](const int16_t* pcm, size_t samples, uint8_t chans,
|
||||
uint32_t rate) {
|
||||
av.sendCallAudio(FriendNum, pcm, samples, chans, rate);
|
||||
});
|
||||
|
||||
if (!audioInConn) {
|
||||
qDebug() << "Audio input connection not working";
|
||||
}
|
||||
|
||||
audio.subscribeOutput(alSource);
|
||||
|
||||
// register video
|
||||
if (videoEnabled) {
|
||||
videoSource = new CoreVideoSource();
|
||||
CameraSource& source = CameraSource::getInstance();
|
||||
|
||||
if (source.isNone()) {
|
||||
source.setupDefault();
|
||||
}
|
||||
source.subscribe();
|
||||
videoInConn = QObject::connect(&source, &VideoSource::frameAvailable,
|
||||
[&av, FriendNum](std::shared_ptr<VideoFrame> frame) {
|
||||
av.sendCallVideo(FriendNum, frame);
|
||||
});
|
||||
if (!videoInConn) {
|
||||
qDebug() << "Video connection not working";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ToxFriendCall::ToxFriendCall(ToxFriendCall &&other) noexcept
|
||||
: ToxCall(std::move(other))
|
||||
, alSource{other.alSource}
|
||||
{
|
||||
other.alSource = 0;
|
||||
}
|
||||
|
||||
ToxFriendCall& ToxFriendCall::operator=(ToxFriendCall &&other) noexcept
|
||||
{
|
||||
ToxCall::operator=(std::move(other));
|
||||
alSource = other.alSource;
|
||||
other.alSource = 0;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ToxFriendCall::~ToxFriendCall()
|
||||
{
|
||||
auto& audio = Audio::getInstance();
|
||||
audio.unsubscribeOutput(alSource);
|
||||
}
|
||||
|
||||
void ToxFriendCall::startTimeout(uint32_t callId)
|
||||
|
@ -239,11 +257,24 @@ void ToxFriendCall::setState(const TOXAV_FRIEND_CALL_STATE& value)
|
|||
}
|
||||
|
||||
ToxGroupCall::ToxGroupCall(int GroupNum, CoreAV& av)
|
||||
: ToxCall(static_cast<uint32_t>(GroupNum), false, av)
|
||||
: ToxCall(false, av)
|
||||
{
|
||||
// register audio
|
||||
Audio& audio = Audio::getInstance();
|
||||
audio.subscribeInput();
|
||||
audioInConn = QObject::connect(&Audio::getInstance(), &Audio::frameAvailable,
|
||||
[&av, GroupNum](const int16_t* pcm, size_t samples, uint8_t chans,
|
||||
uint32_t rate) {
|
||||
av.sendGroupCallAudio(GroupNum, pcm, samples, chans, rate);
|
||||
});
|
||||
|
||||
if (!audioInConn) {
|
||||
qDebug() << "Audio input connection not working";
|
||||
}
|
||||
}
|
||||
|
||||
ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept : ToxCall(std::move(other)), peers{other.peers}
|
||||
ToxGroupCall::ToxGroupCall(ToxGroupCall&& other) noexcept
|
||||
: ToxCall(std::move(other)), peers{other.peers}
|
||||
{
|
||||
// all peers were moved, this ensures audio output is unsubscribed only once
|
||||
other.peers.clear();
|
||||
|
@ -269,10 +300,48 @@ ToxGroupCall& ToxGroupCall::operator=(ToxGroupCall&& other) noexcept
|
|||
|
||||
void ToxGroupCall::removePeer(int peerId)
|
||||
{
|
||||
auto& audio = Audio::getInstance();
|
||||
const auto& sourceId = peers.find(peerId);
|
||||
if(sourceId == peers.constEnd()) {
|
||||
qDebug() << "Peer:" << peerId << "does not have a source, can't remove";
|
||||
return;
|
||||
}
|
||||
|
||||
audio.unsubscribeOutput(sourceId.value());
|
||||
peers.remove(peerId);
|
||||
}
|
||||
|
||||
QMap<int, quint32>& ToxGroupCall::getPeers()
|
||||
void ToxGroupCall::addPeer(int peerId)
|
||||
{
|
||||
return peers;
|
||||
auto& audio = Audio::getInstance();
|
||||
uint sourceId = 0;
|
||||
audio.subscribeOutput(sourceId);
|
||||
peers.insert(peerId, sourceId);
|
||||
}
|
||||
|
||||
bool ToxGroupCall::havePeer(int peerId)
|
||||
{
|
||||
const auto& sourceId = peers.find(peerId);
|
||||
return sourceId != peers.constEnd();
|
||||
}
|
||||
|
||||
void ToxGroupCall::clearPeers()
|
||||
{
|
||||
Audio& audio = Audio::getInstance();
|
||||
|
||||
for (quint32 v : peers) {
|
||||
audio.unsubscribeOutput(v);
|
||||
}
|
||||
|
||||
peers.clear();
|
||||
}
|
||||
|
||||
quint32 ToxGroupCall::getAlSource(int peer)
|
||||
{
|
||||
if(!havePeer(peer)) {
|
||||
qWarning() << "Getting alSource for non-existant peer";
|
||||
return 0;
|
||||
}
|
||||
|
||||
return peers[peer];
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class ToxCall
|
|||
{
|
||||
protected:
|
||||
ToxCall() = delete;
|
||||
ToxCall(uint32_t CallId, bool VideoEnabled, CoreAV& av);
|
||||
ToxCall(bool VideoEnabled, CoreAV& av);
|
||||
~ToxCall();
|
||||
|
||||
public:
|
||||
|
@ -45,9 +45,6 @@ public:
|
|||
|
||||
CoreVideoSource* getVideoSource() const;
|
||||
|
||||
quint32 getAlSource() const;
|
||||
void setAlSource(const quint32& value);
|
||||
|
||||
protected:
|
||||
bool active{false};
|
||||
CoreAV* av{nullptr};
|
||||
|
@ -55,7 +52,6 @@ protected:
|
|||
QMetaObject::Connection audioInConn;
|
||||
bool muteMic{false};
|
||||
bool muteVol{false};
|
||||
quint32 alSource{0};
|
||||
// video
|
||||
CoreVideoSource* videoSource{nullptr};
|
||||
QMetaObject::Connection videoInConn;
|
||||
|
@ -68,8 +64,9 @@ class ToxFriendCall : public ToxCall
|
|||
public:
|
||||
ToxFriendCall() = delete;
|
||||
ToxFriendCall(uint32_t friendId, bool VideoEnabled, CoreAV& av);
|
||||
ToxFriendCall(ToxFriendCall&& other) noexcept = default;
|
||||
ToxFriendCall& operator=(ToxFriendCall&& other) noexcept = default;
|
||||
ToxFriendCall(ToxFriendCall&& other) noexcept;
|
||||
ToxFriendCall& operator=(ToxFriendCall&& other) noexcept;
|
||||
~ToxFriendCall();
|
||||
|
||||
void startTimeout(uint32_t callId);
|
||||
void stopTimeout();
|
||||
|
@ -77,12 +74,16 @@ public:
|
|||
TOXAV_FRIEND_CALL_STATE getState() const;
|
||||
void setState(const TOXAV_FRIEND_CALL_STATE& value);
|
||||
|
||||
quint32 getAlSource() const;
|
||||
void setAlSource(const quint32& value);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<QTimer> timeoutTimer;
|
||||
|
||||
private:
|
||||
TOXAV_FRIEND_CALL_STATE state{TOXAV_FRIEND_CALL_STATE_NONE};
|
||||
static constexpr int CALL_TIMEOUT = 45000;
|
||||
quint32 alSource{0};
|
||||
};
|
||||
|
||||
class ToxGroupCall : public ToxCall
|
||||
|
@ -96,8 +97,11 @@ public:
|
|||
ToxGroupCall& operator=(ToxGroupCall&& other) noexcept;
|
||||
|
||||
void removePeer(int peerId);
|
||||
void addPeer(int peerId);
|
||||
bool havePeer(int peerId);
|
||||
void clearPeers();
|
||||
|
||||
QMap<int, quint32>& getPeers();
|
||||
quint32 getAlSource(int peer);
|
||||
|
||||
private:
|
||||
QMap<int, quint32> peers;
|
||||
|
|
60
src/core/toxlogger.cpp
Normal file
60
src/core/toxlogger.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "toxlogger.h"
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
#include <QStringBuilder>
|
||||
|
||||
/**
|
||||
* @brief Map TOX_LOG_LEVEL to a string
|
||||
* @param level log level
|
||||
* @return Descriptive string for the log level
|
||||
*/
|
||||
QString getToxLogLevel(TOX_LOG_LEVEL level) {
|
||||
switch (level) {
|
||||
case TOX_LOG_LEVEL_TRACE:
|
||||
return QLatin1Literal("TRACE");
|
||||
case TOX_LOG_LEVEL_DEBUG:
|
||||
return QLatin1Literal("DEBUG");
|
||||
case TOX_LOG_LEVEL_INFO:
|
||||
return QLatin1Literal("INFO ");
|
||||
case TOX_LOG_LEVEL_WARNING:
|
||||
return QLatin1Literal("WARN ");
|
||||
case TOX_LOG_LEVEL_ERROR:
|
||||
return QLatin1Literal("ERROR");
|
||||
default:
|
||||
// Invalid log level
|
||||
return QLatin1Literal("INVAL");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log message handler for toxcore log messages
|
||||
* @note See tox.h for the parameter definitions
|
||||
*/
|
||||
void ToxLogger::onLogMessage(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line,
|
||||
const char *func, const char *message, void *user_data)
|
||||
{
|
||||
// for privacy, make the path relative to the c-toxcore source directory
|
||||
const QRegularExpression pathCleaner(QLatin1Literal{"[\\s|\\S]*c-toxcore."});
|
||||
const QString cleanPath = QString{file}.remove(pathCleaner);
|
||||
|
||||
const QString logMsg = getToxLogLevel(level) % QLatin1Literal{":"} % cleanPath
|
||||
% QLatin1Literal{":"} % func % QStringLiteral(":%1: ").arg(line)
|
||||
% message;
|
||||
|
||||
switch (level) {
|
||||
case TOX_LOG_LEVEL_TRACE:
|
||||
return; // trace level generates too much noise to enable by default
|
||||
case TOX_LOG_LEVEL_DEBUG:
|
||||
case TOX_LOG_LEVEL_INFO:
|
||||
qDebug() << logMsg;
|
||||
break;
|
||||
case TOX_LOG_LEVEL_WARNING:
|
||||
case TOX_LOG_LEVEL_ERROR:
|
||||
qWarning() << logMsg;
|
||||
}
|
||||
}
|
||||
|
13
src/core/toxlogger.h
Normal file
13
src/core/toxlogger.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef TOXLOGGER_H
|
||||
#define TOXLOGGER_H
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ToxLogger {
|
||||
void onLogMessage(Tox *tox, TOX_LOG_LEVEL level, const char *file, uint32_t line,
|
||||
const char *func, const char *message, void *user_data);
|
||||
}
|
||||
|
||||
#endif // TOXLOGGER_H
|
133
src/core/toxoptions.cpp
Normal file
133
src/core/toxoptions.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include "toxoptions.h"
|
||||
|
||||
#include "src/core/icoresettings.h"
|
||||
#include "src/core/toxlogger.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
|
||||
// TODO(sudden6): replace this constant with the function from toxcore 0.2.3
|
||||
static const int MAX_PROXY_ADDRESS_LENGTH = 255;
|
||||
|
||||
/**
|
||||
* @brief The ToxOptions class wraps the Tox_Options struct and the matching
|
||||
* proxy address data. This is needed to ensure both have equal lifetime and
|
||||
* are correctly deleted.
|
||||
*/
|
||||
|
||||
ToxOptions::ToxOptions(Tox_Options* options, const QByteArray& proxyAddrData)
|
||||
: options(options)
|
||||
, proxyAddrData(proxyAddrData)
|
||||
{}
|
||||
|
||||
ToxOptions::~ToxOptions()
|
||||
{
|
||||
tox_options_free(options);
|
||||
}
|
||||
|
||||
ToxOptions::ToxOptions(ToxOptions&& from)
|
||||
{
|
||||
options = from.options;
|
||||
proxyAddrData.swap(from.proxyAddrData);
|
||||
from.options = nullptr;
|
||||
from.proxyAddrData.clear();
|
||||
}
|
||||
|
||||
const char* ToxOptions::getProxyAddrData() const
|
||||
{
|
||||
return proxyAddrData.constData();
|
||||
}
|
||||
|
||||
ToxOptions::operator Tox_Options*()
|
||||
{
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes a ToxOptions instance
|
||||
* @param savedata Previously saved Tox data
|
||||
* @return ToxOptions instance initialized to create Tox instance
|
||||
*/
|
||||
std::unique_ptr<ToxOptions> ToxOptions::makeToxOptions(const QByteArray& savedata,
|
||||
const ICoreSettings* s)
|
||||
{
|
||||
// IPv6 needed for LAN discovery, but can crash some weird routers. On by default, can be
|
||||
// disabled in options.
|
||||
const bool enableIPv6 = s->getEnableIPv6();
|
||||
bool forceTCP = s->getForceTCP();
|
||||
// LAN requiring UDP is a toxcore limitation, ideally wouldn't be related
|
||||
const bool enableLanDiscovery = s->getEnableLanDiscovery() && !forceTCP;
|
||||
ICoreSettings::ProxyType proxyType = s->getProxyType();
|
||||
quint16 proxyPort = s->getProxyPort();
|
||||
QString proxyAddr = s->getProxyAddr();
|
||||
|
||||
if (!enableLanDiscovery) {
|
||||
qWarning() << "Core starting without LAN discovery. Peers can only be found through DHT.";
|
||||
}
|
||||
if (enableIPv6) {
|
||||
qDebug() << "Core starting with IPv6 enabled";
|
||||
} else if (enableLanDiscovery) {
|
||||
qWarning() << "Core starting with IPv6 disabled. LAN discovery may not work properly.";
|
||||
}
|
||||
|
||||
Tox_Options* tox_opts = tox_options_new(nullptr);
|
||||
|
||||
if (!tox_opts) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto toxOptions = std::unique_ptr<ToxOptions>(new ToxOptions(tox_opts, proxyAddr.toUtf8()));
|
||||
// register log first, to get messages as early as possible
|
||||
tox_options_set_log_callback(*toxOptions, ToxLogger::onLogMessage);
|
||||
|
||||
// savedata
|
||||
tox_options_set_savedata_type(*toxOptions, !savedata.isNull() ? TOX_SAVEDATA_TYPE_TOX_SAVE
|
||||
: TOX_SAVEDATA_TYPE_NONE);
|
||||
tox_options_set_savedata_data(*toxOptions, reinterpret_cast<const uint8_t*>(savedata.data()),
|
||||
savedata.size());
|
||||
// No proxy by default
|
||||
tox_options_set_proxy_type(*toxOptions, TOX_PROXY_TYPE_NONE);
|
||||
tox_options_set_proxy_host(*toxOptions, nullptr);
|
||||
tox_options_set_proxy_port(*toxOptions, 0);
|
||||
|
||||
if (proxyType != ICoreSettings::ProxyType::ptNone) {
|
||||
if (proxyAddr.length() > MAX_PROXY_ADDRESS_LENGTH) {
|
||||
qWarning() << "proxy address" << proxyAddr << "is too long";
|
||||
} else if (!proxyAddr.isEmpty() && proxyPort > 0) {
|
||||
qDebug() << "using proxy" << proxyAddr << ":" << proxyPort;
|
||||
// protection against changings in TOX_PROXY_TYPE enum
|
||||
if (proxyType == ICoreSettings::ProxyType::ptSOCKS5) {
|
||||
tox_options_set_proxy_type(*toxOptions, TOX_PROXY_TYPE_SOCKS5);
|
||||
} else if (proxyType == ICoreSettings::ProxyType::ptHTTP) {
|
||||
tox_options_set_proxy_type(*toxOptions, TOX_PROXY_TYPE_HTTP);
|
||||
}
|
||||
|
||||
tox_options_set_proxy_host(*toxOptions, toxOptions->getProxyAddrData());
|
||||
tox_options_set_proxy_port(*toxOptions, proxyPort);
|
||||
|
||||
if (!forceTCP) {
|
||||
qDebug() << "Proxy and UDP enabled, this is a security risk, forcing TCP only";
|
||||
forceTCP = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// network options
|
||||
tox_options_set_udp_enabled(*toxOptions, !forceTCP);
|
||||
tox_options_set_ipv6_enabled(*toxOptions, enableIPv6);
|
||||
tox_options_set_local_discovery_enabled(*toxOptions, enableLanDiscovery);
|
||||
tox_options_set_start_port(*toxOptions, 0);
|
||||
tox_options_set_end_port(*toxOptions, 0);
|
||||
|
||||
return toxOptions;
|
||||
}
|
||||
|
||||
bool ToxOptions::getIPv6Enabled() const
|
||||
{
|
||||
return tox_options_get_ipv6_enabled(options);
|
||||
}
|
||||
|
||||
void ToxOptions::setIPv6Enabled(bool enabled)
|
||||
{
|
||||
tox_options_set_ipv6_enabled(options, enabled);
|
||||
}
|
31
src/core/toxoptions.h
Normal file
31
src/core/toxoptions.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef TOXOPTIONS_H
|
||||
#define TOXOPTIONS_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class ICoreSettings;
|
||||
struct Tox_Options;
|
||||
|
||||
class ToxOptions
|
||||
{
|
||||
public:
|
||||
~ToxOptions();
|
||||
ToxOptions(ToxOptions&& from);
|
||||
operator Tox_Options*();
|
||||
const char* getProxyAddrData() const;
|
||||
static std::unique_ptr<ToxOptions> makeToxOptions(const QByteArray& savedata,
|
||||
const ICoreSettings* s);
|
||||
bool getIPv6Enabled() const;
|
||||
void setIPv6Enabled(bool enabled);
|
||||
|
||||
private:
|
||||
ToxOptions(Tox_Options* options, const QByteArray& proxyAddrData);
|
||||
|
||||
private:
|
||||
Tox_Options* options = nullptr;
|
||||
QByteArray proxyAddrData;
|
||||
};
|
||||
|
||||
#endif // TOXOPTIONS_H
|
29
src/main.cpp
29
src/main.cpp
|
@ -140,7 +140,6 @@ void logMessageHandler(QtMsgType type, const QMessageLogContext& ctxt, const QSt
|
|||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
|
||||
|
@ -148,15 +147,16 @@ int main(int argc, char* argv[])
|
|||
|
||||
qInstallMessageHandler(logMessageHandler);
|
||||
|
||||
// initialize random number generator
|
||||
qsrand(time(nullptr));
|
||||
|
||||
std::unique_ptr<QApplication> a(new QApplication(argc, argv));
|
||||
|
||||
#if defined(Q_OS_UNIX)
|
||||
// PosixSignalNotifier is used only for terminating signals,
|
||||
// so it's connected directly to quit() without any filtering.
|
||||
QObject::connect(&PosixSignalNotifier::globalInstance(),
|
||||
&PosixSignalNotifier::activated,
|
||||
a.get(),
|
||||
&QApplication::quit);
|
||||
QObject::connect(&PosixSignalNotifier::globalInstance(), &PosixSignalNotifier::activated,
|
||||
a.get(), &QApplication::quit);
|
||||
PosixSignalNotifier::watchCommonTerminatingSignals();
|
||||
#endif
|
||||
|
||||
|
@ -193,10 +193,14 @@ int main(int argc, char* argv[])
|
|||
parser.addVersionOption();
|
||||
parser.addPositionalArgument("uri", QObject::tr("Tox URI to parse"));
|
||||
parser.addOption(
|
||||
QCommandLineOption(QStringList() << "p" << "profile", QObject::tr("Starts new instance and loads specified profile."),
|
||||
QCommandLineOption(QStringList() << "p"
|
||||
<< "profile",
|
||||
QObject::tr("Starts new instance and loads specified profile."),
|
||||
QObject::tr("profile")));
|
||||
parser.addOption(
|
||||
QCommandLineOption(QStringList() << "l" << "login", QObject::tr("Starts new instance and opens the login screen.")));
|
||||
QCommandLineOption(QStringList() << "l"
|
||||
<< "login",
|
||||
QObject::tr("Starts new instance and opens the login screen.")));
|
||||
parser.process(*a);
|
||||
|
||||
uint32_t profileId = Settings::getInstance().getCurrentProfileId();
|
||||
|
@ -279,7 +283,7 @@ int main(int argc, char* argv[])
|
|||
profileName = parser.value("p");
|
||||
if (!Profile::exists(profileName)) {
|
||||
qWarning() << "-p profile" << profileName + ".tox"
|
||||
<< "doesn't exist, opening login screen";
|
||||
<< "doesn't exist, opening login screen";
|
||||
doIpc = false;
|
||||
autoLogin = false;
|
||||
} else {
|
||||
|
@ -315,8 +319,10 @@ int main(int argc, char* argv[])
|
|||
// If someone else processed it, we're done here, no need to actually start qTox
|
||||
if (ipc.waitUntilAccepted(event, 2)) {
|
||||
if (eventType == "activate") {
|
||||
qDebug() << "Another qTox instance is already running. If you want to start a second "
|
||||
"instance, please open login screen (qtox -l) or start with a profile (qtox -p <profile name>).";
|
||||
qDebug()
|
||||
<< "Another qTox instance is already running. If you want to start a second "
|
||||
"instance, please open login screen (qtox -l) or start with a profile (qtox "
|
||||
"-p <profile name>).";
|
||||
} else {
|
||||
qDebug() << "Event" << eventType << "was handled by other client.";
|
||||
}
|
||||
|
@ -327,8 +333,7 @@ int main(int argc, char* argv[])
|
|||
Profile* profile = nullptr;
|
||||
|
||||
// Autologin
|
||||
if (autoLogin && Profile::exists(profileName) &&
|
||||
!Profile::isEncrypted(profileName)) {
|
||||
if (autoLogin && Profile::exists(profileName) && !Profile::isEncrypted(profileName)) {
|
||||
profile = Profile::loadProfile(profileName);
|
||||
} else {
|
||||
LoginScreen loginScreen{profileName};
|
||||
|
|
31
src/model/chatroom/chatroom.h
Normal file
31
src/model/chatroom/chatroom.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright © 2014-2018 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef MODEL_CHATROOM_H
|
||||
#define MODEL_CHATROOM_H
|
||||
|
||||
#include "src/model/contact.h"
|
||||
|
||||
class Chatroom
|
||||
{
|
||||
public:
|
||||
virtual Contact* getContact() = 0;
|
||||
};
|
||||
|
||||
#endif /* MODEL_CHATROOM_H */
|
143
src/model/chatroom/friendchatroom.cpp
Normal file
143
src/model/chatroom/friendchatroom.cpp
Normal file
|
@ -0,0 +1,143 @@
|
|||
#include "src/grouplist.h"
|
||||
#include "src/model/chatroom/friendchatroom.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/widget/contentdialog.h"
|
||||
|
||||
#include <QCollator>
|
||||
|
||||
namespace {
|
||||
|
||||
QString getShortName(const QString& name)
|
||||
{
|
||||
constexpr auto MAX_NAME_LENGTH = 30;
|
||||
if (name.length() <= MAX_NAME_LENGTH) {
|
||||
return name;
|
||||
}
|
||||
|
||||
return name.left(MAX_NAME_LENGTH).trimmed() + "…";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FriendChatroom::FriendChatroom(Friend* frnd)
|
||||
: frnd{frnd}
|
||||
{
|
||||
}
|
||||
|
||||
Friend* FriendChatroom::getFriend()
|
||||
{
|
||||
return frnd;
|
||||
}
|
||||
|
||||
Contact* FriendChatroom::getContact()
|
||||
{
|
||||
return frnd;
|
||||
}
|
||||
|
||||
void FriendChatroom::setActive(bool _active)
|
||||
{
|
||||
if (active != _active) {
|
||||
active = _active;
|
||||
emit activeChanged(active);
|
||||
}
|
||||
}
|
||||
|
||||
bool FriendChatroom::canBeInvited() const
|
||||
{
|
||||
return frnd->getStatus() != Status::Offline;
|
||||
}
|
||||
|
||||
int FriendChatroom::getCircleId() const
|
||||
{
|
||||
return Settings::getInstance().getFriendCircleID(frnd->getPublicKey());
|
||||
}
|
||||
|
||||
QString FriendChatroom::getCircleName() const
|
||||
{
|
||||
const auto circleId = getCircleId();
|
||||
return Settings::getInstance().getCircleName(circleId);
|
||||
}
|
||||
|
||||
void FriendChatroom::inviteToNewGroup()
|
||||
{
|
||||
auto core = Core::getInstance();
|
||||
const auto friendId = frnd->getId();
|
||||
const auto groupId = core->createGroup();
|
||||
core->groupInviteFriend(friendId, groupId);
|
||||
}
|
||||
|
||||
QString FriendChatroom::getAutoAcceptDir() const
|
||||
{
|
||||
const auto pk = frnd->getPublicKey();
|
||||
return Settings::getInstance().getAutoAcceptDir(pk);
|
||||
}
|
||||
|
||||
void FriendChatroom::setAutoAcceptDir(const QString& dir)
|
||||
{
|
||||
const auto pk = frnd->getPublicKey();
|
||||
Settings::getInstance().setAutoAcceptDir(pk, dir);
|
||||
}
|
||||
|
||||
void FriendChatroom::disableAutoAccept()
|
||||
{
|
||||
setAutoAcceptDir(QString{});
|
||||
}
|
||||
|
||||
bool FriendChatroom::autoAcceptEnabled() const
|
||||
{
|
||||
return getAutoAcceptDir().isEmpty();
|
||||
}
|
||||
|
||||
void FriendChatroom::inviteFriend(const Group* group)
|
||||
{
|
||||
const auto friendId = frnd->getId();
|
||||
const auto groupId = group->getId();
|
||||
Core::getInstance()->groupInviteFriend(friendId, groupId);
|
||||
}
|
||||
|
||||
QVector<GroupToDisplay> FriendChatroom::getGroups() const
|
||||
{
|
||||
QVector<GroupToDisplay> groups;
|
||||
for (const auto group : GroupList::getAllGroups()) {
|
||||
const auto name = getShortName(group->getName());
|
||||
const GroupToDisplay groupToDisplay = { name, group };
|
||||
groups.push_back(groupToDisplay);
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return sorted list of circles exclude current circle.
|
||||
*/
|
||||
QVector<CircleToDisplay> FriendChatroom::getOtherCircles() const
|
||||
{
|
||||
QVector<CircleToDisplay> circles;
|
||||
const auto currentCircleId = getCircleId();
|
||||
const auto& s = Settings::getInstance();
|
||||
for (int i = 0; i < s.getCircleCount(); ++i) {
|
||||
if (i == currentCircleId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto name = getShortName(s.getCircleName(i));
|
||||
const CircleToDisplay circle = { name, i };
|
||||
circles.push_back(circle);
|
||||
}
|
||||
|
||||
std::sort(circles.begin(), circles.end(),
|
||||
[](const CircleToDisplay& a, const CircleToDisplay& b) -> bool {
|
||||
QCollator collator;
|
||||
collator.setNumericMode(true);
|
||||
return collator.compare(a.name, b.name) < 0;
|
||||
});
|
||||
|
||||
return circles;
|
||||
}
|
||||
|
||||
void FriendChatroom::resetEventFlags()
|
||||
{
|
||||
frnd->setEventFlag(false);
|
||||
}
|
84
src/model/chatroom/friendchatroom.h
Normal file
84
src/model/chatroom/friendchatroom.h
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
Copyright © 2014-2017 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FRIEND_CHATROOM_H
|
||||
#define FRIEND_CHATROOM_H
|
||||
|
||||
#include "chatroom.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
|
||||
class Friend;
|
||||
class Group;
|
||||
|
||||
struct GroupToDisplay
|
||||
{
|
||||
QString name;
|
||||
Group* group;
|
||||
};
|
||||
|
||||
struct CircleToDisplay
|
||||
{
|
||||
QString name;
|
||||
int circleId;
|
||||
};
|
||||
|
||||
class FriendChatroom : public QObject, public Chatroom
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FriendChatroom(Friend* frnd);
|
||||
|
||||
Contact* getContact() override;
|
||||
|
||||
public slots:
|
||||
|
||||
Friend* getFriend();
|
||||
|
||||
void setActive(bool active);
|
||||
|
||||
bool canBeInvited() const;
|
||||
|
||||
int getCircleId() const;
|
||||
QString getCircleName() const;
|
||||
|
||||
void inviteToNewGroup();
|
||||
void inviteFriend(const Group* group);
|
||||
|
||||
bool autoAcceptEnabled() const;
|
||||
QString getAutoAcceptDir() const;
|
||||
void disableAutoAccept();
|
||||
void setAutoAcceptDir(const QString& dir);
|
||||
|
||||
QVector<GroupToDisplay> getGroups() const;
|
||||
QVector<CircleToDisplay> getOtherCircles() const;
|
||||
|
||||
void resetEventFlags();
|
||||
|
||||
signals:
|
||||
void activeChanged(bool activated);
|
||||
|
||||
private:
|
||||
bool active{false};
|
||||
Friend* frnd{nullptr};
|
||||
};
|
||||
|
||||
#endif // FRIEND_H
|
51
src/model/chatroom/groupchatroom.cpp
Normal file
51
src/model/chatroom/groupchatroom.cpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "groupchatroom.h"
|
||||
|
||||
#include "src/core/core.h"
|
||||
#include "src/core/toxpk.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/persistence/settings.h"
|
||||
|
||||
GroupChatroom::GroupChatroom(Group* group)
|
||||
: group{group}
|
||||
{
|
||||
}
|
||||
|
||||
Contact* GroupChatroom::getContact()
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
Group* GroupChatroom::getGroup()
|
||||
{
|
||||
return group;
|
||||
}
|
||||
|
||||
bool GroupChatroom::hasNewMessage() const
|
||||
{
|
||||
return group->getEventFlag();
|
||||
}
|
||||
|
||||
void GroupChatroom::resetEventFlags()
|
||||
{
|
||||
group->setEventFlag(false);
|
||||
group->setMentionedFlag(false);
|
||||
}
|
||||
|
||||
bool GroupChatroom::friendExists(const ToxPk& pk)
|
||||
{
|
||||
return FriendList::findFriend(pk) != nullptr;
|
||||
}
|
||||
|
||||
void GroupChatroom::inviteFriend(const ToxPk& pk)
|
||||
{
|
||||
const Friend* frnd = FriendList::findFriend(pk);
|
||||
const auto friendId = frnd->getId();
|
||||
const auto groupId = group->getId();
|
||||
const auto canInvite = frnd->getStatus() != Status::Offline;
|
||||
|
||||
if (canInvite) {
|
||||
Core::getInstance()->groupInviteFriend(friendId, groupId);
|
||||
}
|
||||
}
|
49
src/model/chatroom/groupchatroom.h
Normal file
49
src/model/chatroom/groupchatroom.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
Copyright © 2014-2018 by The qTox Project Contributors
|
||||
|
||||
This file is part of qTox, a Qt-based graphical interface for Tox.
|
||||
|
||||
qTox is libre 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.
|
||||
|
||||
qTox 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 qTox. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GROUP_CHATROOM_H
|
||||
#define GROUP_CHATROOM_H
|
||||
|
||||
#include "chatroom.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
class Group;
|
||||
class ToxPk;
|
||||
|
||||
class GroupChatroom : public QObject, public Chatroom
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupChatroom(Group* group);
|
||||
|
||||
Contact* getContact() override;
|
||||
|
||||
Group* getGroup();
|
||||
|
||||
bool hasNewMessage() const;
|
||||
void resetEventFlags();
|
||||
|
||||
bool friendExists(const ToxPk& pk);
|
||||
void inviteFriend(const ToxPk& pk);
|
||||
private:
|
||||
Group* group{nullptr};
|
||||
};
|
||||
|
||||
#endif /* GROUP_CHATROOM_H */
|
|
@ -19,14 +19,14 @@
|
|||
|
||||
#include "profileinfo.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/nexus.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QClipboard>
|
||||
#include <QFile>
|
||||
#include <QBuffer>
|
||||
|
||||
/**
|
||||
* @class ProfileInfo
|
||||
|
@ -41,7 +41,7 @@
|
|||
* @param profile Pointer to Profile.
|
||||
* @note All pointers parameters shouldn't be null.
|
||||
*/
|
||||
ProfileInfo::ProfileInfo(Core* core, Profile *profile)
|
||||
ProfileInfo::ProfileInfo(Core* core, Profile* profile)
|
||||
: profile{profile}
|
||||
, core{core}
|
||||
{
|
||||
|
@ -55,7 +55,7 @@ ProfileInfo::ProfileInfo(Core* core, Profile *profile)
|
|||
* @param password New password.
|
||||
* @return True on success, false otherwise.
|
||||
*/
|
||||
bool ProfileInfo::setPassword(const QString &password)
|
||||
bool ProfileInfo::setPassword(const QString& password)
|
||||
{
|
||||
QString errorMsg = profile->setPassword(password);
|
||||
return errorMsg.isEmpty();
|
||||
|
@ -98,7 +98,7 @@ void ProfileInfo::copyId() const
|
|||
* @brief Set self user name.
|
||||
* @param name New name.
|
||||
*/
|
||||
void ProfileInfo::setUsername(const QString &name)
|
||||
void ProfileInfo::setUsername(const QString& name)
|
||||
{
|
||||
core->setUsername(name);
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ void ProfileInfo::setUsername(const QString &name)
|
|||
* @brief Set self status message.
|
||||
* @param status New status message.
|
||||
*/
|
||||
void ProfileInfo::setStatusMessage(const QString &status)
|
||||
void ProfileInfo::setStatusMessage(const QString& status)
|
||||
{
|
||||
core->setStatusMessage(status);
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ static QString sanitize(const QString& src)
|
|||
* @param name New profile name.
|
||||
* @return Result code of rename operation.
|
||||
*/
|
||||
IProfileInfo::RenameResult ProfileInfo::renameProfile(const QString &name)
|
||||
IProfileInfo::RenameResult ProfileInfo::renameProfile(const QString& name)
|
||||
{
|
||||
QString cur = profile->getName();
|
||||
if (name.isEmpty()) {
|
||||
|
@ -191,7 +191,7 @@ static bool tryRemoveFile(const QString& filepath)
|
|||
* @param path Path to save profile.
|
||||
* @return Result code of save operation.
|
||||
*/
|
||||
IProfileInfo::SaveResult ProfileInfo::exportProfile(const QString &path) const
|
||||
IProfileInfo::SaveResult ProfileInfo::exportProfile(const QString& path) const
|
||||
{
|
||||
QString current = profile->getName() + Core::TOX_EXT;
|
||||
if (path.isEmpty()) {
|
||||
|
@ -284,7 +284,7 @@ QByteArray picToPng(const QPixmap& pic)
|
|||
* @param path Path to image, which should be the new avatar.
|
||||
* @return Code of set avatar operation.
|
||||
*/
|
||||
IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path)
|
||||
IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString& path)
|
||||
{
|
||||
if (path.isEmpty()) {
|
||||
return SetAvatarResult::EmptyPath;
|
||||
|
@ -327,7 +327,7 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path)
|
|||
return SetAvatarResult::TooLarge;
|
||||
}
|
||||
|
||||
profile->setAvatar(bytes, core->getSelfPublicKey());
|
||||
profile->setAvatar(bytes);
|
||||
return SetAvatarResult::OK;
|
||||
}
|
||||
|
||||
|
@ -336,5 +336,5 @@ IProfileInfo::SetAvatarResult ProfileInfo::setAvatar(const QString &path)
|
|||
*/
|
||||
void ProfileInfo::removeAvatar()
|
||||
{
|
||||
profile->removeAvatar();
|
||||
profile->removeSelfAvatar();
|
||||
}
|
||||
|
|
|
@ -61,8 +61,7 @@ Nexus::Nexus(QObject* parent)
|
|||
, profile{nullptr}
|
||||
, widget{nullptr}
|
||||
, running{true}
|
||||
{
|
||||
}
|
||||
{}
|
||||
|
||||
Nexus::~Nexus()
|
||||
{
|
||||
|
@ -194,9 +193,9 @@ void Nexus::showMainGUI()
|
|||
|
||||
connect(core, &Core::connected, widget, &Widget::onConnected);
|
||||
connect(core, &Core::disconnected, widget, &Widget::onDisconnected);
|
||||
connect(core, &Core::failedToStart, widget, &Widget::onFailedToStartCore,
|
||||
connect(profile, &Profile::failedToStart, widget, &Widget::onFailedToStartCore,
|
||||
Qt::BlockingQueuedConnection);
|
||||
connect(core, &Core::badProxy, widget, &Widget::onBadProxyCore, Qt::BlockingQueuedConnection);
|
||||
connect(profile, &Profile::badProxy, widget, &Widget::onBadProxyCore, Qt::BlockingQueuedConnection);
|
||||
connect(core, &Core::statusSet, widget, &Widget::onStatusSet);
|
||||
connect(core, &Core::usernameSet, widget, &Widget::setUsername);
|
||||
connect(core, &Core::statusMessageSet, widget, &Widget::setStatusMessage);
|
||||
|
@ -209,7 +208,8 @@ void Nexus::showMainGUI()
|
|||
connect(core, &Core::friendMessageReceived, widget, &Widget::onFriendMessageReceived);
|
||||
connect(core, &Core::groupInviteReceived, widget, &Widget::onGroupInviteReceived);
|
||||
connect(core, &Core::groupMessageReceived, widget, &Widget::onGroupMessageReceived);
|
||||
connect(core, &Core::groupNamelistChanged, widget, &Widget::onGroupNamelistChangedOld); // TODO(sudden6): toxcore < 0.2.0, remove
|
||||
connect(core, &Core::groupNamelistChanged, widget,
|
||||
&Widget::onGroupNamelistChangedOld); // TODO(sudden6): toxcore < 0.2.0, remove
|
||||
connect(core, &Core::groupPeerlistChanged, widget, &Widget::onGroupPeerlistChanged);
|
||||
connect(core, &Core::groupPeerNameChanged, widget, &Widget::onGroupPeerNameChanged);
|
||||
connect(core, &Core::groupTitleChanged, widget, &Widget::onGroupTitleChanged);
|
||||
|
@ -224,6 +224,8 @@ void Nexus::showMainGUI()
|
|||
connect(widget, &Widget::friendRequestAccepted, core, &Core::acceptFriendRequest);
|
||||
|
||||
profile->startCore();
|
||||
|
||||
GUI::setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "profilelocker.h"
|
||||
#include "settings.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/core/corefile.h"
|
||||
#include "src/net/avatarbroadcaster.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/widget/gui.h"
|
||||
|
@ -51,6 +52,35 @@
|
|||
|
||||
QStringList Profile::profiles;
|
||||
|
||||
void Profile::initCore(const QByteArray& toxsave, ICoreSettings& s)
|
||||
{
|
||||
Core::ToxCoreErrors err;
|
||||
core = Core::makeToxCore(toxsave, &s, &err);
|
||||
if (!core) {
|
||||
switch (err) {
|
||||
case Core::ToxCoreErrors::BAD_PROXY:
|
||||
emit badProxy();
|
||||
break;
|
||||
case Core::ToxCoreErrors::ERROR_ALLOC:
|
||||
case Core::ToxCoreErrors::FAILED_TO_START:
|
||||
case Core::ToxCoreErrors::INVALID_SAVE:
|
||||
default:
|
||||
emit failedToStart();
|
||||
}
|
||||
|
||||
qDebug() << "failed to start ToxCore";
|
||||
return;
|
||||
}
|
||||
|
||||
// save tox file when Core requests it
|
||||
connect(core.get(), &Core::saveRequest, this, &Profile::onSaveToxSave);
|
||||
// react to avatar changes
|
||||
connect(core.get(), &Core::friendAvatarRemoved, this, &Profile::removeAvatar);
|
||||
connect(core.get(), &Core::friendAvatarData, this, &Profile::saveAvatar);
|
||||
connect(core.get(), &Core::fileAvatarOfferReceived, this, &Profile::onAvatarOfferReceived,
|
||||
Qt::ConnectionType::QueuedConnection);
|
||||
}
|
||||
|
||||
Profile::Profile(QString name, const QString& password, bool isNewProfile, const QByteArray& toxsave)
|
||||
: name{name}
|
||||
, newProfile{isNewProfile}
|
||||
|
@ -60,24 +90,10 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile, const
|
|||
s.setCurrentProfile(name);
|
||||
s.saveGlobal();
|
||||
|
||||
coreThread = new QThread();
|
||||
coreThread->setObjectName("qTox Core");
|
||||
core = new Core(coreThread, *this, &Settings::getInstance());
|
||||
QObject::connect(core, &Core::idSet, this,
|
||||
[this, password](const ToxId& id) { loadDatabase(id, password); },
|
||||
Qt::QueuedConnection);
|
||||
core->moveToThread(coreThread);
|
||||
QObject::connect(coreThread, &QThread::started, core, [=]() {
|
||||
core->start(toxsave);
|
||||
initCore(toxsave, s);
|
||||
|
||||
const ToxPk selfPk = core->getSelfPublicKey();
|
||||
QByteArray data = loadAvatarData(selfPk);
|
||||
if (data.isEmpty()) {
|
||||
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
|
||||
}
|
||||
|
||||
setAvatar(data, selfPk);
|
||||
});
|
||||
const ToxId& selfId = core->getSelfId();
|
||||
loadDatabase(selfId, password);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,8 +107,7 @@ Profile::Profile(QString name, const QString& password, bool isNewProfile, const
|
|||
Profile* Profile::loadProfile(QString name, const QString& password)
|
||||
{
|
||||
if (ProfileLocker::hasLock()) {
|
||||
qCritical() << "Tried to load profile " << name
|
||||
<< ", but another profile is already locked!";
|
||||
qCritical() << "Tried to load profile " << name << ", but another profile is already locked!";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -186,8 +201,7 @@ Profile* Profile::createProfile(QString name, QString password)
|
|||
}
|
||||
|
||||
if (ProfileLocker::hasLock()) {
|
||||
qCritical() << "Tried to create profile " << name
|
||||
<< ", but another profile is already locked!";
|
||||
qCritical() << "Tried to create profile " << name << ", but another profile is already locked!";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -214,14 +228,9 @@ Profile* Profile::createProfile(QString name, QString password)
|
|||
Profile::~Profile()
|
||||
{
|
||||
if (!isRemoved && core->isReady()) {
|
||||
saveToxSave();
|
||||
onSaveToxSave();
|
||||
}
|
||||
|
||||
core->deleteLater();
|
||||
while (coreThread->isRunning())
|
||||
qApp->processEvents();
|
||||
|
||||
delete coreThread;
|
||||
if (!isRemoved) {
|
||||
Settings::getInstance().savePersonal(this);
|
||||
Settings::getInstance().sync();
|
||||
|
@ -275,7 +284,8 @@ QStringList Profile::getProfiles()
|
|||
|
||||
Core* Profile::getCore()
|
||||
{
|
||||
return core;
|
||||
// TODO(sudden6): this is evil
|
||||
return core.get();
|
||||
}
|
||||
|
||||
QString Profile::getName() const
|
||||
|
@ -288,7 +298,18 @@ QString Profile::getName() const
|
|||
*/
|
||||
void Profile::startCore()
|
||||
{
|
||||
coreThread->start();
|
||||
core->start();
|
||||
|
||||
const ToxId& selfId = core->getSelfId();
|
||||
const ToxPk& selfPk = selfId.getPublicKey();
|
||||
const QByteArray data = loadAvatarData(selfPk);
|
||||
if (data.isEmpty()) {
|
||||
qDebug() << "Self avatar not found, will broadcast empty avatar to friends";
|
||||
}
|
||||
// TODO(sudden6): moved here, because it crashes in the constructor
|
||||
// reason: Core::getInstance() returns nullptr, because it's not yet initialized
|
||||
// solution: kill Core::getInstance
|
||||
setAvatar(data);
|
||||
}
|
||||
|
||||
bool Profile::isNewProfile()
|
||||
|
@ -300,7 +321,7 @@ bool Profile::isNewProfile()
|
|||
* @brief Saves the profile's .tox save, encrypted if needed.
|
||||
* @warning Invalid on deleted profiles.
|
||||
*/
|
||||
void Profile::saveToxSave()
|
||||
void Profile::onSaveToxSave()
|
||||
{
|
||||
assert(core->isReady());
|
||||
QByteArray data = core->getToxSaveData();
|
||||
|
@ -308,12 +329,21 @@ void Profile::saveToxSave()
|
|||
saveToxSave(data);
|
||||
}
|
||||
|
||||
// TODO(sudden6): handle this better maybe?
|
||||
void Profile::onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash)
|
||||
{
|
||||
// accept if we don't have it already
|
||||
const bool accept = getAvatarHash(core->getFriendPublicKey(friendId)) != avatarHash;
|
||||
CoreFile::handleAvatarOffer(friendId, fileId, accept);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Write the .tox save, encrypted if needed.
|
||||
* @param data Byte array of profile save.
|
||||
* @return true if successfully saved, false otherwise
|
||||
* @warning Invalid on deleted profiles.
|
||||
*/
|
||||
void Profile::saveToxSave(QByteArray data)
|
||||
bool Profile::saveToxSave(QByteArray data)
|
||||
{
|
||||
assert(!isRemoved);
|
||||
ProfileLocker::assertLock();
|
||||
|
@ -324,7 +354,7 @@ void Profile::saveToxSave(QByteArray data)
|
|||
QSaveFile saveFile(path);
|
||||
if (!saveFile.open(QIODevice::WriteOnly)) {
|
||||
qCritical() << "Tox save file " << path << " couldn't be opened";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (encrypted) {
|
||||
|
@ -332,7 +362,7 @@ void Profile::saveToxSave(QByteArray data)
|
|||
if (data.isEmpty()) {
|
||||
qCritical() << "Failed to encrypt, can't save!";
|
||||
saveFile.cancelWriting();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -345,7 +375,9 @@ void Profile::saveToxSave(QByteArray data)
|
|||
} else {
|
||||
saveFile.cancelWriting();
|
||||
qCritical() << "Failed to write, can't save!";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -374,8 +406,7 @@ QString Profile::avatarPath(const ToxPk& owner, bool forceUnencrypted)
|
|||
QByteArray hash(hashSize, 0);
|
||||
crypto_generichash((uint8_t*)hash.data(), hashSize, (uint8_t*)idData.data(), idData.size(),
|
||||
(uint8_t*)pubkeyData.data(), pubkeyData.size());
|
||||
return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper()
|
||||
+ ".png";
|
||||
return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png";
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -465,26 +496,31 @@ void Profile::loadDatabase(const ToxId& id, QString password)
|
|||
}
|
||||
}
|
||||
|
||||
void Profile::setAvatar(QByteArray pic, const ToxPk& owner)
|
||||
/**
|
||||
* @brief Sets our own avatar
|
||||
* @param pic Picture to use as avatar, if empty an Identicon will be used depending on settings
|
||||
* @param owner
|
||||
*/
|
||||
void Profile::setAvatar(QByteArray pic)
|
||||
{
|
||||
QPixmap pixmap;
|
||||
QByteArray avatarData;
|
||||
const ToxPk& selfPk = core->getSelfPublicKey();
|
||||
if (!pic.isEmpty()) {
|
||||
pixmap.loadFromData(pic);
|
||||
avatarData = pic;
|
||||
} else {
|
||||
if (Settings::getInstance().getShowIdenticons()) {
|
||||
// with IDENTICON_ROWS=5 this gives a 160x160 image file
|
||||
const QImage identicon = Identicon(owner.getKey()).toImage(32);
|
||||
const QImage identicon = Identicon(selfPk.getKey()).toImage(32);
|
||||
pixmap = QPixmap::fromImage(identicon);
|
||||
|
||||
} else {
|
||||
pixmap.load(":/img/contact_dark.svg");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
saveAvatar(avatarData, owner);
|
||||
saveAvatar(selfPk, avatarData);
|
||||
|
||||
emit selfAvatarChanged(pixmap);
|
||||
AvatarBroadcaster::setAvatar(avatarData);
|
||||
|
@ -514,11 +550,10 @@ void Profile::onRequestSent(const ToxPk& friendPk, const QString& message)
|
|||
* @param pic Picture to save.
|
||||
* @param owner PK of avatar owner.
|
||||
*/
|
||||
void Profile::saveAvatar(QByteArray pic, const ToxPk& owner)
|
||||
void Profile::saveAvatar(const ToxPk& owner, const QByteArray& avatar)
|
||||
{
|
||||
if (encrypted && !pic.isEmpty()) {
|
||||
pic = passkey->encrypt(pic);
|
||||
}
|
||||
const bool needEncrypt = encrypted && !avatar.isEmpty();
|
||||
const QByteArray& pic = needEncrypt ? passkey->encrypt(avatar) : avatar;
|
||||
|
||||
QString path = avatarPath(owner);
|
||||
QDir(Settings::getInstance().getSettingsDirPath()).mkdir("avatars");
|
||||
|
@ -551,7 +586,7 @@ QByteArray Profile::getAvatarHash(const ToxPk& owner)
|
|||
/**
|
||||
* @brief Removes our own avatar.
|
||||
*/
|
||||
void Profile::removeAvatar()
|
||||
void Profile::removeSelfAvatar()
|
||||
{
|
||||
removeAvatar(core->getSelfId().getPublicKey());
|
||||
}
|
||||
|
@ -583,7 +618,7 @@ void Profile::removeAvatar(const ToxPk& owner)
|
|||
{
|
||||
QFile::remove(avatarPath(owner));
|
||||
if (owner == core->getSelfId().getPublicKey()) {
|
||||
setAvatar({}, core->getSelfPublicKey());
|
||||
setAvatar({});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -716,11 +751,23 @@ const ToxEncrypt* Profile::getPasskey() const
|
|||
void Profile::restartCore()
|
||||
{
|
||||
GUI::setEnabled(false); // Core::reset re-enables it
|
||||
if (!isRemoved && core->isReady()) {
|
||||
saveToxSave();
|
||||
|
||||
if (core && !isRemoved) {
|
||||
// TODO(sudden6): there's a potential race condition between unlocking the core loop
|
||||
// and killing the core
|
||||
const QByteArray& savedata = core->getToxSaveData();
|
||||
|
||||
// save to disk just in case
|
||||
if (saveToxSave(savedata)) {
|
||||
qDebug() << "Restarting Core";
|
||||
initCore(savedata, Settings::getInstance());
|
||||
core->start();
|
||||
} else {
|
||||
qCritical() << "Failed to save, not restarting core";
|
||||
}
|
||||
}
|
||||
|
||||
QMetaObject::invokeMethod(core, "reset");
|
||||
GUI::setEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -749,7 +796,7 @@ QString Profile::setPassword(const QString& newPassword)
|
|||
}
|
||||
|
||||
// apply new encryption
|
||||
saveToxSave();
|
||||
onSaveToxSave();
|
||||
|
||||
bool dbSuccess = false;
|
||||
|
||||
|
@ -767,13 +814,13 @@ QString Profile::setPassword(const QString& newPassword)
|
|||
Nexus::getDesktopGUI()->reloadHistory();
|
||||
|
||||
QByteArray avatar = loadAvatarData(core->getSelfId().getPublicKey());
|
||||
saveAvatar(avatar, core->getSelfId().getPublicKey());
|
||||
saveAvatar(core->getSelfId().getPublicKey(), avatar);
|
||||
|
||||
QVector<uint32_t> friendList = core->getFriendList();
|
||||
QVectorIterator<uint32_t> i(friendList);
|
||||
while (i.hasNext()) {
|
||||
const ToxPk friendPublicKey = core->getFriendPublicKey(i.next());
|
||||
saveAvatar(loadAvatarData(friendPublicKey), friendPublicKey);
|
||||
saveAvatar(friendPublicKey, loadAvatarData(friendPublicKey));
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef PROFILE_H
|
||||
#define PROFILE_H
|
||||
|
||||
#include "src/core/core.h"
|
||||
#include "src/core/toxencrypt.h"
|
||||
#include "src/core/toxid.h"
|
||||
|
||||
|
@ -33,9 +34,6 @@
|
|||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
class Core;
|
||||
class QThread;
|
||||
|
||||
class Profile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -55,17 +53,12 @@ public:
|
|||
QString setPassword(const QString& newPassword);
|
||||
const ToxEncrypt* getPasskey() const;
|
||||
|
||||
void saveToxSave();
|
||||
void saveToxSave(QByteArray data);
|
||||
|
||||
QPixmap loadAvatar();
|
||||
QPixmap loadAvatar(const ToxPk& owner);
|
||||
QByteArray loadAvatarData(const ToxPk& owner);
|
||||
void setAvatar(QByteArray pic, const ToxPk& owner);
|
||||
void saveAvatar(QByteArray pic, const ToxPk& owner);
|
||||
void setAvatar(QByteArray pic);
|
||||
QByteArray getAvatarHash(const ToxPk& owner);
|
||||
void removeAvatar(const ToxPk& owner);
|
||||
void removeAvatar();
|
||||
void removeSelfAvatar();
|
||||
|
||||
bool isHistoryEnabled();
|
||||
History* getHistory();
|
||||
|
@ -84,20 +77,30 @@ public:
|
|||
signals:
|
||||
void selfAvatarChanged(const QPixmap& pixmap);
|
||||
|
||||
// TODO(sudden6): this doesn't seem to be the right place for Core errors
|
||||
void failedToStart();
|
||||
void badProxy();
|
||||
|
||||
public slots:
|
||||
void onRequestSent(const ToxPk& friendPk, const QString& message);
|
||||
|
||||
private slots:
|
||||
void loadDatabase(const ToxId& id, QString password);
|
||||
void saveAvatar(const ToxPk& owner, const QByteArray& avatar);
|
||||
void removeAvatar(const ToxPk& owner);
|
||||
void onSaveToxSave();
|
||||
// TODO(sudden6): use ToxPk instead of friendId
|
||||
void onAvatarOfferReceived(uint32_t friendId, uint32_t fileId, const QByteArray& avatarHash);
|
||||
|
||||
private:
|
||||
Profile(QString name, const QString& password, bool newProfile, const QByteArray& toxsave);
|
||||
static QStringList getFilesByExt(QString extension);
|
||||
QString avatarPath(const ToxPk& owner, bool forceUnencrypted = false);
|
||||
bool saveToxSave(QByteArray data);
|
||||
void initCore(const QByteArray& toxsave, ICoreSettings& s);
|
||||
|
||||
private:
|
||||
Core* core;
|
||||
QThread* coreThread;
|
||||
std::unique_ptr<Core> core = nullptr;
|
||||
QString name;
|
||||
std::unique_ptr<ToxEncrypt> passkey = nullptr;
|
||||
std::shared_ptr<RawDatabase> database;
|
||||
|
|
|
@ -231,6 +231,7 @@ void Settings::loadGlobal()
|
|||
lightTrayIcon = s.value("lightTrayIcon", false).toBool();
|
||||
useEmoticons = s.value("useEmoticons", true).toBool();
|
||||
statusChangeNotificationEnabled = s.value("statusChangeNotificationEnabled", false).toBool();
|
||||
spellCheckingEnabled = s.value("spellCheckingEnabled", true).toBool();
|
||||
themeColor = s.value("themeColor", 0).toInt();
|
||||
style = s.value("style", "").toString();
|
||||
if (style == "") // Default to Fusion if available, otherwise no style
|
||||
|
@ -547,6 +548,7 @@ void Settings::saveGlobal()
|
|||
s.setValue("themeColor", themeColor);
|
||||
s.setValue("style", style);
|
||||
s.setValue("statusChangeNotificationEnabled", statusChangeNotificationEnabled);
|
||||
s.setValue("spellCheckingEnabled", spellCheckingEnabled);
|
||||
}
|
||||
s.endGroup();
|
||||
|
||||
|
@ -1046,6 +1048,22 @@ void Settings::setStatusChangeNotificationEnabled(bool newValue)
|
|||
}
|
||||
}
|
||||
|
||||
bool Settings::getSpellCheckingEnabled() const
|
||||
{
|
||||
const QMutexLocker locker{&bigLock};
|
||||
return spellCheckingEnabled;
|
||||
}
|
||||
|
||||
void Settings::setSpellCheckingEnabled(bool newValue)
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
||||
if (newValue != spellCheckingEnabled) {
|
||||
spellCheckingEnabled = newValue;
|
||||
emit statusChangeNotificationEnabledChanged(statusChangeNotificationEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool Settings::getShowInFront() const
|
||||
{
|
||||
QMutexLocker locker{&bigLock};
|
||||
|
|
|
@ -91,6 +91,8 @@ class Settings : public QObject, public ICoreSettings, public IFriendSettings,
|
|||
Q_PROPERTY(QString dateFormat READ getDateFormat WRITE setDateFormat NOTIFY dateFormatChanged FINAL)
|
||||
Q_PROPERTY(bool statusChangeNotificationEnabled READ getStatusChangeNotificationEnabled WRITE
|
||||
setStatusChangeNotificationEnabled NOTIFY statusChangeNotificationEnabledChanged FINAL)
|
||||
Q_PROPERTY(bool spellCheckingEnabled READ getSpellCheckingEnabled WRITE
|
||||
setSpellCheckingEnabled NOTIFY spellCheckingEnabledChanged FINAL)
|
||||
|
||||
// Privacy
|
||||
Q_PROPERTY(bool typingNotification READ getTypingNotification WRITE setTypingNotification NOTIFY
|
||||
|
@ -212,6 +214,7 @@ signals:
|
|||
void timestampFormatChanged(const QString& format);
|
||||
void dateFormatChanged(const QString& format);
|
||||
void statusChangeNotificationEnabledChanged(bool enabled);
|
||||
void spellCheckingEnabledChanged(bool enabled);
|
||||
void fauxOfflineMessagingChanged(bool enabled);
|
||||
|
||||
// Privacy
|
||||
|
@ -449,6 +452,9 @@ public:
|
|||
bool getStatusChangeNotificationEnabled() const;
|
||||
void setStatusChangeNotificationEnabled(bool newValue);
|
||||
|
||||
bool getSpellCheckingEnabled() const;
|
||||
void setSpellCheckingEnabled(bool newValue);
|
||||
|
||||
// Privacy
|
||||
bool getTypingNotification() const;
|
||||
void setTypingNotification(bool enabled);
|
||||
|
@ -641,6 +647,7 @@ private:
|
|||
QString timestampFormat;
|
||||
QString dateFormat;
|
||||
bool statusChangeNotificationEnabled;
|
||||
bool spellCheckingEnabled;
|
||||
|
||||
// Privacy
|
||||
bool typingNotification;
|
||||
|
|
|
@ -50,7 +50,7 @@ private:
|
|||
std::atomic_bool stopped;
|
||||
|
||||
friend class CoreAV;
|
||||
friend class ToxCall;
|
||||
friend class ToxFriendCall;
|
||||
};
|
||||
|
||||
#endif // COREVIDEOSOURCE_H
|
||||
|
|
|
@ -50,11 +50,11 @@ public slots:
|
|||
protected:
|
||||
QVBoxLayout* verLayout;
|
||||
VideoSurface* videoSurface;
|
||||
QPushButton* enterFullScreenButton = nullptr;
|
||||
|
||||
private:
|
||||
QHBoxLayout* buttonLayout = nullptr;
|
||||
QPushButton* toggleMessagesButton = nullptr;
|
||||
QPushButton* enterFullScreenButton = nullptr;
|
||||
QFrame* buttonPanel = nullptr;
|
||||
QPushButton* videoPreviewButton = nullptr;
|
||||
QPushButton* volumeButton = nullptr;
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include "groupnetcamview.h"
|
||||
#include "src/audio/audio.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/video/videosurface.h"
|
||||
|
@ -56,9 +56,7 @@ public:
|
|||
layout->addWidget(label);
|
||||
}
|
||||
|
||||
~LabeledVideo()
|
||||
{
|
||||
}
|
||||
~LabeledVideo() {}
|
||||
|
||||
VideoSurface* getVideoSurface() const
|
||||
{
|
||||
|
@ -117,6 +115,9 @@ GroupNetCamView::GroupNetCamView(int group, QWidget* parent)
|
|||
videoLabelSurface->layout()->setMargin(0);
|
||||
videoLabelSurface->setStyleSheet("QFrame { background-color: black; }");
|
||||
|
||||
// remove full screen button in audio group chat since it's useless there
|
||||
enterFullScreenButton->hide();
|
||||
|
||||
QSplitter* splitter = new QSplitter(Qt::Vertical, this);
|
||||
splitter->setChildrenCollapsible(false);
|
||||
verLayout->insertWidget(0, splitter, 1);
|
||||
|
@ -153,7 +154,7 @@ GroupNetCamView::GroupNetCamView(int group, QWidget* parent)
|
|||
setActive();
|
||||
});
|
||||
|
||||
connect(Core::getInstance(), &Core::friendAvatarChanged, this,
|
||||
connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated, this,
|
||||
&GroupNetCamView::friendAvatarChanged);
|
||||
|
||||
selfVideoSurface->setText(Core::getInstance()->getUsername());
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include "netcamview.h"
|
||||
#include "camerasource.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/persistence/settings.h"
|
||||
|
@ -75,7 +75,7 @@ NetCamView::NetCamView(int friendId, QWidget* parent)
|
|||
connections += connect(Nexus::getProfile(), &Profile::selfAvatarChanged,
|
||||
[this](const QPixmap& pixmap) { selfVideoSurface->setAvatar(pixmap); });
|
||||
|
||||
connections += connect(Core::getInstance(), &Core::friendAvatarChanged,
|
||||
connections += connect(Core::getInstance(), &Core::friendAvatarChangedDeprecated,
|
||||
[this](int FriendId, const QPixmap& pixmap) {
|
||||
if (this->friendId == FriendId)
|
||||
videoSurface->setAvatar(pixmap);
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
AboutFriendForm::AboutFriendForm(QPointer<IAboutFriend> about, QWidget* parent)
|
||||
AboutFriendForm::AboutFriendForm(std::unique_ptr<IAboutFriend> _about, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AboutFriendForm)
|
||||
, about{about}
|
||||
, about{std::move(_about)}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->label_4->hide();
|
||||
|
@ -19,7 +19,7 @@ AboutFriendForm::AboutFriendForm(QPointer<IAboutFriend> about, QWidget* parent)
|
|||
connect(ui->autogroupinvite, &QCheckBox::clicked, this, &AboutFriendForm::onAutoGroupInvite);
|
||||
connect(ui->selectSaveDir, &QPushButton::clicked, this, &AboutFriendForm::onSelectDirClicked);
|
||||
connect(ui->removeHistory, &QPushButton::clicked, this, &AboutFriendForm::onRemoveHistoryClicked);
|
||||
about.data()->connectTo_autoAcceptDirChanged([=](const QString& dir){ onAutoAcceptDirChanged(dir); });
|
||||
about->connectTo_autoAcceptDirChanged([=](const QString& dir){ onAutoAcceptDirChanged(dir); });
|
||||
|
||||
const QString dir = about->getAutoAcceptDir();
|
||||
ui->autoacceptfile->setChecked(!dir.isEmpty());
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
#include <QDialog>
|
||||
#include <QPointer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Ui {
|
||||
class AboutFriendForm;
|
||||
}
|
||||
|
@ -15,12 +17,12 @@ class AboutFriendForm : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AboutFriendForm(QPointer<IAboutFriend> about, QWidget* parent = 0);
|
||||
AboutFriendForm(std::unique_ptr<IAboutFriend> about, QWidget* parent = 0);
|
||||
~AboutFriendForm();
|
||||
|
||||
private:
|
||||
Ui::AboutFriendForm* ui;
|
||||
QPointer<IAboutFriend> about;
|
||||
const std::unique_ptr<IAboutFriend> about;
|
||||
|
||||
private slots:
|
||||
void onAutoAcceptDirChanged(const QString& path);
|
||||
|
|
|
@ -156,6 +156,8 @@ ChatFormHeader::ChatFormHeader(QWidget* parent)
|
|||
Translator::registerHandler(std::bind(&ChatFormHeader::retranslateUi, this), this);
|
||||
}
|
||||
|
||||
ChatFormHeader::~ChatFormHeader() = default;
|
||||
|
||||
void ChatFormHeader::setName(const QString& newName)
|
||||
{
|
||||
nameLabel->setText(newName);
|
||||
|
|
|
@ -55,6 +55,7 @@ public:
|
|||
};
|
||||
|
||||
ChatFormHeader(QWidget* parent = nullptr);
|
||||
~ChatFormHeader();
|
||||
|
||||
void setName(const QString& newName);
|
||||
void setMode(Mode mode);
|
||||
|
|
|
@ -27,21 +27,22 @@
|
|||
#include <QShortcut>
|
||||
#include <QSplitter>
|
||||
|
||||
#include "contentlayout.h"
|
||||
#include "friendwidget.h"
|
||||
#include "groupwidget.h"
|
||||
#include "style.h"
|
||||
#include "widget.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/grouplist.h"
|
||||
#include "src/model/chatroom/friendchatroom.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/widget/contentlayout.h"
|
||||
#include "src/widget/friendwidget.h"
|
||||
#include "src/widget/groupwidget.h"
|
||||
#include "src/widget/form/chatform.h"
|
||||
#include "src/widget/friendlistlayout.h"
|
||||
#include "src/widget/style.h"
|
||||
#include "src/widget/tool/adjustingscrollarea.h"
|
||||
#include "src/widget/translator.h"
|
||||
#include "tool/adjustingscrollarea.h"
|
||||
#include "src/widget/widget.h"
|
||||
|
||||
QString ContentDialog::username = "";
|
||||
ContentDialog* ContentDialog::currentDialog = nullptr;
|
||||
|
@ -162,11 +163,12 @@ ContentDialog::~ContentDialog()
|
|||
Translator::unregister(this);
|
||||
}
|
||||
|
||||
FriendWidget* ContentDialog::addFriend(const Friend* frnd, GenericChatForm* form)
|
||||
FriendWidget* ContentDialog::addFriend(std::shared_ptr<FriendChatroom> chatroom, GenericChatForm* form)
|
||||
{
|
||||
bool compact = Settings::getInstance().getCompactLayout();
|
||||
uint32_t friendId = frnd->getId();
|
||||
FriendWidget* friendWidget = new FriendWidget(frnd, compact);
|
||||
const auto compact = Settings::getInstance().getCompactLayout();
|
||||
auto frnd = chatroom->getFriend();
|
||||
auto friendId = frnd->getId();
|
||||
auto friendWidget = new FriendWidget(chatroom, compact);
|
||||
friendLayout->addFriendWidget(friendWidget, frnd->getStatus());
|
||||
friendChatForms[friendId] = form;
|
||||
|
||||
|
@ -187,12 +189,12 @@ FriendWidget* ContentDialog::addFriend(const Friend* frnd, GenericChatForm* form
|
|||
return friendWidget;
|
||||
}
|
||||
|
||||
GroupWidget* ContentDialog::addGroup(const Group* g, GenericChatForm* form)
|
||||
GroupWidget* ContentDialog::addGroup(std::shared_ptr<GroupChatroom> chatroom, GenericChatForm* form)
|
||||
{
|
||||
const auto g = chatroom->getGroup();
|
||||
const auto groupId = g->getId();
|
||||
const auto name = g->getName();
|
||||
const auto compact = Settings::getInstance().getCompactLayout();
|
||||
GroupWidget* groupWidget = new GroupWidget(groupId, name, compact);
|
||||
GroupWidget* groupWidget = new GroupWidget(chatroom, compact);
|
||||
groupLayout.addSortedWidget(groupWidget);
|
||||
groupChatForms[groupId] = form;
|
||||
|
||||
|
|
|
@ -20,27 +20,30 @@
|
|||
#ifndef CONTENTDIALOG_H
|
||||
#define CONTENTDIALOG_H
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include "src/widget/genericchatitemlayout.h"
|
||||
#include "src/widget/tool/activatedialog.h"
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
|
||||
template <typename K, typename V>
|
||||
class QHash;
|
||||
template <typename T>
|
||||
class QSet;
|
||||
|
||||
class QSplitter;
|
||||
class QVBoxLayout;
|
||||
class ContentDialog;
|
||||
class ContentLayout;
|
||||
class Friend;
|
||||
class FriendChatroom;
|
||||
class FriendListLayout;
|
||||
class FriendWidget;
|
||||
class GenericChatForm;
|
||||
class GenericChatroomWidget;
|
||||
class FriendWidget;
|
||||
class GroupWidget;
|
||||
class FriendListLayout;
|
||||
class Friend;
|
||||
class Group;
|
||||
class GroupChatroom;
|
||||
class GroupWidget;
|
||||
class QSplitter;
|
||||
class QVBoxLayout;
|
||||
|
||||
using ContactInfo = std::tuple<ContentDialog*, GenericChatroomWidget*>;
|
||||
|
||||
|
@ -51,8 +54,8 @@ public:
|
|||
explicit ContentDialog(QWidget* parent = nullptr);
|
||||
~ContentDialog() override;
|
||||
|
||||
FriendWidget* addFriend(const Friend* f, GenericChatForm* form);
|
||||
GroupWidget* addGroup(const Group* g, GenericChatForm* form);
|
||||
FriendWidget* addFriend(std::shared_ptr<FriendChatroom> chatroom, GenericChatForm* form);
|
||||
GroupWidget* addGroup(std::shared_ptr<GroupChatroom> chatroom, GenericChatForm* form);
|
||||
void removeFriend(int friendId);
|
||||
void removeGroup(int groupId);
|
||||
bool hasFriendWidget(int friendId, const GenericChatroomWidget* chatroomWidget) const;
|
||||
|
|
|
@ -27,21 +27,21 @@
|
|||
#include "src/core/coreav.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/history.h"
|
||||
#include "src/persistence/offlinemsgengine.h"
|
||||
#include "src/persistence/profile.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/persistence/history.h"
|
||||
#include "src/video/netcamview.h"
|
||||
#include "src/widget/chatformheader.h"
|
||||
#include "src/widget/form/loadhistorydialog.h"
|
||||
#include "src/widget/maskablepixmapwidget.h"
|
||||
#include "src/widget/searchform.h"
|
||||
#include "src/widget/style.h"
|
||||
#include "src/widget/tool/callconfirmwidget.h"
|
||||
#include "src/widget/tool/chattextedit.h"
|
||||
#include "src/widget/tool/screenshotgrabber.h"
|
||||
#include "src/widget/translator.h"
|
||||
#include "src/widget/widget.h"
|
||||
#include "src/widget/searchform.h"
|
||||
|
||||
#include <QClipboard>
|
||||
#include <QFileDialog>
|
||||
|
@ -158,7 +158,8 @@ ChatForm::ChatForm(Friend* chatFriend, History* history)
|
|||
|
||||
const Core* core = Core::getInstance();
|
||||
connect(core, &Core::fileReceiveRequested, this, &ChatForm::onFileRecvRequest);
|
||||
connect(core, &Core::friendAvatarChanged, this, &ChatForm::onAvatarChange);
|
||||
// TODO(sudden6): update slot to new API
|
||||
connect(core, &Core::friendAvatarChangedDeprecated, this, &ChatForm::onAvatarChange);
|
||||
connect(core, &Core::friendAvatarRemoved, this, &ChatForm::onAvatarRemoved);
|
||||
connect(core, &Core::fileSendStarted, this, &ChatForm::startFileSend);
|
||||
connect(core, &Core::fileSendFailed, this, &ChatForm::onFileSendFailed);
|
||||
|
@ -196,12 +197,10 @@ ChatForm::ChatForm(Friend* chatFriend, History* history)
|
|||
});
|
||||
|
||||
// reflect name changes in the header
|
||||
connect(headWidget, &ChatFormHeader::nameChanged, this, [=](const QString& newName) {
|
||||
f->setAlias(newName);
|
||||
});
|
||||
connect(headWidget, &ChatFormHeader::callAccepted, this, [this] {
|
||||
onAnswerCallTriggered(lastCallIsVideo);
|
||||
});
|
||||
connect(headWidget, &ChatFormHeader::nameChanged, this,
|
||||
[=](const QString& newName) { f->setAlias(newName); });
|
||||
connect(headWidget, &ChatFormHeader::callAccepted, this,
|
||||
[this] { onAnswerCallTriggered(lastCallIsVideo); });
|
||||
connect(headWidget, &ChatFormHeader::callRejected, this, &ChatForm::onRejectCallTriggered);
|
||||
|
||||
updateCallButtons();
|
||||
|
@ -219,6 +218,7 @@ ChatForm::~ChatForm()
|
|||
Translator::unregister(this);
|
||||
delete netcam;
|
||||
netcam = nullptr;
|
||||
delete offlineEngine;
|
||||
}
|
||||
|
||||
void ChatForm::setStatusMessage(const QString& newMessage)
|
||||
|
@ -233,8 +233,12 @@ void ChatForm::onSendTriggered()
|
|||
SendMessageStr(msgEdit->toPlainText());
|
||||
msgEdit->clear();
|
||||
}
|
||||
void ChatForm::onFileNameChanged()
|
||||
void ChatForm::onFileNameChanged(const ToxPk& friendPk)
|
||||
{
|
||||
if(friendPk != f->getPublicKey()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QMessageBox::warning(this, tr("Filename contained illegal characters"),
|
||||
tr("Illegal characters have been changed to _ \n"
|
||||
"so you can save the file on windows."));
|
||||
|
@ -263,7 +267,8 @@ void ChatForm::onTextEditChanged()
|
|||
|
||||
void ChatForm::onAttachClicked()
|
||||
{
|
||||
QStringList paths = QFileDialog::getOpenFileNames(Q_NULLPTR, tr("Send a file"), QDir::homePath(), 0, 0);
|
||||
QStringList paths =
|
||||
QFileDialog::getOpenFileNames(Q_NULLPTR, tr("Send a file"), QDir::homePath(), 0, 0);
|
||||
|
||||
if (paths.isEmpty()) {
|
||||
return;
|
||||
|
@ -709,8 +714,9 @@ void ChatForm::dropEvent(QDropEvent* ev)
|
|||
|
||||
file.close();
|
||||
if (file.isSequential()) {
|
||||
QMessageBox::critical(0, tr("Bad idea"), tr("You're trying to send a sequential file, "
|
||||
"which is not going to work!"));
|
||||
QMessageBox::critical(0, tr("Bad idea"),
|
||||
tr("You're trying to send a sequential file, "
|
||||
"which is not going to work!"));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -720,9 +726,9 @@ void ChatForm::dropEvent(QDropEvent* ev)
|
|||
}
|
||||
}
|
||||
|
||||
void ChatForm::onAvatarRemoved(uint32_t friendId)
|
||||
void ChatForm::onAvatarRemoved(const ToxPk& friendPk)
|
||||
{
|
||||
if (friendId != f->getId()) {
|
||||
if (friendPk != f->getPublicKey()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -818,7 +824,9 @@ void ChatForm::insertChatlines(QList<ChatLine::Ptr> chatLines)
|
|||
verticalBar->setValue(savedSliderPos);
|
||||
}
|
||||
|
||||
QDate ChatForm::addDateLineIfNeeded(QList<ChatLine::Ptr> msgs, QDate const& lastDate, History::HistMessage const& newMessage, MessageMetadata const& metadata)
|
||||
QDate ChatForm::addDateLineIfNeeded(QList<ChatLine::Ptr> msgs, QDate const& lastDate,
|
||||
History::HistMessage const& newMessage,
|
||||
MessageMetadata const& metadata)
|
||||
{
|
||||
// Show the date every new day
|
||||
QDate newDate = metadata.msgDateTime.date();
|
||||
|
@ -842,11 +850,13 @@ ChatForm::MessageMetadata ChatForm::getMessageMetadata(History::HistMessage cons
|
|||
return {isSelf, needSending, isAction, id, authorPk, msgDateTime};
|
||||
}
|
||||
|
||||
ChatMessage::Ptr ChatForm::chatMessageFromHistMessage(History::HistMessage const& histMessage, MessageMetadata const& metadata)
|
||||
ChatMessage::Ptr ChatForm::chatMessageFromHistMessage(History::HistMessage const& histMessage,
|
||||
MessageMetadata const& metadata)
|
||||
{
|
||||
ToxPk authorPk(ToxId(histMessage.sender).getPublicKey());
|
||||
QString authorStr = getMsgAuthorDispName(authorPk, histMessage.dispName);
|
||||
QString messageText = metadata.isAction ? histMessage.message.mid(ACTION_PREFIX.length()) : histMessage.message;
|
||||
QString messageText =
|
||||
metadata.isAction ? histMessage.message.mid(ACTION_PREFIX.length()) : histMessage.message;
|
||||
ChatMessage::MessageType type = metadata.isAction ? ChatMessage::ACTION : ChatMessage::NORMAL;
|
||||
QDateTime dateTime = metadata.needSending ? QDateTime() : metadata.msgDateTime;
|
||||
auto msg = ChatMessage::createChatMessage(authorStr, messageText, type, metadata.isSelf, dateTime);
|
||||
|
@ -986,8 +996,7 @@ void ChatForm::stopCounter(bool error)
|
|||
QString mess = error ? tr("Call with %1 ended unexpectedly. %2") : tr("Call with %1 ended. %2");
|
||||
// TODO: add notification once notifications are implemented
|
||||
|
||||
addSystemInfoMessage(mess.arg(name, dhms), ChatMessage::INFO,
|
||||
QDateTime::currentDateTime());
|
||||
addSystemInfoMessage(mess.arg(name, dhms), ChatMessage::INFO, QDateTime::currentDateTime());
|
||||
callDurationTimer->stop();
|
||||
callDuration->setText("");
|
||||
callDuration->hide();
|
||||
|
@ -1062,9 +1071,9 @@ void ChatForm::SendMessageStr(QString msg)
|
|||
QString pk = f->getPublicKey().toString();
|
||||
QString name = Core::getInstance()->getUsername();
|
||||
history->addNewMessage(pk, historyPart, selfPk, timestamp, status, name,
|
||||
[offMsgEngine, rec, ma](int64_t id) {
|
||||
offMsgEngine->registerReceipt(rec, id, ma);
|
||||
});
|
||||
[offMsgEngine, rec, ma](int64_t id) {
|
||||
offMsgEngine->registerReceipt(rec, id, ma);
|
||||
});
|
||||
} else {
|
||||
// TODO: Make faux-offline messaging work partially with the history disabled
|
||||
ma->markAsSent(QDateTime::currentDateTime());
|
||||
|
@ -1124,12 +1133,12 @@ void ChatForm::onExportChat()
|
|||
|
||||
QString buffer;
|
||||
for (const auto& it : msgs) {
|
||||
QString timestamp = it.timestamp.toString();
|
||||
QString timestamp = it.timestamp.time().toString("hh:mm:ss");
|
||||
QString datestamp = it.timestamp.date().toString("yyyy-MM-dd");
|
||||
ToxPk authorPk(ToxId(it.sender).getPublicKey());
|
||||
QString author = getMsgAuthorDispName(authorPk, it.dispName);
|
||||
|
||||
QString line = QString("%1\t%2\t%3\n").arg(timestamp, author, it.message);
|
||||
buffer = buffer % line;
|
||||
buffer = buffer % QString{datestamp % '\t' % timestamp % '\t' % author % '\t' % it.message % '\n'};
|
||||
}
|
||||
file.write(buffer.toUtf8());
|
||||
file.close();
|
||||
|
|
|
@ -73,8 +73,8 @@ public slots:
|
|||
void onAvStart(uint32_t friendId, bool video);
|
||||
void onAvEnd(uint32_t friendId, bool error);
|
||||
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
|
||||
void onAvatarRemoved(uint32_t friendId);
|
||||
void onFileNameChanged();
|
||||
void onAvatarRemoved(const ToxPk& friendPk);
|
||||
void onFileNameChanged(const ToxPk& friendPk);
|
||||
|
||||
protected slots:
|
||||
void searchInBegin(const QString& phrase, const ParameterSearch& parameter) override;
|
||||
|
@ -110,25 +110,30 @@ private slots:
|
|||
void onExportChat();
|
||||
|
||||
private:
|
||||
struct MessageMetadata {
|
||||
struct MessageMetadata
|
||||
{
|
||||
const bool isSelf;
|
||||
const bool needSending;
|
||||
const bool isAction;
|
||||
const qint64 id;
|
||||
const ToxPk authorPk;
|
||||
const QDateTime msgDateTime;
|
||||
MessageMetadata(bool isSelf, bool needSending, bool isAction, qint64 id, ToxPk authorPk, QDateTime msgDateTime) :
|
||||
isSelf{isSelf},
|
||||
needSending{needSending},
|
||||
isAction{isAction},
|
||||
id{id},
|
||||
authorPk{authorPk},
|
||||
msgDateTime{msgDateTime} {}
|
||||
MessageMetadata(bool isSelf, bool needSending, bool isAction, qint64 id, ToxPk authorPk,
|
||||
QDateTime msgDateTime)
|
||||
: isSelf{isSelf}
|
||||
, needSending{needSending}
|
||||
, isAction{isAction}
|
||||
, id{id}
|
||||
, authorPk{authorPk}
|
||||
, msgDateTime{msgDateTime}
|
||||
{}
|
||||
};
|
||||
void handleLoadedMessages(QList<History::HistMessage> newHistMsgs, bool processUndelivered);
|
||||
QDate addDateLineIfNeeded(QList<ChatLine::Ptr> msgs, QDate const& lastDate, History::HistMessage const& newMessage, MessageMetadata const& metadata);
|
||||
QDate addDateLineIfNeeded(QList<ChatLine::Ptr> msgs, QDate const& lastDate,
|
||||
History::HistMessage const& newMessage, MessageMetadata const& metadata);
|
||||
MessageMetadata getMessageMetadata(History::HistMessage const& histMessage);
|
||||
ChatMessage::Ptr chatMessageFromHistMessage(History::HistMessage const& histMessage, MessageMetadata const& metadata);
|
||||
ChatMessage::Ptr chatMessageFromHistMessage(History::HistMessage const& histMessage,
|
||||
MessageMetadata const& metadata);
|
||||
void sendLoadedMessage(ChatMessage::Ptr chatMsg, MessageMetadata const& metadata);
|
||||
void insertChatlines(QList<ChatLine::Ptr> chatLines);
|
||||
void updateMuteMicButton();
|
||||
|
|
|
@ -46,6 +46,11 @@
|
|||
#include <QKeyEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
#include <QStringBuilder>
|
||||
|
||||
#ifdef SPELL_CHECKING
|
||||
#include <KF5/SonnetUi/sonnet/spellcheckdecorator.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @class GenericChatForm
|
||||
|
@ -143,6 +148,11 @@ GenericChatForm::GenericChatForm(const Contact* contact, QWidget* parent)
|
|||
connect(&s, &Settings::chatMessageFontChanged, this, &GenericChatForm::onChatMessageFontChanged);
|
||||
|
||||
msgEdit = new ChatTextEdit();
|
||||
#ifdef SPELL_CHECKING
|
||||
if (s.getSpellCheckingEnabled()) {
|
||||
decorator = new Sonnet::SpellCheckDecorator(msgEdit);
|
||||
}
|
||||
#endif
|
||||
|
||||
sendButton = createButton("sendButton", this, &GenericChatForm::onSendTriggered);
|
||||
emoteButton = createButton("emoteButton", this, &GenericChatForm::onEmoteButtonClicked);
|
||||
|
@ -481,17 +491,16 @@ void GenericChatForm::onSaveLogClicked()
|
|||
for (ChatLine::Ptr l : lines) {
|
||||
Timestamp* rightCol = qobject_cast<Timestamp*>(l->getContent(2));
|
||||
|
||||
if (!rightCol)
|
||||
break;
|
||||
|
||||
ChatLineContent* middleCol = l->getContent(1);
|
||||
ChatLineContent* leftCol = l->getContent(0);
|
||||
|
||||
QString timestamp = rightCol->getTime().isNull() ? tr("Not sent") : rightCol->getText();
|
||||
QString nick = leftCol->getText();
|
||||
QString nick = leftCol->getText().isNull() ? tr("[System message]") : leftCol->getText();
|
||||
|
||||
QString msg = middleCol->getText();
|
||||
|
||||
plainText += QString("[%2] %1\n%3\n\n").arg(nick, timestamp, msg);
|
||||
QString timestamp = (rightCol == nullptr) ? tr("Not sent") : rightCol->getText();
|
||||
|
||||
plainText += QString{nick % "\t" % timestamp % "\t" % msg % "\n"};
|
||||
}
|
||||
|
||||
file.write(plainText.toUtf8());
|
||||
|
|
|
@ -55,6 +55,12 @@ namespace Ui {
|
|||
class MainWindow;
|
||||
}
|
||||
|
||||
#ifdef SPELL_CHECKING
|
||||
namespace Sonnet {
|
||||
class SpellCheckDecorator;
|
||||
}
|
||||
#endif
|
||||
|
||||
class GenericChatForm : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -170,6 +176,9 @@ protected:
|
|||
SearchForm *searchForm;
|
||||
ChatLog* chatWidget;
|
||||
ChatTextEdit* msgEdit;
|
||||
#ifdef SPELL_CHECKING
|
||||
Sonnet::SpellCheckDecorator* decorator{nullptr};
|
||||
#endif
|
||||
FlyoutOverlayWidget* fileFlyout;
|
||||
GenericNetCamView* netcam;
|
||||
Widget* parent;
|
||||
|
|
|
@ -55,18 +55,19 @@ AdvancedForm::AdvancedForm()
|
|||
Settings& s = Settings::getInstance();
|
||||
bodyUI->cbEnableIPv6->setChecked(s.getEnableIPv6());
|
||||
bodyUI->cbMakeToxPortable->setChecked(Settings::getInstance().getMakeToxPortable());
|
||||
const bool udpEnabled = !s.getForceTCP();
|
||||
bodyUI->cbEnableUDP->setChecked(udpEnabled);
|
||||
bodyUI->cbEnableLanDiscovery->setChecked(s.getEnableLanDiscovery());
|
||||
bodyUI->cbEnableLanDiscovery->setEnabled(udpEnabled);
|
||||
bodyUI->proxyAddr->setText(s.getProxyAddr());
|
||||
quint16 port = s.getProxyPort();
|
||||
if (port > 0)
|
||||
if (port > 0) {
|
||||
bodyUI->proxyPort->setValue(port);
|
||||
}
|
||||
|
||||
int index = static_cast<int>(s.getProxyType());
|
||||
bodyUI->proxyType->setCurrentIndex(index);
|
||||
on_proxyType_currentIndexChanged(index);
|
||||
const bool udpEnabled = !s.getForceTCP() && (s.getProxyType() == Settings::ProxyType::ptNone);
|
||||
bodyUI->cbEnableUDP->setChecked(udpEnabled);
|
||||
bodyUI->cbEnableLanDiscovery->setChecked(s.getEnableLanDiscovery() && udpEnabled);
|
||||
bodyUI->cbEnableLanDiscovery->setEnabled(udpEnabled);
|
||||
|
||||
QString warningBody = tr("Unless you %1 know what you are doing, "
|
||||
"please do %2 change anything here. Changes "
|
||||
|
@ -176,7 +177,9 @@ void AdvancedForm::on_cbEnableUDP_stateChanged()
|
|||
{
|
||||
const bool enableUdp = bodyUI->cbEnableUDP->isChecked();
|
||||
Settings::getInstance().setForceTCP(!enableUdp);
|
||||
const bool enableLanDiscovery = Settings::getInstance().getEnableLanDiscovery();
|
||||
bodyUI->cbEnableLanDiscovery->setEnabled(enableUdp);
|
||||
bodyUI->cbEnableLanDiscovery->setChecked(enableUdp && enableLanDiscovery);
|
||||
}
|
||||
|
||||
void AdvancedForm::on_cbEnableLanDiscovery_stateChanged()
|
||||
|
@ -191,8 +194,9 @@ void AdvancedForm::on_proxyAddr_editingFinished()
|
|||
|
||||
void AdvancedForm::on_proxyPort_valueChanged(int port)
|
||||
{
|
||||
if (port <= 0)
|
||||
if (port <= 0) {
|
||||
port = 0;
|
||||
}
|
||||
|
||||
Settings::getInstance().setProxyPort(port);
|
||||
}
|
||||
|
@ -200,9 +204,14 @@ void AdvancedForm::on_proxyPort_valueChanged(int port)
|
|||
void AdvancedForm::on_proxyType_currentIndexChanged(int index)
|
||||
{
|
||||
Settings::ProxyType proxytype = static_cast<Settings::ProxyType>(index);
|
||||
const bool proxyEnabled = proxytype != Settings::ProxyType::ptNone;
|
||||
|
||||
bodyUI->proxyAddr->setEnabled(proxyEnabled);
|
||||
bodyUI->proxyPort->setEnabled(proxyEnabled);
|
||||
// enabling UDP and proxy can be a privacy issue
|
||||
bodyUI->cbEnableUDP->setEnabled(!proxyEnabled);
|
||||
bodyUI->cbEnableUDP->setChecked(!proxyEnabled);
|
||||
|
||||
bodyUI->proxyAddr->setEnabled(proxytype != Settings::ProxyType::ptNone);
|
||||
bodyUI->proxyPort->setEnabled(proxytype != Settings::ProxyType::ptNone);
|
||||
Settings::getInstance().setProxyType(proxytype);
|
||||
}
|
||||
|
||||
|
|
|
@ -191,10 +191,7 @@ void AVForm::on_videoModescomboBox_currentIndexChanged(int index)
|
|||
return;
|
||||
}
|
||||
|
||||
// note: grabber is self-managed and will destroy itself when done
|
||||
ScreenshotGrabber* screenshotGrabber = new ScreenshotGrabber;
|
||||
|
||||
auto onGrabbed = [screenshotGrabber, devName, this](QRect region) {
|
||||
auto onGrabbed = [devName, this](QRect region) {
|
||||
VideoMode mode(region);
|
||||
mode.width = mode.width / 2 * 2;
|
||||
mode.height = mode.height / 2 * 2;
|
||||
|
@ -210,6 +207,9 @@ void AVForm::on_videoModescomboBox_currentIndexChanged(int index)
|
|||
open(devName, mode);
|
||||
};
|
||||
|
||||
// note: grabber is self-managed and will destroy itself when done
|
||||
ScreenshotGrabber* screenshotGrabber = new ScreenshotGrabber;
|
||||
|
||||
connect(screenshotGrabber, &ScreenshotGrabber::regionChosen, this, onGrabbed,
|
||||
Qt::QueuedConnection);
|
||||
screenshotGrabber->showGrabber();
|
||||
|
|
|
@ -105,6 +105,11 @@ GeneralForm::GeneralForm(SettingsWidget* myParent)
|
|||
#else
|
||||
bodyUI->checkUpdates->setVisible(false);
|
||||
#endif
|
||||
|
||||
#ifndef SPELL_CHECKING
|
||||
bodyUI->cbSpellChecking->setVisible(false);
|
||||
#endif
|
||||
|
||||
bodyUI->checkUpdates->setChecked(s.getCheckUpdates());
|
||||
|
||||
for (int i = 0; i < locales.size(); ++i) {
|
||||
|
@ -126,6 +131,7 @@ GeneralForm::GeneralForm(SettingsWidget* myParent)
|
|||
|
||||
bodyUI->cbAutorun->setChecked(s.getAutorun());
|
||||
|
||||
bodyUI->cbSpellChecking->setChecked(s.getSpellCheckingEnabled());
|
||||
bodyUI->lightTrayIcon->setChecked(s.getLightTrayIcon());
|
||||
bool showSystemTray = s.getShowSystemTray();
|
||||
|
||||
|
@ -172,6 +178,11 @@ void GeneralForm::on_cbAutorun_stateChanged()
|
|||
Settings::getInstance().setAutorun(bodyUI->cbAutorun->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::on_cbSpellChecking_stateChanged()
|
||||
{
|
||||
Settings::getInstance().setSpellCheckingEnabled(bodyUI->cbSpellChecking->isChecked());
|
||||
}
|
||||
|
||||
void GeneralForm::on_showSystemTray_stateChanged()
|
||||
{
|
||||
Settings::getInstance().setShowSystemTray(bodyUI->showSystemTray->isChecked());
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
private slots:
|
||||
void on_transComboBox_currentIndexChanged(int index);
|
||||
void on_cbAutorun_stateChanged();
|
||||
void on_cbSpellChecking_stateChanged();
|
||||
void on_showSystemTray_stateChanged();
|
||||
void on_startInTray_stateChanged();
|
||||
void on_closeToTray_stateChanged();
|
||||
|
|
|
@ -119,6 +119,13 @@
|
|||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbSpellChecking">
|
||||
<property name="text">
|
||||
<string>Spell checking</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="lightTrayIcon">
|
||||
<property name="sizePolicy">
|
||||
|
|
|
@ -51,7 +51,7 @@ SettingsWidget::SettingsWidget(QWidget* parent)
|
|||
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
QVBoxLayout* bodyLayout = new QVBoxLayout();
|
||||
bodyLayout = std::unique_ptr<QVBoxLayout>(new QVBoxLayout());
|
||||
|
||||
settingsWidgets = std::unique_ptr<QTabWidget>(new QTabWidget(this));
|
||||
settingsWidgets->setTabPosition(QTabWidget::North);
|
||||
|
|
|
@ -56,6 +56,7 @@ private:
|
|||
void retranslateUi();
|
||||
|
||||
private:
|
||||
std::unique_ptr<QVBoxLayout> bodyLayout;
|
||||
std::unique_ptr<QTabWidget> settingsWidgets;
|
||||
std::array<std::unique_ptr<GenericForm>, 6> cfgForms;
|
||||
int currentIndex;
|
||||
|
|
|
@ -24,11 +24,11 @@
|
|||
#include "maskablepixmapwidget.h"
|
||||
|
||||
#include "src/core/core.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/about/aboutfriend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/about/aboutfriend.h"
|
||||
#include "src/model/chatroom/friendchatroom.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/grouplist.h"
|
||||
#include "src/persistence/settings.h"
|
||||
#include "src/widget/about/aboutfriendform.h"
|
||||
#include "src/widget/form/chatform.h"
|
||||
|
@ -38,7 +38,6 @@
|
|||
|
||||
#include <QApplication>
|
||||
#include <QBitmap>
|
||||
#include <QCollator>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QDebug>
|
||||
#include <QDrag>
|
||||
|
@ -49,11 +48,6 @@
|
|||
|
||||
#include <cassert>
|
||||
|
||||
namespace
|
||||
{
|
||||
constexpr auto MAX_NAME_LENGTH = 30;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class FriendWidget
|
||||
*
|
||||
|
@ -61,21 +55,22 @@ constexpr auto MAX_NAME_LENGTH = 30;
|
|||
* For example, used on friend list.
|
||||
* When you click should open the chat with friend. Widget has a context menu.
|
||||
*/
|
||||
|
||||
FriendWidget::FriendWidget(const Friend* f, bool compact)
|
||||
FriendWidget::FriendWidget(std::shared_ptr<FriendChatroom> chatroom, bool compact)
|
||||
: GenericChatroomWidget(compact)
|
||||
, frnd{f}
|
||||
, chatroom{chatroom}
|
||||
, isDefaultAvatar{true}
|
||||
{
|
||||
avatar->setPixmap(QPixmap(":/img/contact.svg"));
|
||||
statusPic.setPixmap(QPixmap(":/img/status/offline.svg"));
|
||||
statusPic.setMargin(3);
|
||||
setName(f->getDisplayedName());
|
||||
nameLabel->setTextFormat(Qt::PlainText);
|
||||
// update on changes of the displayed name
|
||||
connect(f, &Friend::displayedNameChanged, this, &FriendWidget::setName);
|
||||
|
||||
auto frnd = chatroom->getFriend();
|
||||
nameLabel->setText(frnd->getDisplayedName());
|
||||
// update alias when edited
|
||||
connect(nameLabel, &CroppingLabel::editFinished, f, &Friend::setAlias);
|
||||
connect(nameLabel, &CroppingLabel::editFinished, frnd, &Friend::setAlias);
|
||||
// update on changes of the displayed name
|
||||
connect(frnd, &Friend::displayedNameChanged, nameLabel, &CroppingLabel::setText);
|
||||
connect(chatroom.get(), &FriendChatroom::activeChanged, this, &FriendWidget::setActive);
|
||||
statusMessageLabel->setTextFormat(Qt::PlainText);
|
||||
}
|
||||
|
||||
|
@ -107,92 +102,77 @@ void FriendWidget::onContextMenuCalled(QContextMenuEvent* event)
|
|||
|
||||
QMenu menu;
|
||||
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const auto friendId = frnd->getId();
|
||||
const ContentDialog* contentDialog = ContentDialog::getFriendDialog(friendId);
|
||||
const auto contentDialog = ContentDialog::getFriendDialog(friendId);
|
||||
|
||||
// TODO: move to model
|
||||
if (!contentDialog || contentDialog->chatroomWidgetCount() > 1) {
|
||||
const auto openChatWindow = menu.addAction(tr("Open chat in new window"));
|
||||
connect(openChatWindow, &QAction::triggered, [=]() { emit newWindowOpened(this); });
|
||||
}
|
||||
|
||||
// TODO: move to model
|
||||
if (contentDialog && contentDialog->hasFriendWidget(friendId, this)) {
|
||||
const auto removeChatWindow = menu.addAction(tr("Remove chat from this window"));
|
||||
connect(removeChatWindow, &QAction::triggered, this, &FriendWidget::removeChatWindow);
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
QMenu* inviteMenu = menu.addMenu(tr("Invite to group",
|
||||
"Menu to invite a friend to a groupchat"));
|
||||
inviteMenu->setEnabled(frnd->getStatus() != Status::Offline);
|
||||
QMenu* inviteMenu =
|
||||
menu.addMenu(tr("Invite to group", "Menu to invite a friend to a groupchat"));
|
||||
inviteMenu->setEnabled(chatroom->canBeInvited());
|
||||
const auto newGroupAction = inviteMenu->addAction(tr("To new group"));
|
||||
connect(newGroupAction, &QAction::triggered, this, &FriendWidget::moveToNewGroup);
|
||||
connect(newGroupAction, &QAction::triggered, chatroom.get(), &FriendChatroom::inviteToNewGroup);
|
||||
inviteMenu->addSeparator();
|
||||
|
||||
for (const Group* group : GroupList::getAllGroups()) {
|
||||
auto name = group->getName();
|
||||
if (name.length() > MAX_NAME_LENGTH) {
|
||||
name = name.left(MAX_NAME_LENGTH).trimmed() + "..";
|
||||
}
|
||||
const auto groupAction = inviteMenu->addAction(tr("Invite to group '%1'").arg(name));
|
||||
connect(groupAction, &QAction::triggered, [=]() { inviteFriend(friendId, group); });
|
||||
for (const auto group : chatroom->getGroups()) {
|
||||
const auto groupAction = inviteMenu->addAction(tr("Invite to group '%1'").arg(group.name));
|
||||
connect(groupAction, &QAction::triggered, [=]() {
|
||||
chatroom->inviteFriend(group.group);
|
||||
});
|
||||
}
|
||||
|
||||
const auto& s = Settings::getInstance();
|
||||
const auto circleId = s.getFriendCircleID(frnd->getPublicKey());
|
||||
auto circleMenu = menu.addMenu(tr("Move to circle...",
|
||||
"Menu to move a friend into a different circle"));
|
||||
const auto circleId = chatroom->getCircleId();
|
||||
auto circleMenu =
|
||||
menu.addMenu(tr("Move to circle...", "Menu to move a friend into a different circle"));
|
||||
|
||||
const auto pk = frnd->getPublicKey();
|
||||
const auto newCircleAction = circleMenu->addAction(tr("To new circle"));
|
||||
connect(newCircleAction, &QAction::triggered, this, &FriendWidget::moveToNewCircle);
|
||||
|
||||
if (circleId != -1) {
|
||||
const QString circleName = s.getCircleName(circleId);
|
||||
const auto removeCircleAction = circleMenu->addAction(
|
||||
tr("Remove from circle '%1'").arg(circleName));
|
||||
const auto circleName = chatroom->getCircleName();
|
||||
const auto removeCircleAction =
|
||||
circleMenu->addAction(tr("Remove from circle '%1'").arg(circleName));
|
||||
connect(removeCircleAction, &QAction::triggered, this, &FriendWidget::removeFromCircle);
|
||||
}
|
||||
|
||||
circleMenu->addSeparator();
|
||||
|
||||
QList<QAction*> circleActionList;
|
||||
for (int i = 0; i < s.getCircleCount(); ++i) {
|
||||
if (i == circleId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto name = s.getCircleName(i);
|
||||
QAction* action = new QAction(tr("Move to circle \"%1\"").arg(name), circleMenu);
|
||||
connect(action, &QAction::triggered, [=]() { moveToCircle(i); });
|
||||
circleActionList.push_back(action);
|
||||
for (const auto circle : chatroom->getOtherCircles()) {
|
||||
QAction* action = new QAction(tr("Move to circle \"%1\"").arg(circle.name), circleMenu);
|
||||
connect(action, &QAction::triggered, [=]() { moveToCircle(circle.circleId); });
|
||||
circleMenu->addAction(action);
|
||||
}
|
||||
|
||||
std::sort(circleActionList.begin(), circleActionList.end(),
|
||||
[](const QAction* lhs, const QAction* rhs) -> bool {
|
||||
QCollator collator;
|
||||
collator.setNumericMode(true);
|
||||
return collator.compare(lhs->text(), rhs->text()) < 0;
|
||||
});
|
||||
|
||||
circleMenu->addActions(circleActionList);
|
||||
|
||||
const auto setAlias = menu.addAction(tr("Set alias..."));
|
||||
connect(setAlias, &QAction::triggered, [this]() { nameLabel->editBegin(); });
|
||||
connect(setAlias, &QAction::triggered, nameLabel, &CroppingLabel::editBegin);
|
||||
|
||||
menu.addSeparator();
|
||||
auto autoAccept = menu.addAction(tr("Auto accept files from this friend",
|
||||
"context menu entry"));
|
||||
const auto dir = s.getAutoAcceptDir(pk);
|
||||
auto autoAccept =
|
||||
menu.addAction(tr("Auto accept files from this friend", "context menu entry"));
|
||||
autoAccept->setCheckable(true);
|
||||
autoAccept->setChecked(!dir.isEmpty());
|
||||
autoAccept->setChecked(!chatroom->autoAcceptEnabled());
|
||||
connect(autoAccept, &QAction::triggered, this, &FriendWidget::changeAutoAccept);
|
||||
menu.addSeparator();
|
||||
|
||||
// TODO: move to model
|
||||
if (!contentDialog || !contentDialog->hasFriendWidget(friendId, this)) {
|
||||
const auto removeAction = menu.addAction(
|
||||
tr("Remove friend", "Menu to remove the friend from our friendlist"));
|
||||
const auto removeAction =
|
||||
menu.addAction(tr("Remove friend", "Menu to remove the friend from our friendlist"));
|
||||
connect(removeAction, &QAction::triggered, this, [=]() { emit removeFriend(friendId); },
|
||||
Qt::QueuedConnection);
|
||||
Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
@ -211,28 +191,15 @@ void FriendWidget::onContextMenuCalled(QContextMenuEvent* event)
|
|||
|
||||
void FriendWidget::removeChatWindow()
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const auto friendId = frnd->getId();
|
||||
ContentDialog* contentDialog = ContentDialog::getFriendDialog(friendId);
|
||||
contentDialog->removeFriend(friendId);
|
||||
}
|
||||
|
||||
void FriendWidget::moveToNewGroup()
|
||||
{
|
||||
const auto friendId = frnd->getId();
|
||||
const auto groupId = Core::getInstance()->createGroup();
|
||||
Core::getInstance()->groupInviteFriend(friendId, groupId);
|
||||
}
|
||||
namespace {
|
||||
|
||||
void FriendWidget::inviteFriend(uint32_t friendId, const Group* group)
|
||||
{
|
||||
Core::getInstance()->groupInviteFriend(friendId, group->getId());
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
std::tuple<CircleWidget*, FriendListWidget*> getCircleAndFriendList(
|
||||
const Friend* frnd, FriendWidget* fw)
|
||||
std::tuple<CircleWidget*, FriendListWidget*> getCircleAndFriendList(const Friend* frnd, FriendWidget* fw)
|
||||
{
|
||||
const auto pk = frnd->getPublicKey();
|
||||
const auto circleId = Settings::getInstance().getFriendCircleID(pk);
|
||||
|
@ -242,10 +209,11 @@ std::tuple<CircleWidget*, FriendListWidget*> getCircleAndFriendList(
|
|||
return std::make_tuple(circleWidget, friendList);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void FriendWidget::moveToNewCircle()
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
CircleWidget* circleWidget;
|
||||
FriendListWidget* friendList;
|
||||
std::tie(circleWidget, friendList) = getCircleAndFriendList(frnd, this);
|
||||
|
@ -258,7 +226,7 @@ void FriendWidget::moveToNewCircle()
|
|||
friendList->addCircleWidget(this);
|
||||
} else {
|
||||
const auto pk = frnd->getPublicKey();
|
||||
auto &s = Settings::getInstance();
|
||||
auto& s = Settings::getInstance();
|
||||
auto circleId = s.addCircle();
|
||||
s.setFriendCircleID(pk, circleId);
|
||||
}
|
||||
|
@ -266,6 +234,7 @@ void FriendWidget::moveToNewCircle()
|
|||
|
||||
void FriendWidget::removeFromCircle()
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
CircleWidget* circleWidget;
|
||||
FriendListWidget* friendList;
|
||||
std::tie(circleWidget, friendList) = getCircleAndFriendList(frnd, this);
|
||||
|
@ -286,6 +255,7 @@ void FriendWidget::removeFromCircle()
|
|||
|
||||
void FriendWidget::moveToCircle(int newCircleId)
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const auto pk = frnd->getPublicKey();
|
||||
const auto oldCircleId = Settings::getInstance().getFriendCircleID(pk);
|
||||
auto& s = Settings::getInstance();
|
||||
|
@ -309,48 +279,47 @@ void FriendWidget::moveToCircle(int newCircleId)
|
|||
|
||||
void FriendWidget::changeAutoAccept(bool enable)
|
||||
{
|
||||
const auto pk = frnd->getPublicKey();
|
||||
auto &s = Settings::getInstance();
|
||||
if (enable) {
|
||||
const auto oldDir = s.getAutoAcceptDir(pk);
|
||||
const auto oldDir = chatroom->getAutoAcceptDir();
|
||||
const auto newDir = QFileDialog::getExistingDirectory(
|
||||
Q_NULLPTR, tr("Choose an auto accept directory", "popup title"), oldDir);
|
||||
|
||||
const auto friendId = frnd->getId();
|
||||
qDebug() << "Setting auto accept dir for" << friendId << "to" << newDir;
|
||||
s.setAutoAcceptDir(pk, newDir);
|
||||
chatroom->setAutoAcceptDir(newDir);
|
||||
} else {
|
||||
qDebug() << "not checked";
|
||||
s.setAutoAcceptDir(pk, "");
|
||||
chatroom->disableAutoAccept();
|
||||
}
|
||||
}
|
||||
void FriendWidget::showDetails()
|
||||
{
|
||||
const QPointer<IAboutFriend> about = new AboutFriend(frnd, &Settings::getInstance());
|
||||
auto aboutUser = new AboutFriendForm(about, Widget::getInstance());
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const auto iabout = new AboutFriend(frnd, &Settings::getInstance());
|
||||
std::unique_ptr<IAboutFriend> about = std::unique_ptr<IAboutFriend>(iabout);
|
||||
const auto aboutUser = new AboutFriendForm(std::move(about), Widget::getInstance());
|
||||
aboutUser->show();
|
||||
}
|
||||
|
||||
void FriendWidget::setAsActiveChatroom()
|
||||
{
|
||||
setActive(true);
|
||||
|
||||
if (isDefaultAvatar) {
|
||||
avatar->setPixmap(QPixmap(":img/contact_dark.svg"));
|
||||
}
|
||||
}
|
||||
|
||||
void FriendWidget::setAsInactiveChatroom()
|
||||
{
|
||||
setActive(false);
|
||||
}
|
||||
|
||||
void FriendWidget::setActive(bool active)
|
||||
{
|
||||
GenericChatroomWidget::setActive(active);
|
||||
if (isDefaultAvatar) {
|
||||
avatar->setPixmap(QPixmap(":img/contact.svg"));
|
||||
const auto uri = active ? QStringLiteral(":img/contact_dark.svg")
|
||||
: QStringLiteral(":img/contact.svg");
|
||||
avatar->setPixmap(QPixmap{uri});
|
||||
}
|
||||
}
|
||||
|
||||
void FriendWidget::updateStatusLight()
|
||||
{
|
||||
// clang-format off
|
||||
static const QString statuses[] = {
|
||||
":img/status/online.svg",
|
||||
":img/status/online_notification.svg",
|
||||
|
@ -361,7 +330,9 @@ void FriendWidget::updateStatusLight()
|
|||
":img/status/offline.svg",
|
||||
":img/status/offline_notification.svg",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const bool event = frnd->getEventFlag();
|
||||
const int index = static_cast<int>(frnd->getStatus()) * 2 + event;
|
||||
statusPic.setPixmap(QPixmap(statuses[index]));
|
||||
|
@ -382,6 +353,7 @@ void FriendWidget::updateStatusLight()
|
|||
|
||||
QString FriendWidget::getStatusString() const
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
const int status = static_cast<int>(frnd->getStatus());
|
||||
const bool event = frnd->getEventFlag();
|
||||
|
||||
|
@ -397,11 +369,12 @@ QString FriendWidget::getStatusString() const
|
|||
|
||||
const Friend* FriendWidget::getFriend() const
|
||||
{
|
||||
return frnd;
|
||||
return chatroom->getFriend();
|
||||
}
|
||||
|
||||
void FriendWidget::search(const QString& searchString, bool hide)
|
||||
{
|
||||
const auto frnd = chatroom->getFriend();
|
||||
searchName(searchString, hide);
|
||||
const Settings& s = Settings::getInstance();
|
||||
const uint32_t circleId = s.getFriendCircleID(frnd->getPublicKey());
|
||||
|
@ -413,14 +386,13 @@ void FriendWidget::search(const QString& searchString, bool hide)
|
|||
|
||||
void FriendWidget::resetEventFlags()
|
||||
{
|
||||
// Hack to avoid edit const Friend. TODO: Repalce on emit
|
||||
Friend* f = FriendList::findFriend(frnd->getId());
|
||||
f->setEventFlag(false);
|
||||
chatroom->resetEventFlags();
|
||||
}
|
||||
|
||||
void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic)
|
||||
void FriendWidget::onAvatarChange(const ToxPk& friendPk, const QPixmap& pic)
|
||||
{
|
||||
if (friendId != frnd->getId()) {
|
||||
const auto frnd = chatroom->getFriend();
|
||||
if (friendPk != frnd->getPublicKey()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -428,9 +400,10 @@ void FriendWidget::onAvatarChange(uint32_t friendId, const QPixmap& pic)
|
|||
avatar->setPixmap(pic);
|
||||
}
|
||||
|
||||
void FriendWidget::onAvatarRemoved(uint32_t friendId)
|
||||
void FriendWidget::onAvatarRemoved(const ToxPk& friendPk)
|
||||
{
|
||||
if (friendId != frnd->getId()) {
|
||||
const auto frnd = chatroom->getFriend();
|
||||
if (friendPk != frnd->getPublicKey()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,11 @@
|
|||
#define FRIENDWIDGET_H
|
||||
|
||||
#include "genericchatroomwidget.h"
|
||||
#include "src/core/toxpk.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class FriendChatroom;
|
||||
class QPixmap;
|
||||
class MaskablePixmapWidget;
|
||||
|
||||
|
@ -27,7 +31,8 @@ class FriendWidget : public GenericChatroomWidget
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FriendWidget(const Friend* f, bool compact);
|
||||
FriendWidget(std::shared_ptr<FriendChatroom> chatform, bool compact);
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent* event) override final;
|
||||
void setAsActiveChatroom() override final;
|
||||
void setAsInactiveChatroom() override final;
|
||||
|
@ -45,9 +50,10 @@ signals:
|
|||
void contextMenuCalled(QContextMenuEvent* event);
|
||||
|
||||
public slots:
|
||||
void onAvatarChange(uint32_t friendId, const QPixmap& pic);
|
||||
void onAvatarRemoved(uint32_t friendId);
|
||||
void onAvatarChange(const ToxPk& friendPk, const QPixmap& pic);
|
||||
void onAvatarRemoved(const ToxPk& friendPk);
|
||||
void onContextMenuCalled(QContextMenuEvent* event);
|
||||
void setActive(bool active);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent* ev) override;
|
||||
|
@ -56,8 +62,6 @@ protected:
|
|||
|
||||
private slots:
|
||||
void removeChatWindow();
|
||||
void moveToNewGroup();
|
||||
void inviteFriend(uint32_t friendId, const Group* group);
|
||||
void moveToNewCircle();
|
||||
void removeFromCircle();
|
||||
void moveToCircle(int circleId);
|
||||
|
@ -65,7 +69,7 @@ private slots:
|
|||
void showDetails();
|
||||
|
||||
public:
|
||||
const Friend* frnd;
|
||||
std::shared_ptr<FriendChatroom> chatroom;
|
||||
bool isDefaultAvatar;
|
||||
};
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ class GenericChatroomWidget : public GenericChatItemWidget
|
|||
public:
|
||||
explicit GenericChatroomWidget(bool compact, QWidget* parent = 0);
|
||||
|
||||
public slots:
|
||||
virtual void setAsActiveChatroom() = 0;
|
||||
virtual void setAsInactiveChatroom() = 0;
|
||||
virtual void updateStatusLight() = 0;
|
||||
|
@ -53,7 +54,6 @@ public:
|
|||
virtual bool eventFilter(QObject*, QEvent*) final override;
|
||||
|
||||
bool isActive();
|
||||
void setActive(bool active);
|
||||
|
||||
void setName(const QString& name);
|
||||
void setStatusMsg(const QString& status);
|
||||
|
@ -62,7 +62,6 @@ public:
|
|||
|
||||
void reloadTheme();
|
||||
|
||||
public slots:
|
||||
void activate();
|
||||
void compactChange(bool compact);
|
||||
|
||||
|
@ -75,10 +74,10 @@ protected:
|
|||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void enterEvent(QEvent* e) override;
|
||||
void leaveEvent(QEvent* e) override;
|
||||
|
||||
QPoint dragStartPos;
|
||||
void setActive(bool active);
|
||||
|
||||
protected:
|
||||
QPoint dragStartPos;
|
||||
QColor lastColor;
|
||||
QHBoxLayout* mainLayout = nullptr;
|
||||
QVBoxLayout* textLayout = nullptr;
|
||||
|
|
|
@ -40,22 +40,24 @@
|
|||
#include "src/widget/translator.h"
|
||||
#include "tool/croppinglabel.h"
|
||||
|
||||
GroupWidget::GroupWidget(int groupId, const QString& name, bool compact)
|
||||
GroupWidget::GroupWidget(std::shared_ptr<GroupChatroom> chatroom, bool compact)
|
||||
: GenericChatroomWidget(compact)
|
||||
, groupId{groupId}
|
||||
, groupId{static_cast<int>(chatroom->getGroup()->getId())}
|
||||
, chatroom{chatroom}
|
||||
{
|
||||
avatar->setPixmap(Style::scaleSvgImage(":img/group.svg", avatar->width(), avatar->height()));
|
||||
statusPic.setPixmap(QPixmap(":img/status/online.svg"));
|
||||
statusPic.setMargin(3);
|
||||
nameLabel->setText(name);
|
||||
|
||||
Group* g = chatroom->getGroup();
|
||||
nameLabel->setText(g->getName());
|
||||
|
||||
updateUserCount();
|
||||
setAcceptDrops(true);
|
||||
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
connect(g, &Group::titleChanged, this, &GroupWidget::updateTitle);
|
||||
connect(g, &Group::userListChanged, this, &GroupWidget::updateUserCount);
|
||||
connect(nameLabel, &CroppingLabel::editFinished, this, &GroupWidget::setTitle);
|
||||
connect(nameLabel, &CroppingLabel::editFinished, g, &Group::setName);
|
||||
Translator::registerHandler(std::bind(&GroupWidget::retranslateUi, this), this);
|
||||
}
|
||||
|
||||
|
@ -64,12 +66,6 @@ GroupWidget::~GroupWidget()
|
|||
Translator::unregister(this);
|
||||
}
|
||||
|
||||
void GroupWidget::setTitle(const QString& newName)
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
g->setName(newName);
|
||||
}
|
||||
|
||||
void GroupWidget::updateTitle(uint32_t groupId, const QString& author, const QString& newName)
|
||||
{
|
||||
Q_UNUSED(groupId);
|
||||
|
@ -79,8 +75,9 @@ void GroupWidget::updateTitle(uint32_t groupId, const QString& author, const QSt
|
|||
|
||||
void GroupWidget::contextMenuEvent(QContextMenuEvent* event)
|
||||
{
|
||||
if (!active)
|
||||
if (!active) {
|
||||
setBackgroundRole(QPalette::Highlight);
|
||||
}
|
||||
|
||||
installEventFilter(this); // Disable leave event.
|
||||
|
||||
|
@ -89,14 +86,17 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||
QAction* openChatWindow = nullptr;
|
||||
QAction* removeChatWindow = nullptr;
|
||||
|
||||
// TODO: Move to model
|
||||
ContentDialog* contentDialog = ContentDialog::getGroupDialog(groupId);
|
||||
bool notAlone = contentDialog != nullptr && contentDialog->chatroomWidgetCount() > 1;
|
||||
const bool notAlone = contentDialog != nullptr && contentDialog->chatroomWidgetCount() > 1;
|
||||
|
||||
if (contentDialog == nullptr || notAlone)
|
||||
if (contentDialog == nullptr || notAlone) {
|
||||
openChatWindow = menu.addAction(tr("Open chat in new window"));
|
||||
}
|
||||
|
||||
if (contentDialog && contentDialog->hasGroupWidget(groupId, this))
|
||||
if (contentDialog && contentDialog->hasGroupWidget(groupId, this)) {
|
||||
removeChatWindow = menu.addAction(tr("Remove chat from this window"));
|
||||
}
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
|
@ -107,8 +107,9 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||
|
||||
removeEventFilter(this);
|
||||
|
||||
if (!active)
|
||||
if (!active) {
|
||||
setBackgroundRole(QPalette::Window);
|
||||
}
|
||||
|
||||
if (!selectedItem) {
|
||||
return;
|
||||
|
@ -119,6 +120,7 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||
} else if (selectedItem == openChatWindow) {
|
||||
emit newWindowOpened(this);
|
||||
} else if (selectedItem == removeChatWindow) {
|
||||
// TODO: move to model
|
||||
ContentDialog* contentDialog = ContentDialog::getGroupDialog(groupId);
|
||||
contentDialog->removeGroup(groupId);
|
||||
} else if (selectedItem == setTitle) {
|
||||
|
@ -128,16 +130,18 @@ void GroupWidget::contextMenuEvent(QContextMenuEvent* event)
|
|||
|
||||
void GroupWidget::mousePressEvent(QMouseEvent* ev)
|
||||
{
|
||||
if (ev->button() == Qt::LeftButton)
|
||||
if (ev->button() == Qt::LeftButton) {
|
||||
dragStartPos = ev->pos();
|
||||
}
|
||||
|
||||
GenericChatroomWidget::mousePressEvent(ev);
|
||||
}
|
||||
|
||||
void GroupWidget::mouseMoveEvent(QMouseEvent* ev)
|
||||
{
|
||||
if (!(ev->buttons() & Qt::LeftButton))
|
||||
if (!(ev->buttons() & Qt::LeftButton)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((dragStartPos - ev->pos()).manhattanLength() > QApplication::startDragDistance()) {
|
||||
QMimeData* mdata = new QMimeData;
|
||||
|
@ -152,14 +156,8 @@ void GroupWidget::mouseMoveEvent(QMouseEvent* ev)
|
|||
|
||||
void GroupWidget::updateUserCount()
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
if (g) {
|
||||
int peersCount = g->getPeersCount();
|
||||
if (peersCount == 1)
|
||||
statusMessageLabel->setText(tr("1 user in chat"));
|
||||
else
|
||||
statusMessageLabel->setText(tr("%1 users in chat").arg(peersCount));
|
||||
}
|
||||
int peersCount = chatroom->getGroup()->getPeersCount();
|
||||
statusMessageLabel->setText(tr("%n user(s) in chat", "", peersCount));
|
||||
}
|
||||
|
||||
void GroupWidget::setAsActiveChatroom()
|
||||
|
@ -176,25 +174,24 @@ void GroupWidget::setAsInactiveChatroom()
|
|||
|
||||
void GroupWidget::updateStatusLight()
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
Group* g = chatroom->getGroup();
|
||||
|
||||
if (!g->getEventFlag()) {
|
||||
statusPic.setPixmap(QPixmap(":img/status/online.svg"));
|
||||
statusPic.setMargin(3);
|
||||
} else {
|
||||
if (g->getEventFlag()) {
|
||||
statusPic.setPixmap(QPixmap(":img/status/online_notification.svg"));
|
||||
statusPic.setMargin(1);
|
||||
} else {
|
||||
statusPic.setPixmap(QPixmap(":img/status/online.svg"));
|
||||
statusPic.setMargin(3);
|
||||
}
|
||||
}
|
||||
|
||||
QString GroupWidget::getStatusString() const
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
|
||||
if (!g->getEventFlag())
|
||||
return "Online";
|
||||
else
|
||||
return "New Message";
|
||||
if (chatroom->hasNewMessage()) {
|
||||
return tr("New Message");
|
||||
} else {
|
||||
return tr("Online");
|
||||
}
|
||||
}
|
||||
|
||||
void GroupWidget::editName()
|
||||
|
@ -202,49 +199,51 @@ void GroupWidget::editName()
|
|||
nameLabel->editBegin();
|
||||
}
|
||||
|
||||
// TODO: Remove
|
||||
Group* GroupWidget::getGroup() const
|
||||
{
|
||||
return GroupList::findGroup(groupId);
|
||||
return chatroom->getGroup();
|
||||
}
|
||||
|
||||
void GroupWidget::resetEventFlags()
|
||||
{
|
||||
Group* g = GroupList::findGroup(groupId);
|
||||
g->setEventFlag(false);
|
||||
g->setMentionedFlag(false);
|
||||
chatroom->resetEventFlags();
|
||||
}
|
||||
|
||||
void GroupWidget::dragEnterEvent(QDragEnterEvent* ev)
|
||||
{
|
||||
ToxId toxId = ToxId(ev->mimeData()->text());
|
||||
Friend* frnd = FriendList::findFriend(toxId.getPublicKey());
|
||||
if (frnd)
|
||||
// TODO: Send ToxPk in mimeData
|
||||
const ToxId toxId = ToxId(ev->mimeData()->text());
|
||||
const ToxPk pk = toxId.getPublicKey();
|
||||
if (chatroom->friendExists(pk)) {
|
||||
ev->acceptProposedAction();
|
||||
}
|
||||
|
||||
if (!active)
|
||||
if (!active) {
|
||||
setBackgroundRole(QPalette::Highlight);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupWidget::dragLeaveEvent(QDragLeaveEvent*)
|
||||
{
|
||||
if (!active)
|
||||
if (!active) {
|
||||
setBackgroundRole(QPalette::Window);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupWidget::dropEvent(QDropEvent* ev)
|
||||
{
|
||||
ToxId toxId = ToxId(ev->mimeData()->text());
|
||||
Friend* frnd = FriendList::findFriend(toxId.getPublicKey());
|
||||
if (!frnd)
|
||||
const ToxId toxId = ToxId(ev->mimeData()->text());
|
||||
const ToxPk pk = toxId.getPublicKey();
|
||||
if (!chatroom->friendExists(pk)) {
|
||||
return;
|
||||
|
||||
int friendId = frnd->getId();
|
||||
if (frnd->getStatus() != Status::Offline) {
|
||||
Core::getInstance()->groupInviteFriend(friendId, groupId);
|
||||
}
|
||||
|
||||
if (!active)
|
||||
chatroom->inviteFriend(pk);
|
||||
|
||||
if (!active) {
|
||||
setBackgroundRole(QPalette::Window);
|
||||
}
|
||||
}
|
||||
|
||||
void GroupWidget::setName(const QString& name)
|
||||
|
|
|
@ -22,11 +22,15 @@
|
|||
|
||||
#include "genericchatroomwidget.h"
|
||||
|
||||
#include "src/model/chatroom/groupchatroom.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
class GroupWidget final : public GenericChatroomWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
GroupWidget(int GroupId, const QString& Name, bool compact);
|
||||
GroupWidget(std::shared_ptr<GroupChatroom> chatroom, bool compact);
|
||||
~GroupWidget();
|
||||
void setAsInactiveChatroom() final override;
|
||||
void setAsActiveChatroom() final override;
|
||||
|
@ -51,12 +55,14 @@ protected:
|
|||
|
||||
private slots:
|
||||
void retranslateUi();
|
||||
void setTitle(const QString& newName);
|
||||
void updateTitle(uint32_t groupId, const QString& author, const QString& newName);
|
||||
void updateUserCount();
|
||||
|
||||
public:
|
||||
int groupId;
|
||||
|
||||
private:
|
||||
std::shared_ptr<GroupChatroom> chatroom;
|
||||
};
|
||||
|
||||
#endif // GROUPWIDGET_H
|
||||
|
|
|
@ -35,9 +35,10 @@ public slots:
|
|||
void setEditable(bool editable);
|
||||
void setElideMode(Qt::TextElideMode elide);
|
||||
|
||||
void setText(const QString& text);
|
||||
QString fullText();
|
||||
|
||||
public slots:
|
||||
void setText(const QString& text);
|
||||
void minimizeMaximumWidth();
|
||||
|
||||
signals:
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "friendlistwidget.h"
|
||||
#include "friendwidget.h"
|
||||
#include "groupwidget.h"
|
||||
#include "src/model/groupinvite.h"
|
||||
#include "maskablepixmapwidget.h"
|
||||
#include "splitterrestorer.h"
|
||||
#include "systemtrayicon.h"
|
||||
|
@ -52,11 +51,15 @@
|
|||
#include "src/audio/audio.h"
|
||||
#include "src/core/core.h"
|
||||
#include "src/core/coreav.h"
|
||||
#include "src/model/chatroom/friendchatroom.h"
|
||||
#include "src/model/chatroom/groupchatroom.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/friendlist.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/model/profile/profileinfo.h"
|
||||
#include "src/grouplist.h"
|
||||
#include "src/model/friend.h"
|
||||
#include "src/model/group.h"
|
||||
#include "src/model/groupinvite.h"
|
||||
#include "src/model/profile/profileinfo.h"
|
||||
#include "src/net/autoupdate.h"
|
||||
#include "src/nexus.h"
|
||||
#include "src/persistence/offlinemsgengine.h"
|
||||
|
@ -528,11 +531,13 @@ Widget::~Widget()
|
|||
|
||||
delete icon;
|
||||
delete profileForm;
|
||||
delete profileInfo;
|
||||
delete addFriendForm;
|
||||
delete groupInviteForm;
|
||||
delete filesForm;
|
||||
delete timer;
|
||||
delete contentLayout;
|
||||
delete settingsWidget;
|
||||
|
||||
FriendList::clear();
|
||||
GroupList::clear();
|
||||
|
@ -980,11 +985,13 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
|
|||
s.updateFriendAddress(friendPk.toString());
|
||||
|
||||
Friend* newfriend = FriendList::addFriend(friendId, friendPk);
|
||||
bool compact = s.getCompactLayout();
|
||||
FriendWidget* widget = new FriendWidget(newfriend, compact);
|
||||
History* history = Nexus::getProfile()->getHistory();
|
||||
ChatForm* friendForm = new ChatForm(newfriend, history);
|
||||
std::shared_ptr<FriendChatroom> chatroom(new FriendChatroom(newfriend));
|
||||
const auto compact = Settings::getInstance().getCompactLayout();
|
||||
auto widget = new FriendWidget(chatroom, compact);
|
||||
auto history = Nexus::getProfile()->getHistory();
|
||||
auto friendForm = new ChatForm(newfriend, history);
|
||||
|
||||
friendChatrooms[friendId] = chatroom;
|
||||
friendWidgets[friendId] = widget;
|
||||
chatForms[friendId] = friendForm;
|
||||
|
||||
|
@ -1020,7 +1027,7 @@ void Widget::addFriend(uint32_t friendId, const ToxPk& friendPk)
|
|||
QPixmap avatar = Nexus::getProfile()->loadAvatar(friendPk);
|
||||
if (!avatar.isNull()) {
|
||||
friendForm->onAvatarChange(friendId, avatar);
|
||||
widget->onAvatarChange(friendId, avatar);
|
||||
widget->onAvatarChange(friendPk, avatar);
|
||||
}
|
||||
|
||||
FilterCriteria filter = getFilterCriteria();
|
||||
|
@ -1240,8 +1247,9 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
|
|||
onAddClicked();
|
||||
}
|
||||
|
||||
ChatForm* form = chatForms[friendId];
|
||||
FriendWidget* friendWidget = dialog->addFriend(frnd, form);
|
||||
auto form = chatForms[friendId];
|
||||
auto chatroom = friendChatrooms[friendId];
|
||||
FriendWidget* friendWidget = dialog->addFriend(chatroom, form);
|
||||
|
||||
friendWidget->setStatusMsg(widget->getStatusMsg());
|
||||
|
||||
|
@ -1251,9 +1259,8 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
|
|||
auto widgetRemoveFriend = static_cast<void (Widget::*)(int)>(&Widget::removeFriend);
|
||||
#endif
|
||||
connect(friendWidget, &FriendWidget::removeFriend, this, widgetRemoveFriend);
|
||||
connect(friendWidget, &FriendWidget::middleMouseClicked, dialog, [=]() {
|
||||
dialog->removeFriend(friendId);
|
||||
});
|
||||
connect(friendWidget, &FriendWidget::middleMouseClicked, dialog,
|
||||
[=]() { dialog->removeFriend(friendId); });
|
||||
connect(friendWidget, &FriendWidget::copyFriendIdToClipboard, this,
|
||||
&Widget::copyFriendIdToClipboard);
|
||||
|
||||
|
@ -1263,16 +1270,14 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
|
|||
connect(friendWidget, &FriendWidget::contextMenuCalled, widget,
|
||||
[=](QContextMenuEvent* event) { emit widget->contextMenuCalled(event); });
|
||||
|
||||
connect(friendWidget, &FriendWidget::chatroomWidgetClicked,
|
||||
[=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
});
|
||||
connect(friendWidget, &FriendWidget::newWindowOpened,
|
||||
[=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->newWindowOpened(widget);
|
||||
});
|
||||
connect(friendWidget, &FriendWidget::chatroomWidgetClicked, [=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
});
|
||||
connect(friendWidget, &FriendWidget::newWindowOpened, [=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->newWindowOpened(widget);
|
||||
});
|
||||
// FIXME: emit should be removed
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
|
||||
|
@ -1282,7 +1287,7 @@ void Widget::addFriendDialog(const Friend* frnd, ContentDialog* dialog)
|
|||
|
||||
QPixmap avatar = Nexus::getProfile()->loadAvatar(frnd->getPublicKey());
|
||||
if (!avatar.isNull()) {
|
||||
friendWidget->onAvatarChange(friendId, avatar);
|
||||
friendWidget->onAvatarChange(frnd->getPublicKey(), avatar);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1298,7 +1303,8 @@ void Widget::addGroupDialog(Group* group, ContentDialog* dialog)
|
|||
}
|
||||
|
||||
auto chatForm = groupChatForms[groupId];
|
||||
auto groupWidget = dialog->addGroup(group, chatForm);
|
||||
auto chatroom = groupChatrooms[groupId];
|
||||
auto groupWidget = dialog->addGroup(chatroom, chatForm);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
|
||||
auto removeGroup = QOverload<int>::of(&Widget::removeGroup);
|
||||
#else
|
||||
|
@ -1306,25 +1312,22 @@ void Widget::addGroupDialog(Group* group, ContentDialog* dialog)
|
|||
#endif
|
||||
connect(groupWidget, &GroupWidget::removeGroup, this, removeGroup);
|
||||
connect(groupWidget, &GroupWidget::chatroomWidgetClicked, chatForm, &GroupChatForm::focusInput);
|
||||
connect(groupWidget, &GroupWidget::middleMouseClicked, dialog, [=]() {
|
||||
dialog->removeGroup(groupId);
|
||||
});
|
||||
connect(groupWidget, &GroupWidget::middleMouseClicked, dialog,
|
||||
[=]() { dialog->removeGroup(groupId); });
|
||||
connect(groupWidget, &GroupWidget::chatroomWidgetClicked, chatForm, &ChatForm::focusInput);
|
||||
|
||||
// Signal transmission from the created `groupWidget` (which shown in
|
||||
// ContentDialog) to the `widget` (which shown in main widget)
|
||||
// FIXME: emit should be removed
|
||||
connect(groupWidget, &GroupWidget::chatroomWidgetClicked,
|
||||
[=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
});
|
||||
connect(groupWidget, &GroupWidget::chatroomWidgetClicked, [=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
});
|
||||
|
||||
connect(groupWidget, &GroupWidget::newWindowOpened,
|
||||
[=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->newWindowOpened(widget);
|
||||
});
|
||||
connect(groupWidget, &GroupWidget::newWindowOpened, [=](GenericChatroomWidget* w) {
|
||||
Q_UNUSED(w);
|
||||
emit widget->newWindowOpened(widget);
|
||||
});
|
||||
|
||||
// FIXME: emit should be removed
|
||||
emit widget->chatroomWidgetClicked(widget);
|
||||
|
@ -1915,11 +1918,12 @@ Group* Widget::createGroup(int groupId)
|
|||
|
||||
bool enabled = coreAv->isGroupAvEnabled(groupId);
|
||||
Group* newgroup = GroupList::addGroup(groupId, groupName, enabled, core->getUsername());
|
||||
bool compact = Settings::getInstance().getCompactLayout();
|
||||
GroupWidget* widget = new GroupWidget(groupId, groupName, compact);
|
||||
groupWidgets[groupId] = widget;
|
||||
|
||||
std::shared_ptr<GroupChatroom> chatroom(new GroupChatroom(newgroup));
|
||||
const auto compact = Settings::getInstance().getCompactLayout();
|
||||
auto widget = new GroupWidget(chatroom, compact);
|
||||
auto form = new GroupChatForm(newgroup);
|
||||
groupWidgets[groupId] = widget;
|
||||
groupChatrooms[groupId] = chatroom;
|
||||
groupChatForms[groupId] = form;
|
||||
|
||||
contactListWidget->addGroupWidget(widget);
|
||||
|
@ -1934,9 +1938,7 @@ Group* Widget::createGroup(int groupId)
|
|||
auto widgetRemoveGroup = static_cast<void (Widget::*)(int)>(&Widget::removeGroup);
|
||||
#endif
|
||||
connect(widget, &GroupWidget::removeGroup, this, widgetRemoveGroup);
|
||||
connect(widget, &GroupWidget::middleMouseClicked, this, [=]() {
|
||||
removeGroup(groupId);
|
||||
});
|
||||
connect(widget, &GroupWidget::middleMouseClicked, this, [=]() { removeGroup(groupId); });
|
||||
connect(widget, &GroupWidget::chatroomWidgetClicked, form, &ChatForm::focusInput);
|
||||
connect(form, &GroupChatForm::sendMessage, core, &Core::sendGroupMessage);
|
||||
connect(form, &GroupChatForm::sendAction, core, &Core::sendGroupAction);
|
||||
|
@ -2275,8 +2277,7 @@ inline QIcon Widget::prepareIcon(QString path, int w, int h)
|
|||
}
|
||||
|
||||
desktop = desktop.toLower();
|
||||
if (desktop == "xfce" || desktop.contains("gnome") || desktop == "mate"
|
||||
|| desktop == "x-cinnamon") {
|
||||
if (desktop == "xfce" || desktop.contains("gnome") || desktop == "mate" || desktop == "x-cinnamon") {
|
||||
if (w > 0 && h > 0) {
|
||||
QSvgRenderer renderer(path);
|
||||
|
||||
|
|
|
@ -48,11 +48,13 @@ class ContentLayout;
|
|||
class Core;
|
||||
class FilesForm;
|
||||
class Friend;
|
||||
class FriendChatroom;
|
||||
class FriendListWidget;
|
||||
class FriendWidget;
|
||||
class GenericChatroomWidget;
|
||||
class Group;
|
||||
class GroupChatForm;
|
||||
class GroupChatroom;
|
||||
class GroupInvite;
|
||||
class GroupInviteForm;
|
||||
class GroupWidget;
|
||||
|
@ -303,9 +305,12 @@ private:
|
|||
unsigned int unreadGroupInvites;
|
||||
int icon_size;
|
||||
|
||||
QMap<uint32_t, GroupWidget*> groupWidgets;
|
||||
QMap<uint32_t, FriendWidget*> friendWidgets;
|
||||
QMap<uint32_t, std::shared_ptr<FriendChatroom>> friendChatrooms;
|
||||
QMap<uint32_t, ChatForm*> chatForms;
|
||||
|
||||
QMap<uint32_t, GroupWidget*> groupWidgets;
|
||||
QMap<uint32_t, std::shared_ptr<GroupChatroom>> groupChatrooms;
|
||||
QMap<uint32_t, GroupChatForm*> groupChatForms;
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
|
|
76
translations/bg.ts
vendored
76
translations/bg.ts
vendored
|
@ -81,39 +81,39 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Enables the experimental audio backend with echo cancelling support, needs qTox restart to take effect.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Включва експериментален звуков процесор с потискане на ехото, изисква рестарт на qTox.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Enable experimental audio backend</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Включва експериментален звуков процесор</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio quality</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Качество на звука</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transmitted audio quality. Lower this setting if your bandwidth is not high enough or if you want to lower the internet usage.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Качество на предавания звук. Намалете тази настройка ако нямате достатъчно широколентова връзка или ако искате да намалите използването на интернет.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High (64 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Високо (64 kбита/с)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Medium (32 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Средно (32 kбита/с)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Low (16 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ниско (16 kбита/с)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Very low (8 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Много ниско (8 kбита/с)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Threshold</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Прагова стойност</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -198,7 +198,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Public key:</source>
|
||||
<translation type="unfinished">Публичен ключ:</translation>
|
||||
<translation>Публичен ключ:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Used aliases:</source>
|
||||
|
@ -242,7 +242,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Automatically accept group chat invitations from this contact if set.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Автоматично приемане на покани за групов чат от този контакт ако е включено.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto accept group invites</source>
|
||||
|
@ -355,7 +355,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>%1 Tox ID is invalid or does not exist</source>
|
||||
<comment>Toxme error</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 Tox ID е невалиден или не съществува</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>You can't add yourself as a friend!</source>
|
||||
|
@ -364,24 +364,24 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Open contact list</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Отваряне на списък с контакти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't open file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Не може да се отвори файла</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't open the contact file</source>
|
||||
<extracomment>Error message when trying to open a contact list file to import</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Не може да се отвори файла с контакти</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Invalid file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Невалиден файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>We couldn't find any contacts to import in this file!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Не са намерени контакти за зареждане в този файл!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tox ID</source>
|
||||
|
@ -401,11 +401,11 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Open</source>
|
||||
<extracomment>Button to choose a file with a list of contacts to import</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Отваряне</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Send friend requests</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Изпращане на заявка за приятелство</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 here! Tox me maybe?</source>
|
||||
|
@ -414,7 +414,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Import a list of contacts, one Tox ID per line</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Зареждане на списък с контакти, по един Tox ID на ред</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>Ready to import %n contact(s), click send to confirm</source>
|
||||
|
@ -426,7 +426,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Import contacts</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Зареждане на контакти</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -658,7 +658,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Export to file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Изнасяне към файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Save chat log</source>
|
||||
|
@ -666,7 +666,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Call with %1 ended unexpectedly. %2</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Връзката с %1 завърши неочаквано. %2</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -929,7 +929,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Never</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Никога</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1297,7 +1297,7 @@ instead of system taskbar.</source>
|
|||
<name>GroupInviteWidget</name>
|
||||
<message>
|
||||
<source>Invited by %1 on %2 at %3.</source>
|
||||
<translation>Поканен от %1 на %2 в %3</translation>
|
||||
<translation>Поканен от %1на %2 в %3.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Join</source>
|
||||
|
@ -1581,7 +1581,7 @@ Profile does not contain your history.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>%1 messages</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 съобщения</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -1803,7 +1803,7 @@ You may want to create one.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Contact search input for known friends</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Входно поле за търсене на известни приятели</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sorting and visibility</source>
|
||||
|
@ -1961,18 +1961,18 @@ If you are getting spammed with friend requests, change the NoSpam.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>BlackList</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Черен списък</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Filter group message by group member's public key. Put public key here, one per line.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Филтриране на групови съобщения по публичен ключ на членовете. Поставете побличните ключове тук, по един на ред.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Profile</name>
|
||||
<message>
|
||||
<source>Failed to derive key from password, the profile won't use the new password.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Неуспешно произвеждане на ключ от парола, профилът няма за използва новата парола.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't change password on the database, it might be corrupted or use the old password.</source>
|
||||
|
@ -2128,7 +2128,7 @@ Please use another image.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Couldn't change password</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Неуспешна смяна на парола</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This bunch of characters tells other Tox clients how to contact you.
|
||||
|
@ -2139,7 +2139,7 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Empty path is unavaliable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Празен път не е достъпен</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to rename</source>
|
||||
|
@ -2155,15 +2155,15 @@ This ID includes the NoSpam code (in blue), and the checksum (in gray).</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Empty name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Празно име</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty name is unavaliable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Празно име не е достъпно</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty path</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Празен път</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't change password on the database, it might be corrupted or use the old password.</source>
|
||||
|
@ -2409,11 +2409,11 @@ It will be installed when qTox restarts.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Reformatting text in progress..</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Изпълнява се преформатиране на текст..</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Starts new instance and opens the login screen.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Стартира ново копие и отваря екрана за вписване.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -2709,7 +2709,7 @@ It will be installed when qTox restarts.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Use identicons instead of empty avatars</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Използване на идентикони вместо празни аватари</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
94
translations/ko.ts
vendored
94
translations/ko.ts
vendored
|
@ -33,7 +33,7 @@
|
|||
</message>
|
||||
<message>
|
||||
<source>Playback device</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>재생 기기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use slider to set volume of your speakers.</source>
|
||||
|
@ -87,7 +87,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio quality</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>오디오 음질</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transmitted audio quality. Lower this setting if your bandwidth is not high enough or if you want to lower the internet usage.</source>
|
||||
|
@ -95,23 +95,23 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>High (64 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>높음(64kbps)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Medium (32 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>중간(32kbps)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Low (16 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>낮음 (16kbps)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Very low (8 kbps)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>아주 낮음 (8kbps)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Threshold</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>한계점</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -135,7 +135,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>You are using qTox version %1.</source>
|
||||
<translation>qTox 버젼 %1.</translation>
|
||||
<translation>qTox 버젼 %1 사용중.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Commit hash: %1</source>
|
||||
|
@ -184,7 +184,7 @@ which may lead to problems with video calls.</source>
|
|||
<name>AboutFriendForm</name>
|
||||
<message>
|
||||
<source>Dialog</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>대화</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>username</source>
|
||||
|
@ -232,11 +232,11 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio</source>
|
||||
<translation type="unfinished">오디오</translation>
|
||||
<translation>오디오</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio + Video</source>
|
||||
<translation type="unfinished">오디오 + 비디오</translation>
|
||||
<translation>오디오 + 비디오</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Automatically accept group chat invitations from this contact if set.</source>
|
||||
|
@ -244,7 +244,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Auto accept group invites</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>그룹 초대를 받아드립니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remove history (operation can not be undone!)</source>
|
||||
|
@ -264,11 +264,11 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>History removed</source>
|
||||
<translation type="unfinished">기록이 삭제되었습니다</translation>
|
||||
<translation>기록 삭제</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Chat history with %1 removed!</source>
|
||||
<translation type="unfinished">%1 채팅기록이 삭제되었습니다!</translation>
|
||||
<translation>%1 채팅기록이 삭제되었습니다!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Choose an auto accept directory</source>
|
||||
|
@ -357,7 +357,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>You can't add yourself as a friend!</source>
|
||||
<extracomment>When trying to add your own Tox ID as friend</extracomment>
|
||||
<translation type="unfinished">자기 자신을 친구로 추가할 수 없습니다!</translation>
|
||||
<translation>자신을 친구로 추가할 수 없습니다!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open contact list</source>
|
||||
|
@ -365,7 +365,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Couldn't open file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>파일을 열 수 없습니다</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't open the contact file</source>
|
||||
|
@ -393,16 +393,16 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Message</source>
|
||||
<extracomment>The message you send in friend requests</extracomment>
|
||||
<translation type="unfinished">메시지</translation>
|
||||
<translation>메시지</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<extracomment>Button to choose a file with a list of contacts to import</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>열기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Send friend requests</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>친구 요청을 보냄</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 here! Tox me maybe?</source>
|
||||
|
@ -475,7 +475,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Save File</source>
|
||||
<translation>파일보관</translation>
|
||||
<translation>파일저장</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logs (*.log)</source>
|
||||
|
@ -499,7 +499,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Portable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>이동가능</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Connection Settings</source>
|
||||
|
@ -584,7 +584,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Bad idea</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>좋지않은 의견</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 calling</source>
|
||||
|
@ -606,7 +606,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>qTox wasn't able to save the screenshot</source>
|
||||
<translatorcomment>laut Duden ist Screenshot schon deutsch</translatorcomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>스크린샷을 저장할 수 없었습니다.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Call with %1 ended. %2</source>
|
||||
|
@ -646,7 +646,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>online</source>
|
||||
<comment>contact status</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>온라인</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>%1 is now %2</source>
|
||||
|
@ -659,7 +659,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Save chat log</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>채팅 기록을 저장</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Call with %1 ended unexpectedly. %2</source>
|
||||
|
@ -674,7 +674,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Start audio call</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>음성통화 시작</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>End audio call</source>
|
||||
|
@ -694,7 +694,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Start video call</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>영상통화 시작</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>End video call</source>
|
||||
|
@ -718,7 +718,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Mute call</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>음소거 전화</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Microphone can be muted only during a call</source>
|
||||
|
@ -795,12 +795,12 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Your message is too long!</source>
|
||||
<comment>Error while sending friendship request</comment>
|
||||
<translation type="unfinished">제한된 메시지 길이를 초과했습니다!</translation>
|
||||
<translation>제한된 메시지 길이를 초과했습니다!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Friend is already added</source>
|
||||
<comment>Error while sending friendship request</comment>
|
||||
<translation type="unfinished">이미 추가된 친구입니다</translation>
|
||||
<translation>이미 추가된 친구입니다</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -895,7 +895,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Transferred Files</source>
|
||||
<comment>"Headline" of the window</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>전송 된 파일</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Downloads</source>
|
||||
|
@ -910,23 +910,23 @@ which may lead to problems with video calls.</source>
|
|||
<name>FriendListWidget</name>
|
||||
<message>
|
||||
<source>Today</source>
|
||||
<translation type="unfinished">오늘</translation>
|
||||
<translation>오늘</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Yesterday</source>
|
||||
<translation type="unfinished">어제</translation>
|
||||
<translation>어제</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Last 7 days</source>
|
||||
<translation type="unfinished">지난 7일</translation>
|
||||
<translation>지난 7일</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>This month</source>
|
||||
<translation type="unfinished">이달내</translation>
|
||||
<translation>이 달</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Older than 6 Months</source>
|
||||
<translation type="unfinished">6개월 이전</translation>
|
||||
<translation>6개월 이전</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Never</source>
|
||||
|
@ -2726,23 +2726,23 @@ It will be installed when qTox restarts.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>File</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>파일</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Edit Profile</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>프로필 편집</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Change Status</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>상태 바꾸기</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Log out</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>로그아웃</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Edit</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>편집</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Logout</source>
|
||||
|
@ -2772,7 +2772,7 @@ It will be installed when qTox restarts.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Previous Conversation</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>이전의 대화</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Executable file</source>
|
||||
|
@ -2803,7 +2803,7 @@ It will be installed when qTox restarts.</source>
|
|||
<message>
|
||||
<source><Empty></source>
|
||||
<comment>Placeholder when someone's name in a group chat is empty</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>비었습니다</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Message failed to send</source>
|
||||
|
@ -2874,17 +2874,17 @@ It will be installed when qTox restarts.</source>
|
|||
<message>
|
||||
<source>Add friend</source>
|
||||
<comment>title of the window</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>친구 추가</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Group invites</source>
|
||||
<comment>title of the window</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>그룹 초대</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>File transfers</source>
|
||||
<comment>title of the window</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>파일 이동</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Settings</source>
|
||||
|
@ -2894,7 +2894,7 @@ It will be installed when qTox restarts.</source>
|
|||
<message>
|
||||
<source>My profile</source>
|
||||
<comment>title of the window</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>내 프로필</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
|
94
translations/sv.ts
vendored
94
translations/sv.ts
vendored
|
@ -113,7 +113,7 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>Threshold</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tröskel</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -169,7 +169,7 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
<message>
|
||||
<source>bug-tracker</source>
|
||||
<comment>Replaces `%1` in the `A list of all knownâ¦`</comment>
|
||||
<translation type="unfinished">felbevakare</translation>
|
||||
<translation>felbevakare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Writing Useful Bug Reports</source>
|
||||
|
@ -179,7 +179,7 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
<message>
|
||||
<source>contributors</source>
|
||||
<comment>Replaces `%1` in `See a full list ofâ¦`</comment>
|
||||
<translation type="unfinished">bidragare</translation>
|
||||
<translation>bidragsgivare</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -190,11 +190,11 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>username</source>
|
||||
<translation type="unfinished">användarnamn</translation>
|
||||
<translation>användarnamn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>status message</source>
|
||||
<translation type="unfinished">statusmeddelande</translation>
|
||||
<translation>statusmeddelande</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Public key:</source>
|
||||
|
@ -214,7 +214,7 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>Auto accept files</source>
|
||||
<translation type="unfinished">Acceptera automatiskt filer</translation>
|
||||
<translation>Acceptera filer automatiskt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Default directory to save files:</source>
|
||||
|
@ -222,23 +222,23 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>Auto accept for this contact is disabled</source>
|
||||
<translation type="unfinished">Acceptera automatiskt för den här kontakten är avaktiverad</translation>
|
||||
<translation>Acceptera automatiskt för den här kontakten är inaktiverat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Auto accept call:</source>
|
||||
<translation type="unfinished">Acceptera automatiskt samtal:</translation>
|
||||
<translation>Acceptera samtal automatiskt:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Manual</source>
|
||||
<translation type="unfinished">Handbok</translation>
|
||||
<translation>Handbok</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio</source>
|
||||
<translation type="unfinished">Ljud</translation>
|
||||
<translation>Ljud</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Audio + Video</source>
|
||||
<translation type="unfinished">Ljud + Video</translation>
|
||||
<translation>Ljud + video</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Automatically accept group chat invitations from this contact if set.</source>
|
||||
|
@ -246,15 +246,15 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>Auto accept group invites</source>
|
||||
<translation type="unfinished">Acceptera automatiskt gruppinbjudningar</translation>
|
||||
<translation>Acceptera gruppinbjudningar automatiskt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Remove history (operation can not be undone!)</source>
|
||||
<translation type="unfinished">Ta bort historia (operation kan inte ångras!)</translation>
|
||||
<translation>Ta bort historik (operation kan inte ångras!)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Notes</source>
|
||||
<translation type="unfinished">Anteckningar</translation>
|
||||
<translation>Anteckningar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Input field for notes about the contact</source>
|
||||
|
@ -266,11 +266,11 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>History removed</source>
|
||||
<translation type="unfinished">Historik raderad</translation>
|
||||
<translation>Historik borttagen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Chat history with %1 removed!</source>
|
||||
<translation type="unfinished">Chatthistorik med %1 raderad!</translation>
|
||||
<translation>Chatthistorik med %1 borttagen!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Choose an auto accept directory</source>
|
||||
|
@ -359,7 +359,7 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
<message>
|
||||
<source>You can't add yourself as a friend!</source>
|
||||
<extracomment>When trying to add your own Tox ID as friend</extracomment>
|
||||
<translation type="unfinished">Du kan inte lägga till dig själv som vän!</translation>
|
||||
<translation>Du kan inte lägga till dig själv som vän!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open contact list</source>
|
||||
|
@ -385,17 +385,17 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
<message>
|
||||
<source>Tox ID</source>
|
||||
<extracomment>Tox ID of the person you're sending a friend request to</extracomment>
|
||||
<translation type="unfinished">Tox-ID</translation>
|
||||
<translation>Tox-ID</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>either 76 hexadecimal characters or name@example.com</source>
|
||||
<extracomment>Tox ID format description</extracomment>
|
||||
<translation type="unfinished">antingen 76 hexadecimala tecken eller name@example.com</translation>
|
||||
<translation>antingen 76 hexadecimala tecken eller namn@exempel.se</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Message</source>
|
||||
<extracomment>The message you send in friend requests</extracomment>
|
||||
<translation type="unfinished">Meddelande</translation>
|
||||
<translation>Meddelande</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
|
@ -418,11 +418,9 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
<message numerus="yes">
|
||||
<source>Ready to import %n contact(s), click send to confirm</source>
|
||||
<extracomment>Shows the number of contacts we're about to import from a file (at least one)</extracomment>
|
||||
<translation type="unfinished">
|
||||
<numerusform></numerusform>
|
||||
<numerusform></numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<translation><numerusform>Klar för att importera %n kontakt(er), klicka på skicka för att bekräfta</numerusform>
|
||||
<numerusform>Klar för att importera %n kontakter, klicka på skicka för att bekräfta</numerusform>
|
||||
</translation></message>
|
||||
<message>
|
||||
<source>Import contacts</source>
|
||||
<translation>Importera kontakter</translation>
|
||||
|
@ -680,15 +678,15 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>End audio call</source>
|
||||
<translation type="unfinished">Avsluta ljudsamtal</translation>
|
||||
<translation>Avsluta ljudsamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel audio call</source>
|
||||
<translation type="unfinished">Avbryt ljudsamtal</translation>
|
||||
<translation>Avbryt ljudsamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Accept audio call</source>
|
||||
<translation type="unfinished">Acceptera ljudsamtal</translation>
|
||||
<translation>Acceptera ljudsamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Can't start video call</source>
|
||||
|
@ -700,23 +698,23 @@ vilket kan leda till problem med videosamtal.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>End video call</source>
|
||||
<translation type="unfinished">Avsluta videosamtal</translation>
|
||||
<translation>Avsluta videosamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Cancel video call</source>
|
||||
<translation type="unfinished">Avbryt videosamtal</translation>
|
||||
<translation>Avbryt videosamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Accept video call</source>
|
||||
<translation type="unfinished">Acceptera videosamtal</translation>
|
||||
<translation>Acceptera videosamtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Sound can be disabled only during a call</source>
|
||||
<translation type="unfinished">Ljud kan endast avaktiveras under ett samtal</translation>
|
||||
<translation>Ljud kan endast inaktiveras under ett samtal</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unmute call</source>
|
||||
<translation type="unfinished">Slå på samtal</translation>
|
||||
<translation>Slå på mikrofon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Mute call</source>
|
||||
|
@ -1964,7 +1962,7 @@ Om du blir spammad med vänförfrågningar, ändra NoSpam.</translation>
|
|||
</message>
|
||||
<message>
|
||||
<source>Filter group message by group member's public key. Put public key here, one per line.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Filtrera gruppmeddelande genom gruppmedlems allmänna nyckel. Ange den offentliga nyckeln här, en per rad.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -2141,39 +2139,39 @@ Detta ID inkluderar NoSpam-koden (i blått) och checksum (i grått).</translatio
|
|||
</message>
|
||||
<message>
|
||||
<source>Empty path is unavaliable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tom sökväg är inte tillgänglig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to rename</source>
|
||||
<translation type="unfinished">Det gick inte att byta namn</translation>
|
||||
<translation>Det gick inte att byta namn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Profile already exists</source>
|
||||
<translation type="unfinished">Profil finns redan</translation>
|
||||
<translation>Profilen finns redan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A profile named "%1" already exists.</source>
|
||||
<translation type="unfinished">En profil med namnet "%1" finns redan.</translation>
|
||||
<translation>En profil med namnet "%1" finns redan.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tomt namn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty name is unavaliable</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tomt namn är inte tillgängligt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Empty path</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Tom sökväg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't change password on the database, it might be corrupted or use the old password.</source>
|
||||
<translation type="unfinished">Kunde inte byta lösenord på databasen, den kan vara trasig eller använda det gamla lösenordet.</translation>
|
||||
<translation>Det gick inte att byta lösenord på databasen, den kan vara trasig eller använda det gamla lösenordet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export profile</source>
|
||||
<translation type="unfinished">Exportera profil</translation>
|
||||
<translation>Exportera profil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tox save file (*.tox)</source>
|
||||
|
@ -2183,17 +2181,17 @@ Detta ID inkluderar NoSpam-koden (i blått) och checksum (i grått).</translatio
|
|||
<message>
|
||||
<source>The following files could not be deleted:</source>
|
||||
<extracomment>deletion failed text part 1</extracomment>
|
||||
<translation type="unfinished">Följande filer kan inte tas bort:</translation>
|
||||
<translation>Följande filer kunde inte tas bort:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Please manually remove them.</source>
|
||||
<extracomment>deletion failed text part 2</extracomment>
|
||||
<translation type="unfinished">Vänligen ta bort dem manuellt.</translation>
|
||||
<translation>Ta bort dem manuellt.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Are you sure you want to delete your password?</source>
|
||||
<extracomment>deletion confirmation text</extracomment>
|
||||
<translation type="unfinished">Är du säker på att du vill ta bort ditt lösenord?</translation>
|
||||
<translation>Är du säker på att du vill ta bort ditt lösenord?</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -2707,11 +2705,11 @@ Den kommer att installeras när qTox startas om.</translation>
|
|||
<message>
|
||||
<source>If enabled every contact without an avatar set will have a generated avatar based on their Tox ID instead of a default picture. Requires restart to apply.</source>
|
||||
<comment>toolTip for show identicons</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Om den är aktiverad kommer varje kontakt utan en avatar att ha en genererad avatar baserat på deras Tox-ID istället för en standardbild. Kräver omstart att tillämpa.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Use identicons instead of empty avatars</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Använd identicons istället för tomma avatarer</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
2
translations/ta.ts
vendored
2
translations/ta.ts
vendored
|
@ -89,7 +89,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Audio quality</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>ஒலித்தரம்</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Transmitted audio quality. Lower this setting if your bandwidth is not high enough or if you want to lower the internet usage.</source>
|
||||
|
|
70
translations/uk.ts
vendored
70
translations/uk.ts
vendored
|
@ -93,7 +93,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Transmitted audio quality. Lower this setting if your bandwidth is not high enough or if you want to lower the internet usage.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Якість передаваємого звуку. Зменшіть цей параметр якщо пропускна здатність з'єднання недостатня або ви хочете зменшити використання Інтернет трафіку.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>High (64 kbps)</source>
|
||||
|
@ -137,7 +137,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>You are using qTox version %1.</source>
|
||||
<translation type="unfinished">Ви використовуєте qTox версії %1.</translation>
|
||||
<translation>Ви використовуєте qTox версії %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Commit hash: %1</source>
|
||||
|
@ -145,11 +145,11 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>toxcore version: %1</source>
|
||||
<translation type="unfinished">Версія toxcore: %1</translation>
|
||||
<translation>Версія toxcore: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Qt version: %1</source>
|
||||
<translation type="unfinished">Версія Qt: %1</translation>
|
||||
<translation>Версія Qt: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>A list of all known issues may be found at our %1 at Github. If you discover a bug or security vulnerability within qTox, please report it according to the guidelines in our %2 wiki article.</source>
|
||||
|
@ -169,7 +169,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>bug-tracker</source>
|
||||
<comment>Replaces `%1` in the `A list of all knownâ¦`</comment>
|
||||
<translation type="unfinished">баг-трекері</translation>
|
||||
<translation>баг-трекері</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Writing Useful Bug Reports</source>
|
||||
|
@ -367,40 +367,40 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Couldn't open file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Помилка відкриття файлу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Couldn't open the contact file</source>
|
||||
<extracomment>Error message when trying to open a contact list file to import</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Помилка відкриття файлу контактів</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Invalid file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Неправильний файл</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>We couldn't find any contacts to import in this file!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Контактів для імпорту не знайдено!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Tox ID</source>
|
||||
<extracomment>Tox ID of the person you're sending a friend request to</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ідентифікатор Tox</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>either 76 hexadecimal characters or name@example.com</source>
|
||||
<extracomment>Tox ID format description</extracomment>
|
||||
<translation type="unfinished">76 шістнадцяткових цифр або name@example.com</translation>
|
||||
<translation>76 шістнадцяткових символів або name@example.com</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Message</source>
|
||||
<extracomment>The message you send in friend requests</extracomment>
|
||||
<translation type="unfinished">Повідомлення</translation>
|
||||
<translation>Повідомлення</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Open</source>
|
||||
<extracomment>Button to choose a file with a list of contacts to import</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Відкрити</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Send friend requests</source>
|
||||
|
@ -413,7 +413,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Import a list of contacts, one Tox ID per line</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Імпортувати список контактів, один Ідентифікатор Tox на рядок</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>Ready to import %n contact(s), click send to confirm</source>
|
||||
|
@ -426,14 +426,14 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Import contacts</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Імпортувати контакти</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>AdvancedForm</name>
|
||||
<message>
|
||||
<source>Advanced</source>
|
||||
<translation>Додатково</translation>
|
||||
<translation>Більше</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Unless you %1 know what you are doing, please do %2 change anything here. Changes made here may lead to problems with qTox, and even to loss of your data, e.g. history.</source>
|
||||
|
@ -441,7 +441,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>really</source>
|
||||
<translation>впевнені</translation>
|
||||
<translation>дійсно</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>not</source>
|
||||
|
@ -461,11 +461,11 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Yes</source>
|
||||
<translation type="unfinished">Так</translation>
|
||||
<translation>Так</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>No</source>
|
||||
<translation type="unfinished">Ні</translation>
|
||||
<translation>Ні</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Call active</source>
|
||||
|
@ -483,7 +483,7 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Logs (*.log)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Логи (*.log)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -512,7 +512,7 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Enable IPv6 (recommended)</source>
|
||||
<extracomment>Text on a checkbox to enable IPv6</extracomment>
|
||||
<translation type="unfinished">Дозволити IPv6 (рекомендовано)</translation>
|
||||
<translation>Увімкнути IPv6 (рекомендовано)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Disabling this allows, e.g., toxing over Tor. It adds load to the Tox network however, so uncheck only when necessary.</source>
|
||||
|
@ -522,21 +522,21 @@ which may lead to problems with video calls.</source>
|
|||
<message>
|
||||
<source>Enable UDP (recommended)</source>
|
||||
<extracomment>Text on checkbox to disable UDP</extracomment>
|
||||
<translation type="unfinished">Дозволити UDP (рекомендовано)</translation>
|
||||
<translation>Увімкнути UDP (рекомендовано)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Proxy type:</source>
|
||||
<translation type="unfinished">Тип проксі:</translation>
|
||||
<translation>Тип проксі:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Address:</source>
|
||||
<extracomment>Text on proxy addr label</extracomment>
|
||||
<translation type="unfinished">Адреса проксі:</translation>
|
||||
<translation>Адреса:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Port:</source>
|
||||
<extracomment>Text on proxy port label</extracomment>
|
||||
<translation type="unfinished">Порт:</translation>
|
||||
<translation>Порт:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>None</source>
|
||||
|
@ -544,28 +544,28 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>SOCKS5</source>
|
||||
<translation type="unfinished">SOCKS5</translation>
|
||||
<translation>SOCKS5</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>HTTP</source>
|
||||
<translation type="unfinished">HTTP</translation>
|
||||
<translation>HTTP</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Reconnect</source>
|
||||
<comment>reconnect button</comment>
|
||||
<translation type="unfinished">Повторно під'єднатись</translation>
|
||||
<translation>Перепідключитись</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Debug</source>
|
||||
<translation type="unfinished">Налагодження</translation>
|
||||
<translation>Відладка</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Export Debug Log</source>
|
||||
<translation type="unfinished">Вивантажити логи налагодження</translation>
|
||||
<translation>Експортувати логи відладки</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Copy Debug Log</source>
|
||||
<translation type="unfinished">Скопіювати логи налагодження</translation>
|
||||
<translation>Скопіювати логи відладки</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -600,20 +600,20 @@ which may lead to problems with video calls.</source>
|
|||
</message>
|
||||
<message>
|
||||
<source>Failed to send file "%1"</source>
|
||||
<translation>Не вдалось відправити файл «%1»</translation>
|
||||
<translation>Не вдалось відправити файл "%1"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Failed to open temporary file</source>
|
||||
<comment>Temporary file for screenshot</comment>
|
||||
<translation>Помилка під час відкриття тимчасового файлу</translation>
|
||||
<translation>Помилка відкриття тимчасового файлу</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>qTox wasn't able to save the screenshot</source>
|
||||
<translation>qTox не може зберегти снімок екрану</translation>
|
||||
<translation>qTox не зміг зберегти скриншот</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Call with %1 ended. %2</source>
|
||||
<translation>Виклик із %1 завершено. %2</translation>
|
||||
<translation>Дзвінок з %1 завершено. %2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<source>Call duration: </source>
|
||||
|
|
|
@ -1,39 +1,42 @@
|
|||
QLineEdit {
|
||||
QLineEdit
|
||||
{
|
||||
color: @black;
|
||||
background: white;
|
||||
border: 0px;
|
||||
}
|
||||
|
||||
#nameLabel {
|
||||
#nameLabel
|
||||
{
|
||||
color: @black;
|
||||
font: @mediumBold;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#statusLabel {
|
||||
#statusLabel
|
||||
{
|
||||
color: @mediumGrey;
|
||||
font: @medium;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
#peersLabel {
|
||||
#peersLabel
|
||||
{
|
||||
color: @mediumGrey;
|
||||
font: @medium;
|
||||
font-size:12px;
|
||||
}
|
||||
|
||||
QLabel[peerType="our"] {
|
||||
QLabel[peerType="our"]
|
||||
{
|
||||
color: green;
|
||||
}
|
||||
|
||||
QLabel[peerType="muted"] {
|
||||
QLabel[peerType="muted"]
|
||||
{
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
QLabel[playingAudio="true"] {
|
||||
QLabel[playingAudio="true"]
|
||||
{
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
QMenu:disabled {
|
||||
color: gray;
|
||||
}
|
||||
|
|
|
@ -1,64 +1,80 @@
|
|||
QScrollArea {
|
||||
QScrollArea
|
||||
{
|
||||
background: @themeMedium;
|
||||
}
|
||||
|
||||
QScrollBar:vertical {
|
||||
QScrollBar:vertical
|
||||
{
|
||||
background: @themeMedium;
|
||||
width: 16px;
|
||||
padding: 0px 3px 0px 3px;
|
||||
}
|
||||
|
||||
QScrollBar:handle:vertical {
|
||||
QScrollBar:handle:vertical
|
||||
{
|
||||
background: @themeDark;
|
||||
min-height: 20px;
|
||||
border-radius: 5px;
|
||||
margin: 3px 0px 3px 0px;
|
||||
}
|
||||
|
||||
QScrollBar:handle:vertical:hover {
|
||||
QScrollBar:handle:vertical:hover
|
||||
{
|
||||
background: @themeMediumDark;
|
||||
}
|
||||
|
||||
QScrollBar:handle:vertical:pressed {
|
||||
QScrollBar:handle:vertical:pressed
|
||||
{
|
||||
background: @themeDark;
|
||||
}
|
||||
|
||||
QScrollBar:add-line:vertical {height: 0px;subcontrol-position: bottom;subcontrol-origin: margin;}
|
||||
QScrollBar:add-line:vertical
|
||||
{
|
||||
height: 0px;
|
||||
subcontrol-position: bottom;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
|
||||
QScrollBar:sub-line:vertical {height: 0px;subcontrol-position: top;subcontrol-origin: margin;}
|
||||
QScrollBar:sub-line:vertical
|
||||
{
|
||||
height: 0px;
|
||||
subcontrol-position: top;
|
||||
subcontrol-origin: margin;
|
||||
}
|
||||
|
||||
QScrollBar:add-page:vertical, QScrollBar::sub-page:vertical {
|
||||
QScrollBar:add-page:vertical, QScrollBar::sub-page:vertical
|
||||
{
|
||||
background: none;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer > QFrame#line
|
||||
{
|
||||
color: white;
|
||||
color: white;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer
|
||||
{
|
||||
background-color: @themeMedium;
|
||||
background-color: @themeMedium;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer:hover
|
||||
{
|
||||
background-color: @themeLight;
|
||||
background-color: @themeLight;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer QLineEdit
|
||||
{
|
||||
background-color: @themeLight;
|
||||
background-color: @themeLight;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer > QLabel#status
|
||||
{
|
||||
font: @small;
|
||||
color: @lightGrey;
|
||||
font: @small;
|
||||
color: @lightGrey;
|
||||
}
|
||||
|
||||
QWidget#circleWidgetContainer > QLabel#name
|
||||
{
|
||||
font: @big;
|
||||
color: @white;
|
||||
font: @big;
|
||||
color: @white;
|
||||
}
|
||||
|
|
|
@ -1,58 +1,68 @@
|
|||
#LoginScreen {
|
||||
background-color: #1c1c1c;
|
||||
#LoginScreen
|
||||
{
|
||||
background-color: #1c1c1c;
|
||||
}
|
||||
|
||||
#line {
|
||||
color: #757575;
|
||||
#line
|
||||
{
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
#stackedWidget {
|
||||
background-color: #d6d2Cf;
|
||||
#stackedWidget
|
||||
{
|
||||
background-color: #d6d2Cf;
|
||||
}
|
||||
|
||||
#labelNewProfile,
|
||||
#labelLoadProfile {
|
||||
border-style: solid;
|
||||
border-width: 15px 0 15px 15px;
|
||||
border-color: #d6d2cf #d6d2cf #d6d2cf #1c1c1c;
|
||||
#labelLoadProfile
|
||||
{
|
||||
border-style: solid;
|
||||
border-width: 15px 0 15px 15px;
|
||||
border-color: #d6d2cf #d6d2cf #d6d2cf #1c1c1c;
|
||||
}
|
||||
#labelNewProfile {
|
||||
margin-top:125px;
|
||||
margin-bottom:45px;
|
||||
#labelNewProfile
|
||||
{
|
||||
margin-top:125px;
|
||||
margin-bottom:45px;
|
||||
}
|
||||
#labelLoadProfile {
|
||||
margin-top:165px;
|
||||
margin-bottom:5px;
|
||||
#labelLoadProfile
|
||||
{
|
||||
margin-top:165px;
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
LoginScreen > QPushButton,
|
||||
QStackedWidget QPushButton
|
||||
{
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#loginButton,
|
||||
#importButton,
|
||||
#createAccountButton {
|
||||
border-radius:5px;
|
||||
padding:5px;
|
||||
background-color:#42a33a;
|
||||
#createAccountButton
|
||||
{
|
||||
border-radius:5px;
|
||||
padding:5px;
|
||||
background-color:#42a33a;
|
||||
}
|
||||
|
||||
#loginButton:hover,
|
||||
#importButton:hover,
|
||||
#createAccountButton:hover {
|
||||
background: #0c530d;
|
||||
#createAccountButton:hover
|
||||
{
|
||||
background: #0c530d;
|
||||
}
|
||||
|
||||
QLabel, QCheckBox, QProgressBar {
|
||||
color: black;
|
||||
QLabel, QCheckBox, QProgressBar
|
||||
{
|
||||
color: black;
|
||||
}
|
||||
|
||||
QCheckBox:disabled {
|
||||
color: gray;
|
||||
QCheckBox:disabled
|
||||
{
|
||||
color: gray;
|
||||
}
|
||||
|
|
|
@ -1,27 +1,33 @@
|
|||
QTextEdit {
|
||||
border-color: @lightGrey;
|
||||
border-style: solid;
|
||||
border-width: 1px 0 1px 1px;
|
||||
QTextEdit
|
||||
{
|
||||
border-color: @lightGrey;
|
||||
border-style: solid;
|
||||
border-width: 1px 0 1px 1px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
QTextEdit:hover {
|
||||
border-color: #d7d4d1;
|
||||
QTextEdit:hover
|
||||
{
|
||||
border-color: #d7d4d1;
|
||||
}
|
||||
|
||||
QTextEdit:pressed {
|
||||
border-color: #4ea6ea;
|
||||
QTextEdit:pressed
|
||||
{
|
||||
border-color: #4ea6ea;
|
||||
}
|
||||
|
||||
QTextEdit#group {
|
||||
/*border-radius: 0 6px 6px 0; would use to round corners in groupchat, but Qt's implementation seems to be bugged*/
|
||||
border: 1px solid #c4c1bd;
|
||||
QTextEdit#group
|
||||
{
|
||||
/*border-radius: 0 6px 6px 0; would use to round corners in groupchat, but Qt's implementation seems to be bugged*/
|
||||
border: 1px solid #c4c1bd;
|
||||
}
|
||||
|
||||
QTextEdit#group:hover {
|
||||
border-color: #d7d4d1;
|
||||
QTextEdit#group:hover
|
||||
{
|
||||
border-color: #d7d4d1;
|
||||
}
|
||||
|
||||
QTextEdit#group:pressed {
|
||||
border-color: #4ea6ea;
|
||||
QTextEdit#group:pressed
|
||||
{
|
||||
border-color: #4ea6ea;
|
||||
}
|
||||
|
|
|
@ -10,21 +10,22 @@ QPushButton
|
|||
|
||||
QPushButton:default
|
||||
{
|
||||
background-color: @themeMediumDark;
|
||||
background-color: @themeMediumDark;
|
||||
}
|
||||
|
||||
/*Bugged in Qt, but it's probably better to leave enabled so that users can tell it's clickable*/
|
||||
QPushButton:hover
|
||||
{
|
||||
background-color: @themeMedium;
|
||||
background-color: @themeMedium;
|
||||
}
|
||||
|
||||
QPushButton:pressed
|
||||
{
|
||||
background-color: @themeMediumDark;
|
||||
background-color: @themeMediumDark;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
QPushButton:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
@ -32,9 +33,9 @@ QPushButton::menu-indicator {image: none;}
|
|||
|
||||
QPushButton::menu-indicator:pressed, QPushButton::menu-indicator:open
|
||||
{
|
||||
image: url(":ui/statusButton/menu_indicator.svg");
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: bottom center;
|
||||
position: relative;
|
||||
image: url(":ui/statusButton/menu_indicator.svg");
|
||||
subcontrol-origin: padding;
|
||||
subcontrol-position: bottom center;
|
||||
position: relative;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#selfAvatar:hover {
|
||||
#selfAvatar:hover
|
||||
{
|
||||
border-radius: 6px;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,8 @@ QLineEdit
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QToolButton {
|
||||
QToolButton
|
||||
{
|
||||
background: none;
|
||||
background-color: @themeMedium;
|
||||
color: white;
|
||||
|
@ -15,17 +16,20 @@ QToolButton {
|
|||
border-radius: 4px;
|
||||
}
|
||||
|
||||
QToolButton:pressed {
|
||||
QToolButton:pressed
|
||||
{
|
||||
background-color: @themeMediumDark;
|
||||
border-radius: 4px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
QToolButton::menu-indicator {
|
||||
QToolButton::menu-indicator
|
||||
{
|
||||
image: none
|
||||
}
|
||||
|
||||
QPushButton#green {
|
||||
QPushButton#green
|
||||
{
|
||||
background: none;
|
||||
background-color: #6bc260;
|
||||
color: white;
|
||||
|
@ -48,12 +52,14 @@ QPushButton#green:pressed
|
|||
/**
|
||||
Uncomment this after https://github.com/qTox/qTox/pull/1640
|
||||
is merged!
|
||||
QComboBox:down-arrow {
|
||||
QComboBox:down-arrow
|
||||
{
|
||||
image: url(ui/css/down_arrow.png);
|
||||
}
|
||||
**/
|
||||
|
||||
QListView {
|
||||
QListView
|
||||
{
|
||||
background-color: @themeLight;
|
||||
border-style: none;
|
||||
border-radius: 4px;
|
||||
|
@ -69,13 +75,15 @@ QListView {
|
|||
background-color: @themeDark;
|
||||
}
|
||||
|
||||
#statusPanel > #statusHead > #nameLabel {
|
||||
#statusPanel > #statusHead > #nameLabel
|
||||
{
|
||||
background-color: @themeDark;
|
||||
font: @extraBig;
|
||||
color: @white;
|
||||
}
|
||||
|
||||
#statusPanel > #statusHead > #statusLabel {
|
||||
#statusPanel > #statusHead > #statusLabel
|
||||
{
|
||||
background-color: @themeDark;
|
||||
font: @medium;
|
||||
color: @lightGrey;
|
||||
|
@ -102,7 +110,8 @@ QListView {
|
|||
background-color: @themeMedium;
|
||||
}
|
||||
|
||||
#statusPanel > #statusHead > #statusButton:focus {
|
||||
#statusPanel > #statusHead > #statusButton:focus
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
@ -116,4 +125,3 @@ QListView {
|
|||
position: relative;
|
||||
bottom: 2px;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,8 @@ QPushButton#minimizeButton
|
|||
{
|
||||
border: 0px solid transparent;
|
||||
background-color: transparent;
|
||||
image: url(":ui/window/minimizeButton.png");}
|
||||
image: url(":ui/window/minimizeButton.png");
|
||||
}
|
||||
QPushButton#minimizeButton:hover {image: url(":ui/window/minimizeButtonHover.png");}
|
||||
QPushButton#minimizeButton:pressed {image: url(":ui/window/minimizeButtonPressed.png");}
|
||||
QPushButton#minimizeButton:focus {outline: none;}
|
||||
|
@ -44,7 +45,8 @@ QPushButton#maximizeButton
|
|||
{
|
||||
border: 0px solid transparent;
|
||||
background-color: transparent;
|
||||
image: url(":ui/window/maximizeButton.png");}
|
||||
image: url(":ui/window/maximizeButton.png");
|
||||
}
|
||||
QPushButton#maximizeButton:hover {image: url(":ui/window/maximizeButtonHover.png");}
|
||||
QPushButton#maximizeButton:pressed {image: url(":ui/window/maximizeButtonPressed.png");}
|
||||
QPushButton#maximizeButton:focus {outline: none;}
|
||||
|
@ -53,7 +55,8 @@ QPushButton#closeButton
|
|||
{
|
||||
border: 0px solid transparent;
|
||||
background-color: transparent;
|
||||
image: url(":ui/window/closeButton.png");}
|
||||
image: url(":ui/window/closeButton.png");
|
||||
}
|
||||
QPushButton#closeButton:hover {image: url(":ui/window/closeButtonHover.png");}
|
||||
QPushButton#closeButton:pressed {image: url(":ui/window/closeButtonPressed.png");}
|
||||
QPushButton#closeButton:focus {outline: none;}
|
||||
|
@ -62,7 +65,8 @@ QPushButton#restoreButton
|
|||
{
|
||||
border: 0px solid transparent;
|
||||
background-color: transparent;
|
||||
image: url(":ui/window/restoreButton.png");}
|
||||
image: url(":ui/window/restoreButton.png");
|
||||
}
|
||||
QPushButton#restoreButton:hover {image: url(":ui/window/restoreButtonHover.png");}
|
||||
QPushButton#restoreButton:pressed {image: url(":ui/window/restoreButtonPressed.png");}
|
||||
QPushButton#restoreButton:focus {outline: none;}
|
||||
|
|
|
@ -26,10 +26,6 @@
|
|||
# - Doesn't build qTox updater, because it wasn't ported to cmake yet and
|
||||
# because it requires static Qt, which means we'd need to build Qt twice, and
|
||||
# building Qt takes really long time.
|
||||
#
|
||||
# - FFmpeg 3.3 doesn't cross-compile correctly, qTox build fails when linking
|
||||
# against the 3.3 FFmpeg. They have removed `--enable-memalign-hack` switch,
|
||||
# which might be what causes this. Further research needed.
|
||||
|
||||
|
||||
set -euo pipefail
|
||||
|
@ -217,15 +213,16 @@ OPENSSL_PREFIX_DIR="$DEP_DIR/libopenssl"
|
|||
OPENSSL_VERSION=1.0.2o
|
||||
# hash from https://www.openssl.org/source/
|
||||
OPENSSL_HASH="ec3f5c9714ba0fd45cb4e087301eb1336c317e0d20b575a125050470e8089e4d"
|
||||
OPENSSL_FILENAME="openssl-$OPENSSL_VERSION.tar.gz"
|
||||
if [ ! -f "$OPENSSL_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$OPENSSL_PREFIX_DIR"
|
||||
mkdir -p "$OPENSSL_PREFIX_DIR"
|
||||
|
||||
wget https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz
|
||||
check_sha256 "$OPENSSL_HASH" "openssl-$OPENSSL_VERSION.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf openssl*.tar.gz
|
||||
rm openssl*.tar.gz
|
||||
wget "https://www.openssl.org/source/$OPENSSL_FILENAME"
|
||||
check_sha256 "$OPENSSL_HASH" "$OPENSSL_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$OPENSSL_FILENAME"
|
||||
rm $OPENSSL_FILENAME
|
||||
cd openssl*
|
||||
|
||||
CONFIGURE_OPTIONS="--prefix=$OPENSSL_PREFIX_DIR shared"
|
||||
|
@ -256,19 +253,20 @@ fi
|
|||
QT_PREFIX_DIR="$DEP_DIR/libqt5"
|
||||
QT_MAJOR=5
|
||||
QT_MINOR=9
|
||||
QT_PATCH=5
|
||||
QT_PATCH=6
|
||||
QT_VERSION=$QT_MAJOR.$QT_MINOR.$QT_PATCH
|
||||
# hash from https://download.qt.io/archive/qt/5.9/5.9.5/single/qt-everywhere-opensource-src-5.9.5.tar.xz.mirrorlist
|
||||
QT_HASH="a75b87f46240a374fde93fb60038d63e3b570457785268c766c639b5dc18ccf6"
|
||||
# hash from https://download.qt.io/archive/qt/5.9/5.9.6/single/qt-everywhere-opensource-src-5.9.6.tar.xz.mirrorlist
|
||||
QT_HASH="dacc995ae3a7cdad80eb9fdf6470299a8fac41f468a9bb941670ece523b62af4"
|
||||
QT_FILENAME="qt-everywhere-opensource-src-$QT_VERSION.tar.xz"
|
||||
if [ ! -f "$QT_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$QT_PREFIX_DIR"
|
||||
mkdir -p "$QT_PREFIX_DIR"
|
||||
|
||||
wget https://download.qt.io/official_releases/qt/$QT_MAJOR.$QT_MINOR/$QT_VERSION/single/qt-everywhere-opensource-src-$QT_VERSION.tar.xz
|
||||
check_sha256 "$QT_HASH" "qt-everywhere-opensource-src-$QT_VERSION.tar.xz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf qt*.tar.xz
|
||||
rm qt*.tar.xz
|
||||
wget "https://download.qt.io/official_releases/qt/$QT_MAJOR.$QT_MINOR/$QT_VERSION/single/$QT_FILENAME"
|
||||
check_sha256 "$QT_HASH" "$QT_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf $QT_FILENAME
|
||||
rm $QT_FILENAME
|
||||
cd qt*
|
||||
|
||||
export PKG_CONFIG_PATH="$OPENSSL_PREFIX_DIR/lib/pkgconfig"
|
||||
|
@ -374,15 +372,16 @@ set -u
|
|||
SQLCIPHER_PREFIX_DIR="$DEP_DIR/libsqlcipher"
|
||||
SQLCIPHER_VERSION=v3.4.2
|
||||
SQLCIPHER_HASH="69897a5167f34e8a84c7069f1b283aba88cdfa8ec183165c4a5da2c816cfaadb"
|
||||
SQLCIPHER_FILENAME="$SQLCIPHER_VERSION.tar.gz"
|
||||
if [ ! -f "$SQLCIPHER_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$SQLCIPHER_PREFIX_DIR"
|
||||
mkdir -p "$SQLCIPHER_PREFIX_DIR"
|
||||
|
||||
wget https://github.com/sqlcipher/sqlcipher/archive/$SQLCIPHER_VERSION.tar.gz -O sqlcipher.tar.gz
|
||||
check_sha256 "$SQLCIPHER_HASH" "sqlcipher.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf sqlcipher.tar.gz
|
||||
rm sqlcipher.tar.gz
|
||||
wget "https://github.com/sqlcipher/sqlcipher/archive/$SQLCIPHER_FILENAME"
|
||||
check_sha256 "$SQLCIPHER_HASH" "$SQLCIPHER_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$SQLCIPHER_FILENAME"
|
||||
rm $SQLCIPHER_FILENAME
|
||||
cd sqlcipher*
|
||||
|
||||
sed -i s/'LIBS="-lcrypto $LIBS"'/'LIBS="-lcrypto -lgdi32 $LIBS"'/g configure
|
||||
|
@ -397,8 +396,8 @@ then
|
|||
@@ -1074,7 +1074,7 @@
|
||||
$(TOP)/ext/fts5/fts5_varint.c \
|
||||
$(TOP)/ext/fts5/fts5_vocab.c \
|
||||
|
||||
-fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
|
||||
-fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon
|
||||
+fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon$(BEXE)
|
||||
cp $(TOP)/ext/fts5/fts5parse.y .
|
||||
rm -f fts5parse.h
|
||||
|
@ -431,17 +430,18 @@ fi
|
|||
# FFmpeg
|
||||
|
||||
FFMPEG_PREFIX_DIR="$DEP_DIR/libffmpeg"
|
||||
FFMPEG_VERSION=3.2.10
|
||||
FFMPEG_HASH="3c1626220c7b68ff6be7312559f77f3c65ff6809daf645d4470ac0189926bdbc"
|
||||
FFMPEG_VERSION=4.0.1
|
||||
FFMPEG_HASH="605f5c01c60db35d3b617a79cabb2c7032412be243554602eeed1b628125c0ee"
|
||||
FFMPEG_FILENAME="ffmpeg-$FFMPEG_VERSION.tar.xz"
|
||||
if [ ! -f "$FFMPEG_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$FFMPEG_PREFIX_DIR"
|
||||
mkdir -p "$FFMPEG_PREFIX_DIR"
|
||||
|
||||
wget https://www.ffmpeg.org/releases/ffmpeg-$FFMPEG_VERSION.tar.xz
|
||||
check_sha256 "$FFMPEG_HASH" "ffmpeg-$FFMPEG_VERSION.tar.xz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf ffmpeg*.tar.xz
|
||||
rm ffmpeg*.tar.xz
|
||||
wget "https://www.ffmpeg.org/releases/$FFMPEG_FILENAME"
|
||||
check_sha256 "$FFMPEG_HASH" "$FFMPEG_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf $FFMPEG_FILENAME
|
||||
rm $FFMPEG_FILENAME
|
||||
cd ffmpeg*
|
||||
|
||||
if [[ "$ARCH" == "x86_64"* ]]
|
||||
|
@ -453,6 +453,7 @@ then
|
|||
fi
|
||||
|
||||
./configure $CONFIGURE_OPTIONS \
|
||||
--enable-gpl \
|
||||
--prefix="$FFMPEG_PREFIX_DIR" \
|
||||
--target-os="mingw32" \
|
||||
--cross-prefix="$ARCH-w64-mingw32-" \
|
||||
|
@ -460,11 +461,12 @@ then
|
|||
--extra-cflags="-static -O2 -g0" \
|
||||
--extra-ldflags="-lm -static" \
|
||||
--pkg-config-flags="--static" \
|
||||
--disable-debug \
|
||||
--disable-shared \
|
||||
--disable-programs \
|
||||
--disable-protocols \
|
||||
--disable-doc \
|
||||
--disable-sdl \
|
||||
--disable-sdl2 \
|
||||
--disable-avfilter \
|
||||
--disable-avresample \
|
||||
--disable-filters \
|
||||
|
@ -492,14 +494,14 @@ then
|
|||
--disable-decoders \
|
||||
--disable-demuxers \
|
||||
--disable-parsers \
|
||||
--disable-bsfs \
|
||||
--enable-demuxer=h264 \
|
||||
--enable-demuxer=mjpeg \
|
||||
--enable-parser=h264 \
|
||||
--enable-parser=mjpeg \
|
||||
--enable-decoder=h264 \
|
||||
--enable-decoder=mjpeg \
|
||||
--enable-decoder=rawvideo \
|
||||
--enable-memalign-hack
|
||||
--enable-decoder=rawvideo
|
||||
make
|
||||
make install
|
||||
echo -n $FFMPEG_VERSION > $FFMPEG_PREFIX_DIR/done
|
||||
|
@ -702,17 +704,18 @@ fi
|
|||
# QREncode
|
||||
|
||||
QRENCODE_PREFIX_DIR="$DEP_DIR/libqrencode"
|
||||
QRENCODE_VERSION=4.0.0
|
||||
QRENCODE_HASH="c90035e16921117d4086a7fdee65aab85be32beb4a376f6b664b8a425d327d0b"
|
||||
QRENCODE_VERSION=4.0.2
|
||||
QRENCODE_HASH="c9cb278d3b28dcc36b8d09e8cad51c0eca754eb004cb0247d4703cb4472b58b4"
|
||||
QRENCODE_FILENAME="qrencode-$QRENCODE_VERSION.tar.bz2"
|
||||
if [ ! -f "$QRENCODE_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$QRENCODE_PREFIX_DIR"
|
||||
mkdir -p "$QRENCODE_PREFIX_DIR"
|
||||
|
||||
wget https://fukuchi.org/works/qrencode/qrencode-$QRENCODE_VERSION.tar.bz2
|
||||
check_sha256 "$QRENCODE_HASH" "qrencode-$QRENCODE_VERSION.tar.bz2"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf qrencode*.tar.bz2
|
||||
rm qrencode*.tar.bz2
|
||||
wget https://fukuchi.org/works/qrencode/$QRENCODE_FILENAME
|
||||
check_sha256 "$QRENCODE_HASH" "$QRENCODE_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$QRENCODE_FILENAME"
|
||||
rm $QRENCODE_FILENAME
|
||||
cd qrencode*
|
||||
|
||||
CFLAGS="-O2 -g0" ./configure --host="$ARCH-w64-mingw32" \
|
||||
|
@ -738,15 +741,16 @@ fi
|
|||
EXIF_PREFIX_DIR="$DEP_DIR/libexif"
|
||||
EXIF_VERSION=0.6.21
|
||||
EXIF_HASH="16cdaeb62eb3e6dfab2435f7d7bccd2f37438d21c5218ec4e58efa9157d4d41a"
|
||||
EXIF_FILENAME=libexif-$EXIF_VERSION.tar.bz2
|
||||
if [ ! -f "$EXIF_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$EXIF_PREFIX_DIR"
|
||||
mkdir -p "$EXIF_PREFIX_DIR"
|
||||
|
||||
wget https://sourceforge.net/projects/libexif/files/libexif/0.6.21/libexif-$EXIF_VERSION.tar.bz2
|
||||
check_sha256 "$EXIF_HASH" "libexif-$EXIF_VERSION.tar.bz2"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf libexif*.tar.bz2
|
||||
rm libexif*.tar.bz2
|
||||
wget https://sourceforge.net/projects/libexif/files/libexif/$EXIF_VERSION/$EXIF_FILENAME
|
||||
check_sha256 "$EXIF_HASH" "$EXIF_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf $EXIF_FILENAME
|
||||
rm $EXIF_FILENAME
|
||||
cd libexif*
|
||||
|
||||
CFLAGS="-O2 -g0" ./configure --host="$ARCH-w64-mingw32" \
|
||||
|
@ -771,15 +775,16 @@ fi
|
|||
OPUS_PREFIX_DIR="$DEP_DIR/libopus"
|
||||
OPUS_VERSION=1.2.1
|
||||
OPUS_HASH="cfafd339ccd9c5ef8d6ab15d7e1a412c054bf4cb4ecbbbcc78c12ef2def70732"
|
||||
OPUS_FILENAME="opus-$OPUS_VERSION.tar.gz"
|
||||
if [ ! -f "$OPUS_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$OPUS_PREFIX_DIR"
|
||||
mkdir -p "$OPUS_PREFIX_DIR"
|
||||
|
||||
wget https://archive.mozilla.org/pub/opus/opus-$OPUS_VERSION.tar.gz
|
||||
check_sha256 "$OPUS_HASH" "opus-$OPUS_VERSION.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf opus*.tar.gz
|
||||
rm opus*.tar.gz
|
||||
wget "https://archive.mozilla.org/pub/opus/$OPUS_FILENAME"
|
||||
check_sha256 "$OPUS_HASH" "$OPUS_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$OPUS_FILENAME"
|
||||
rm $OPUS_FILENAME
|
||||
cd opus*
|
||||
|
||||
CFLAGS="-O2 -g0" ./configure --host="$ARCH-w64-mingw32" \
|
||||
|
@ -804,15 +809,16 @@ fi
|
|||
SODIUM_PREFIX_DIR="$DEP_DIR/libsodium"
|
||||
SODIUM_VERSION=1.0.16
|
||||
SODIUM_HASH="eeadc7e1e1bcef09680fb4837d448fbdf57224978f865ac1c16745868fbd0533"
|
||||
SODIUM_FILENAME="libsodium-$SODIUM_VERSION.tar.gz"
|
||||
if [ ! -f "$SODIUM_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$SODIUM_PREFIX_DIR"
|
||||
mkdir -p "$SODIUM_PREFIX_DIR"
|
||||
|
||||
wget https://download.libsodium.org/libsodium/releases/libsodium-$SODIUM_VERSION.tar.gz
|
||||
check_sha256 "$SODIUM_HASH" "libsodium-$SODIUM_VERSION.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf libsodium*.tar.gz
|
||||
rm libsodium*.tar.gz
|
||||
wget "https://download.libsodium.org/libsodium/releases/$SODIUM_FILENAME"
|
||||
check_sha256 "$SODIUM_HASH" "$SODIUM_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$SODIUM_FILENAME"
|
||||
rm "$SODIUM_FILENAME"
|
||||
cd libsodium*
|
||||
|
||||
./configure --host="$ARCH-w64-mingw32" \
|
||||
|
@ -836,15 +842,16 @@ fi
|
|||
VPX_PREFIX_DIR="$DEP_DIR/libvpx"
|
||||
VPX_VERSION=v1.7.0
|
||||
VPX_HASH="1fec931eb5c94279ad219a5b6e0202358e94a93a90cfb1603578c326abfc1238"
|
||||
VPX_FILENAME="libvpx-$VPX_VERSION.tar.bz2"
|
||||
if [ ! -f "$VPX_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$VPX_PREFIX_DIR"
|
||||
mkdir -p "$VPX_PREFIX_DIR"
|
||||
|
||||
wget https://github.com/webmproject/libvpx/archive/$VPX_VERSION.tar.gz -O libvpx-$VPX_VERSION.tar.gz
|
||||
check_sha256 "$VPX_HASH" "libvpx-$VPX_VERSION.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf libvpx-*.tar.gz
|
||||
rm libvpx*.tar.gz
|
||||
wget https://github.com/webmproject/libvpx/archive/$VPX_VERSION.tar.gz -O $VPX_FILENAME
|
||||
check_sha256 "$VPX_HASH" "$VPX_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$VPX_FILENAME"
|
||||
rm $VPX_FILENAME
|
||||
cd libvpx*
|
||||
|
||||
if [[ "$ARCH" == "x86_64" ]]
|
||||
|
@ -877,17 +884,18 @@ fi
|
|||
# Toxcore
|
||||
|
||||
TOXCORE_PREFIX_DIR="$DEP_DIR/libtoxcore"
|
||||
TOXCORE_VERSION=0.2.2
|
||||
TOXCORE_HASH=a3b25d8bd92b9526b47ba1f60a2893d2154a80bb7ae690f44b5a2dea41c76ea1
|
||||
TOXCORE_VERSION=0.2.3
|
||||
TOXCORE_HASH=22c52f286c46d3f802edb6978bcf2a53f8301363e2b745784613427a33ba3a34
|
||||
TOXCORE_FILENAME="c-toxcore-$TOXCORE_VERSION.tar.gz"
|
||||
if [ ! -f "$TOXCORE_PREFIX_DIR/done" ]
|
||||
then
|
||||
rm -rf "$TOXCORE_PREFIX_DIR"
|
||||
mkdir -p "$TOXCORE_PREFIX_DIR"
|
||||
|
||||
wget https://github.com/TokTok/c-toxcore/archive/v$TOXCORE_VERSION.tar.gz -O c-toxcore-$TOXCORE_VERSION.tar.gz
|
||||
check_sha256 "$TOXCORE_HASH" "c-toxcore-$TOXCORE_VERSION.tar.gz"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf c-toxcore*.tar.gz
|
||||
rm c-toxcore*.tar.gz
|
||||
wget https://github.com/TokTok/c-toxcore/archive/v$TOXCORE_VERSION.tar.gz -O $TOXCORE_FILENAME
|
||||
check_sha256 "$TOXCORE_HASH" "$TOXCORE_FILENAME"
|
||||
bsdtar --no-same-owner --no-same-permissions -xf "$TOXCORE_FILENAME"
|
||||
rm "$TOXCORE_FILENAME"
|
||||
cd c-toxcore*
|
||||
|
||||
mkdir -p build
|
||||
|
@ -1117,15 +1125,18 @@ then
|
|||
fi
|
||||
set -u
|
||||
|
||||
# Spell check on windows currently not supported, disable
|
||||
if [[ "$BUILD_TYPE" == "release" ]]
|
||||
then
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=./toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DSPELL_CHECK=OFF \
|
||||
..
|
||||
elif [[ "$BUILD_TYPE" == "debug" ]]
|
||||
then
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=./toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DSPELL_CHECK=OFF \
|
||||
..
|
||||
fi
|
||||
|
||||
|
|
|
@ -276,7 +276,7 @@ Section "Install"
|
|||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "Path" "$INSTDIR\bin\"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "qTox"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "1.15.0"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "1.16.3"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "The qTox Project"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "https://qtox.github.io"
|
||||
|
|
|
@ -277,7 +277,7 @@ Section "Install"
|
|||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "" "$INSTDIR\${MAIN_APP_EXE}"
|
||||
${WriteRegStr} "${REG_ROOT}" "${REG_APP_PATH}" "Path" "$INSTDIR\bin\"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayName" "qTox"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "1.15.0"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "DisplayVersion" "1.16.3"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "Publisher" "The qTox Project"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "UninstallString" "$INSTDIR\uninstall.exe"
|
||||
${WriteRegStr} ${REG_ROOT} "${UNINSTALL_PATH}" "URLInfoAbout" "https://qtox.github.io"
|
||||
|
|
Loading…
Reference in New Issue
Block a user