Compare commits

...

318 Commits

Author SHA1 Message Date
John Preston
9d1a4cdbfe Beta version 2.1.8: Fix build on 64 bit systems. 2020-06-03 16:18:03 +04:00
John Preston
383e6dec43 Beta version 2.1.8.
- Add support for full group message history export.
- Allow export of a single chat message history in JSON format.
2020-06-03 15:51:27 +04:00
John Preston
85904e3022 Update submodules. 2020-06-03 15:51:15 +04:00
John Preston
f88b97553e Fix crash in destructor of Data::CloudFile. 2020-06-03 13:48:11 +04:00
John Preston
63c6a1db82 Allow removing users invited by me. 2020-06-03 12:57:36 +04:00
John Preston
ca97e3c375 Add more warnings for suspicious urls. 2020-06-03 12:44:46 +04:00
John Preston
ef30c776bf Fix visual glitch in filter change from archived chat. 2020-06-03 12:31:15 +04:00
Ilya Fedin
d45e74619d Use Platform::IsWayland from lib_base 2020-06-03 11:43:55 +04:00
Ilya Fedin
d92b5eebcc Restore X error handler just like qgtk3 2020-06-03 11:31:34 +04:00
Ilya Fedin
5c6b4d95b0 Suppress warning about transient parent when opening gtk file dialog 2020-06-03 11:31:34 +04:00
Ilya Fedin
0fbec5eba1 Use QVersionNumber to compare version in native notifications 2020-06-03 11:31:34 +04:00
Ilya Fedin
ab13d9bdaf Skip empty parts in QT_QPA_PLATFORMTHEME 2020-06-03 11:31:34 +04:00
Ilya Fedin
0165e31ca7 Never use custom code for portal detecting in flatpak 2020-06-03 11:31:34 +04:00
Ilya Fedin
f1e75d809a Separate patches 2020-06-03 11:31:34 +04:00
Ilya Fedin
c776f81dc7 Add support for choosing directories via xdg-desktop-portal 2020-06-03 11:31:34 +04:00
John Preston
9fd62d3892 Add more deprecated system versions. 2020-06-02 22:26:59 +04:00
John Preston
793906ca9a Fix build on Windows. 2020-06-02 12:26:58 +04:00
23rd
35e575c2d7 Fixed build for macOS. 2020-06-01 19:28:19 +03:00
23rd
f5e84220eb Fixed crash in context menu for uploading scheduled messages. 2020-06-01 17:55:22 +03:00
Ilya Fedin
1d622fb3c0 Add patches with the fix for https://github.com/telegramdesktop/tdesktop/issues/6645 2020-06-01 18:43:42 +04:00
Nicholas Guriev
d8d3dda2f3 Fix little typo in theme names generator 2020-06-01 18:26:16 +04:00
Ilya Fedin
e098922a4b Add Platform::AutostartSupported 2020-06-01 18:25:21 +04:00
Ilya Fedin
413ddf285e Fix crash in gtk file dialog on Wayland 2020-06-01 18:22:53 +04:00
Ilya Fedin
7ac78be984 Load gtk2 even on Wayland 2020-06-01 18:22:53 +04:00
Ilya Fedin
4c546156da Remove duplicate log line 2020-06-01 18:22:53 +04:00
Ilya Fedin
db528b39e1 Fix macOS cache validating
macOS action has runner version in the workdir path, it should be a part of the cache key
2020-06-01 18:21:52 +04:00
Ilya Fedin
586744c112 Apply sway fixes to the PiP and export windows too 2020-06-01 18:21:30 +04:00
Ilya Fedin
7b106761be Remove cache from snap action since it works not so good 2020-06-01 18:19:34 +04:00
Ilya Fedin
8fb7f0fc73 Use TDESKTOP_USE_GTK_FILE_DIALOG in snap 2020-06-01 18:19:34 +04:00
Ilya Fedin
10b169f9f6 Make not supported errors static 2020-06-01 18:19:34 +04:00
Ilya Fedin
c83b8d4043 Fix naming of static variables 2020-06-01 18:19:34 +04:00
Ilya Fedin
1fc2b19c94 Add Cinnamon sound settings command 2020-06-01 18:19:34 +04:00
Ilya Fedin
fb97940cac Rename SandboxAutostart to PortalAutostart 2020-06-01 18:19:34 +04:00
Ilya Fedin
16c38b54e2 Rename InSandbox to InFlatpak 2020-06-01 18:19:34 +04:00
Ilya Fedin
7f29f57c3d Use custom gtk file dialog only on gtk-based DEs 2020-06-01 18:19:34 +04:00
Ilya Fedin
1fb1d57a27 Get system icon theme on gtk-based DEs 2020-06-01 18:19:34 +04:00
Ilya Fedin
47d7bd95ae Add a method to check if gtk integration is forced 2020-06-01 18:19:34 +04:00
John Preston
368eeaf754 Improve single chat export progress display. 2020-06-01 18:09:34 +04:00
John Preston
1686eb394d Add support for JSON single-chat export. 2020-06-01 18:09:34 +04:00
John Preston
02586ebe4b Allow export of just-converted supergroup. 2020-06-01 18:09:34 +04:00
John Preston
8f80c19ae1 Merge old group with supergroup history in export. 2020-06-01 18:09:34 +04:00
John Preston
1598165e2b Closed alpha version 2.1.7.4. 2020-06-01 18:09:34 +04:00
John Preston
f4cd84c313 Fix crash in stickers. 2020-06-01 18:09:34 +04:00
John Preston
9b574e497d Closed alpha version 2.1.7.3. 2020-06-01 18:09:34 +04:00
John Preston
6660338ccc Fix crash in sticker sets without a thumbnail. 2020-06-01 18:09:34 +04:00
John Preston
423ea5b499 Fix crash on invalid image data. 2020-06-01 18:09:34 +04:00
John Preston
4695ebae6e Fix crash in sticker set parsing. 2020-06-01 18:09:34 +04:00
John Preston
aaa4db7b27 Fix a crash in custom notifications. 2020-06-01 18:09:34 +04:00
John Preston
0965b06fa3 Closed alpha version 2.1.7.2. 2020-06-01 18:09:34 +04:00
Ilya Fedin
be96bf2812 Set parent for dialogs only on Wayland 2020-06-01 18:09:34 +04:00
John Preston
b7aa60bedf Fix build for Linux. 2020-06-01 18:09:34 +04:00
John Preston
d5b3fa017b Fix build for macOS. 2020-06-01 18:09:34 +04:00
John Preston
36fbdfb380 Simplify Image, remove ImageSource. 2020-06-01 18:09:33 +04:00
John Preston
d0c78eaddd Leave only one image source type. 2020-06-01 18:09:33 +04:00
John Preston
6513422e40 Remove legacy image-related code. 2020-06-01 18:09:33 +04:00
John Preston
f066e0f05a Use Data::CloudImage for userpics. 2020-06-01 18:09:33 +04:00
John Preston
249f7813c1 Don't hold session pointer in Data::CloudImage. 2020-06-01 18:09:33 +04:00
John Preston
29a498b959 Use Data::CloudImage for location thumbnails. 2020-06-01 18:09:33 +04:00
John Preston
ae9ed820ee Fix sticker set icons display. 2020-06-01 18:09:33 +04:00
John Preston
803593cd8d Change Stickers::Set from value to object type. 2020-06-01 18:09:33 +04:00
John Preston
897e432f40 Use CloudImageView in the inline bot thumbnails. 2020-06-01 18:09:33 +04:00
John Preston
50e0c3ee4d Fix preloading in media viewer. 2020-06-01 18:09:33 +04:00
John Preston
056945d9f5 Remove legacy image creation methods. 2020-06-01 18:09:32 +04:00
John Preston
a9b70a7d63 Closed alpha 2.1.7.1: Fix build for Xcode. 2020-06-01 18:09:32 +04:00
John Preston
6dabd87df3 Closed alpha version 2.1.7.1. 2020-06-01 18:09:32 +04:00
John Preston
b35b6c4449 Fix saving cache from InMemoryLocation. 2020-06-01 18:09:32 +04:00
John Preston
74ef8104a7 Fix photo edit caption box, remove 's' size. 2020-06-01 18:09:32 +04:00
John Preston
af0eebb6f1 Remove debug inline bot results marks. 2020-06-01 18:09:32 +04:00
John Preston
dbb46ce9b0 Let [Photo|Document]Media outlive message view. 2020-06-01 18:09:32 +04:00
John Preston
700d3db4cc Correctly unload heavy parts on quit. 2020-06-01 18:09:32 +04:00
John Preston
64cf0e1a44 Fix caching of sent photos and document previews. 2020-06-01 18:09:32 +04:00
John Preston
7ad660a0e7 Allow photos not have some of the thumbnails. 2020-06-01 18:09:32 +04:00
John Preston
e27d2bc2d5 Move photo data to Data::PhotoMedia. 2020-06-01 18:09:32 +04:00
John Preston
24fed8105c Fix stickers panel on Retina screens. 2020-06-01 18:09:32 +04:00
John Preston
9ce59730ff Collect local DocumentMedia data. 2020-06-01 18:09:32 +04:00
John Preston
3f26fc9f55 Allow WebDocument video thumbnails. 2020-06-01 18:09:32 +04:00
John Preston
0834920db8 Fix sending of video-thumbed GIFs from panel. 2020-06-01 18:09:32 +04:00
John Preston
f4ed2c26ba Save video thumbnail location to local storage. 2020-06-01 18:09:32 +04:00
John Preston
c63e2c01ac Use video thumbnail in media preview. 2020-06-01 18:09:31 +04:00
John Preston
c61f3a0aba Fix sending of thumbnailed inline result GIFs. 2020-06-01 18:09:31 +04:00
John Preston
3c9ca2eb94 Load and show video thumbnails in the panel. 2020-06-01 18:09:31 +04:00
John Preston
33c1c48ad9 Update API scheme to layer 114. 2020-06-01 18:09:31 +04:00
John Preston
a27aea3887 Allow retrying of updates build preparing. 2020-06-01 18:09:31 +04:00
John Preston
ea4044e38c Use TgVoip interface instead of VoIPController. 2020-06-01 18:09:31 +04:00
John Preston
c967a72dcb Save frame in GIFs panel. 2020-06-01 18:09:31 +04:00
John Preston
7d386b164b Save a frame in stickers panel. 2020-06-01 18:09:31 +04:00
John Preston
ccbbf6f5f3 Always download GIFs in the panel.
Fixes #6981.
2020-06-01 18:09:31 +04:00
John Preston
9725d4272e Clear DocumentMedia in sticker panel. 2020-06-01 18:09:31 +04:00
John Preston
eb75859dc0 Cache last frame of stickers panel footer icons. 2020-06-01 18:09:31 +04:00
John Preston
ad5507f2c8 Clear DocumentMedia in media overview. 2020-06-01 18:09:31 +04:00
John Preston
58f82620e0 Simplify media overview layouts. 2020-06-01 18:09:31 +04:00
John Preston
053eace154 Prepare overview layouts for media clearing. 2020-06-01 18:09:31 +04:00
John Preston
d64014c995 Clear DocumentMedia in ReplyPreview. 2020-06-01 18:09:31 +04:00
John Preston
44ec55b6a8 Clear DocumentMedia in links overview. 2020-06-01 18:09:31 +04:00
John Preston
9dba723643 Better DocumentMedia management in BackgroundBox. 2020-06-01 18:09:31 +04:00
John Preston
97a82762ef Fix build with MSVC 16.6.0. 2020-06-01 18:09:31 +04:00
John Preston
1542311d89 Preload documents in media viewer. 2020-06-01 18:09:31 +04:00
John Preston
fb322b5fc5 Use empty Storage::Cache::Key as nullopt. 2020-06-01 18:09:31 +04:00
John Preston
581a21dbd9 Use Media::Streaming in EditCaptionBox. 2020-06-01 18:09:31 +04:00
John Preston
3d431a27cb Improve inline thumbnail usage in PiP player. 2020-06-01 18:09:31 +04:00
John Preston
cbb9657044 Fix download task finalizing. 2020-06-01 18:09:30 +04:00
John Preston
3797753d16 Support different location types for thumbnails. 2020-06-01 18:09:30 +04:00
John Preston
37aabc0da9 Add generic DownloadLocation and ImageLocation. 2020-06-01 18:09:30 +04:00
John Preston
956c3af0ae Start DocumentData::thumbnail move to DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
1329870c8e Fix build on macOS. 2020-06-01 18:09:30 +04:00
John Preston
ff6365ec72 Fix crash in still downloaded ~DocumentData. 2020-06-01 18:09:30 +04:00
John Preston
1e9c79ca85 Move automaticLoad() to DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
40f12a2584 Keep document byte data only in DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
97bab388ea Use rpl for file download progress notifications. 2020-06-01 18:09:30 +04:00
John Preston
bf616036b3 Check loaded status through DocumentMedia if possible. 2020-06-01 18:09:30 +04:00
John Preston
669b79588e Remove FilePathResolve::SaveFromData. 2020-06-01 18:09:30 +04:00
John Preston
33f4946242 Start using document bytes from DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
888e42df34 Remove data_document_good_thumbnail module. 2020-06-01 18:09:30 +04:00
John Preston
70c79eb6bd Move sticker image to DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
bdd3c51ab8 Move inline thumbnail image to DocumentMedia. 2020-06-01 18:09:30 +04:00
John Preston
6ca43153bb Improve clearing of DocumentMedia. 2020-06-01 18:09:29 +04:00
John Preston
7db53599e8 Use Data::DocumentMedia to store good thumbnails. 2020-06-01 18:09:29 +04:00
John Preston
61647275e8 Optimize image destruction.
No need to call _source->unload(), it leads to saving to PNG.
2020-06-01 18:09:29 +04:00
Ilya Fedin
a37138aa52 Fix signature key errors in snap action 2020-06-01 15:24:35 +04:00
Ilya Fedin
1504136828 Don't spam logs if there are no dbus 2020-05-26 07:24:18 +04:00
Ilya Fedin
c12356a032 Disable unneeded alsa dependency in ffmpeg 2020-05-25 10:34:12 +04:00
Ilya Fedin
126ed6e6e3 Fix path to compose file 2020-05-25 10:34:12 +04:00
Ilya Fedin
fa4236e9ea Add support for DESKTOP_APP_USE_PACKAGED on macOS 2020-05-25 10:29:40 +04:00
Ilya Fedin
b19dcf0653 Add possibility to control external upater flag with a config in /etc 2020-05-25 10:27:48 +04:00
Ilya Fedin
77d1f64e0e Disable fallback session management 2020-05-25 09:31:52 +04:00
Ilya Fedin
3479a4ec59 Add parent, minimum and maximum size to notifications 2020-05-25 09:29:15 +04:00
Ilya Fedin
bdf28370f9 Fix call window size on Sway 2020-05-25 09:29:15 +04:00
Ilya Fedin
cd81fc6727 Don't lose -freetype argument on restart 2020-05-25 09:26:49 +04:00
John Preston
7351641034 Version 2.1.7.
- Fix the Fcitx input method plugin.
2020-05-24 11:59:19 +04:00
Ilya Fedin
e0669e222d Update fcitx5-qt 2020-05-24 11:09:34 +04:00
Ilya Fedin
4c1f83daca Add a check for bundled Qt plugins 2020-05-24 10:57:37 +04:00
Ilya Fedin
ced2652deb OpenAL returns device names with UTF-8 2020-05-24 10:56:29 +04:00
23rd
8d1db85a28 Fixed album items selection in section of scheduled messages.
This bug relates only to albums with captions.
2020-05-20 12:00:44 +03:00
John Preston
97305c8cb5 Fix build. 2020-05-20 12:49:41 +04:00
23rd
1ef5d81270 Added ability to change months in calendar with mouse wheel. 2020-05-20 12:42:03 +04:00
23rd
9ff427afad Fixed indefinitely bouncing of dock icon. 2020-05-20 12:41:44 +04:00
23rd
1c5eadcd79 Fixed context menu for caption of scheduled album.
Fixed #6523.
2020-05-20 12:41:44 +04:00
23rd
bc6c01de7f Added Esc shortcut to clear selection in section of scheduled messages. 2020-05-20 12:41:44 +04:00
23rd
41255cab44 Removed display views and author for sent scheduled messages.
Moved filling of post flags to a single place.
2020-05-20 12:41:44 +04:00
23rd
ccbc63cd6e Added ability to paste data in section of scheduled messages.
Fixed #6702.
Fixed #6539.
2020-05-20 12:41:44 +04:00
23rd
97446ae783 Added ability to reschedule scheduled messages. 2020-05-20 12:41:44 +04:00
23rd
5a75dd2b6f Added handling of updates for rescheduled messages. 2020-05-20 12:41:43 +04:00
Wei Cheng
6559e83e83 fix: obtain doNotDisturb value correctly 2020-05-15 11:44:06 +04:00
John Preston
d679703bbf Version 2.1.6.
- Fix automatic downloads on Windows by clean rebuild.
2020-05-14 01:16:13 +04:00
John Preston
66a3e36024 Version 2.1.5.
- Disable the taskbar icon flash or the dock icon bounce
in Settings > Notifications.
- View messages containing long monospace texts in wide bubbles.
- Bug fixes and other minor improvements.
2020-05-13 18:22:05 +04:00
John Preston
31e38e1690 Fix layout of community transfer error box. 2020-05-13 18:19:09 +04:00
John Preston
da10059f45 Update lib_lottie, hide rlottie dependency. 2020-05-13 17:07:26 +04:00
John Preston
cb5863177f Apply edition updates to search result previews. 2020-05-12 20:29:18 +04:00
John Preston
84399286c1 Update build instructions. 2020-05-12 19:43:39 +04:00
John Preston
2e92441b3a Add input method field text edit workaround. 2020-05-12 19:26:50 +04:00
John Preston
7883f97c94 Use precise sync of the server unixtime. 2020-05-12 17:33:06 +04:00
Ilya Fedin
297b5d6a76 Update submodules 2020-05-12 17:32:40 +04:00
Ilya Fedin
492dc2568c Add DESKTOP_APP_USE_PACKAGED support for Windows 2020-05-12 17:32:40 +04:00
John Preston
547c657b1a Don't reset search results on dialogs re-open. 2020-05-12 16:30:31 +04:00
John Preston
c478d96385 Add debug logs for chats reading requests. 2020-05-12 16:18:19 +04:00
John Preston
2ede53e0ee Always try to open new provided URL.
Fixes #6941.
2020-05-12 16:15:22 +04:00
John Preston
6f760d513e Add a checkbox to disable taskbar flash.
Also add ability to set urgent flag for the window on Linux.

Fixes #223, fixes #897, fixes #906.
2020-05-12 14:16:24 +04:00
John Preston
f4f6550d66 Clear fake-unread status when switching folders. 2020-05-12 12:18:52 +04:00
John Preston
c7878f9d21 Pause by-emoji stickers on sticker preview. 2020-05-12 12:18:31 +04:00
John Preston
cd75a45673 Disable create polls in support accounts. 2020-05-12 11:26:47 +04:00
John Preston
07e3671ca8 Allow monospace blocks to extend bubble width.
This partially fixes #2060 instead of additional settings from #7822.
2020-05-12 11:07:41 +04:00
23rd
295aa644bf Fixed master branch updater Github Action. 2020-05-12 09:55:36 +04:00
John Preston
b5b78c0ade Update submodules. 2020-05-12 09:44:24 +04:00
John Preston
f5c0e5d31d Remove unnecessary include. 2020-05-12 09:43:54 +04:00
root
246ed43046 Remove replyTo from switchInlineBotButton in same peer 2020-05-12 09:29:30 +04:00
Ilya Fedin
701e1d7b4d Add fcitx5 support 2020-05-12 09:26:04 +04:00
Ilya Fedin
9cbe899688 Fix call window hiding when compositing is not supported 2020-05-12 09:17:27 +04:00
Ilya Fedin
7409d615a3 Add a cheat code to enable freetype on Windows and macOS 2020-05-10 17:09:59 +04:00
John Preston
c9553c2d4c Version 2.1.4.
- Improve bold font selection.
2020-05-08 20:34:00 +04:00
John Preston
bedefaee4d Version 2.1.3.
- Added support for new emoji.
- Channels to which you can't post will no longer be suggested when forwarding.
- Improved font selection and bold font support for CJK and Farsi.
2020-05-08 16:48:56 +04:00
John Preston
5d3b8f02fc Add Vazir font as a fallback for Farsi. 2020-05-08 13:38:23 +04:00
John Preston
5120d3ef2c Skip channels without write access in forward box. 2020-05-08 13:35:16 +04:00
John Preston
82a372873f Add two local urls to open language selection box.
tg://setlanguage and tg://settings/language

Fixes #7831.
2020-05-08 13:03:49 +04:00
Ilya Fedin
d1d1f83881 Remove outdated LIBGL_ALWAYS_INDIRECT hack 2020-05-08 12:54:21 +04:00
Ilya Fedin
78c3c86fe6 Check only if at least one audio device is exist on startup
This makes https://github.com/telegramdesktop/tdesktop/issues/1548 don't affect on startup, but only when capture feature is used
2020-05-08 12:50:25 +04:00
Ilya Fedin
447d4e6c47 Remove Portaudio from building instructions
Since it loaded at runtime with dlopen anyway and headers from the system package are OK
2020-05-08 12:49:21 +04:00
John Preston
d0e3d15e8e Update supported systems information. 2020-05-08 12:27:55 +04:00
John Preston
0251f58bf2 Use Semibold in names, use Bold in messages.
Fixes #7813, fixes #7823.
2020-05-08 12:12:47 +04:00
John Preston
36997f084a Automatically load and apply old emoji set by id. 2020-05-08 11:22:22 +04:00
John Preston
942fcb9aae Add new emoji sets file ids. 2020-05-07 19:05:57 +04:00
John Preston
6232dce1a3 Update emoji in the built-in data and sprites. 2020-05-06 19:29:02 +04:00
23rd
0c0fc46b90 Added Github Action that updates code in master branch. 2020-05-06 13:29:17 +04:00
23rd
dcf737bebe Fixed Linux build instruction. 2020-05-06 00:36:48 +03:00
23rd
919834093e Added TG for macOS version check to issue closer. 2020-05-05 18:22:54 +04:00
John Preston
99ccd49e13 Version 2.1.2: Update patches revision in docs. 2020-05-05 18:14:38 +04:00
John Preston
29896b2efd Version 2.1.2: Update Mac App Store build script. 2020-05-05 17:35:42 +04:00
John Preston
1b7f3db43a Version 2.1.2.
- Fix polls and quizes results viewing.
- Fix memory leak in web page previews with autoplayed videos.
- Fix running on OS X 10.10.
- Other minor bug fixes and improvements.
2020-05-05 17:20:03 +04:00
John Preston
1fa22398a9 Fix returning of tabbed panel in third column. 2020-05-05 16:55:05 +04:00
John Preston
0e16b3fe69 Decrease sticker size 256px -> 228px. 2020-05-05 16:19:10 +04:00
John Preston
462020d54c Update submodules. 2020-05-05 16:19:00 +04:00
John Preston
9c17147f60 Show only one dice-media tooltip. Hide on SEND. 2020-05-05 15:51:55 +04:00
Ilya Fedin
0bf933b009 Remove dependencies from snap that are present in kde-frameworks-5-core18 snap 2020-05-05 14:31:18 +04:00
Ilya Fedin
27f6c8ce62 Move CMAKE_DL_LIBS to libtgvoip cmake file and add missed pthread
Remove unneeded minizip include directory from cmake

Remove unneeded compile definations

Opus is needed only by libtgvoip
2020-05-05 14:31:18 +04:00
Ilya Fedin
3135463017 Add new option to simplify creation of self-contained packages (snap/flatpak/appimage) 2020-05-05 14:31:18 +04:00
RadRussianRus
89950de93e Do not ignore changes for docs needed for build 2020-05-05 14:20:58 +04:00
Ilya Fedin
13c2d6ff72 Detect global menu at runtime 2020-05-05 09:54:35 +04:00
John Preston
5e70bf64c6 Fix adding the string. 2020-05-04 19:16:41 +04:00
John Preston
3260e9e752 Add a separate string for empty channel admin log. 2020-05-04 19:15:10 +04:00
John Preston
1f16ac59ca Try to fix a crash in pinned reordering. 2020-05-04 19:06:53 +04:00
RadRussianRus
87bf0654a2 Move "X groups in common" in shared media to bottom 2020-05-04 18:36:47 +04:00
John Preston
6adcf660f1 Guard click handlers that capture session data.
Click handlers invocation is done by posting on_main,
so in rare cases the session may be already destroyed.
2020-05-04 17:38:49 +04:00
John Preston
038d8f1781 Force non-empty text in message bubbles. 2020-05-04 17:03:47 +04:00
John Preston
a5977f5f7a Don't link unneeded frameworks in OS X version.
Fixes #7786.
2020-05-04 16:52:07 +04:00
John Preston
2143864fd5 Remove views count from admin log. 2020-05-04 16:15:09 +04:00
John Preston
73691e795b Fix broken poll results view.
Regression was introduced in dd78052f92.

Fixes #7780.

Copy-Paste is bad.
2020-05-04 14:42:06 +04:00
John Preston
c0246a9373 Fix pasting of an image with attached URL data.
Regression was introduced in db5d599052.

Fixes #7794.
2020-05-04 14:18:33 +04:00
John Preston
1af394a485 Fix video unloading in streaming in WebPage-s.
Fixes #7778.
2020-05-04 13:27:30 +04:00
Ilya Fedin
5180d31b40 Fix decoration applying and trigger repainting on update
For some reason this is needed for newer Qt in flatpak
2020-05-02 16:29:00 +04:00
John Preston
07c8aae225 Version 2.1.1: Pin to top only new bots. 2020-05-01 21:20:10 +04:00
John Preston
3c1c17ef80 Version 2.1.1: Remove font substitutions on Win. 2020-05-01 19:59:54 +04:00
Ilya Fedin
b79ecb5909 Show friendly warning if snapd didn't update snap right for some reason 2020-05-01 17:30:11 +04:00
John Preston
b98f0933af Version 2.1.1.
- Improve quiz explanation tooltip layout.
- Fix possible crash in theme editor.
- Other minor bug fixes and improvements.
2020-05-01 17:16:57 +04:00
John Preston
05dcd6fc9c Fix possible crash in rlottie.
Fixes #7767.
2020-05-01 17:16:57 +04:00
John Preston
19bcc145ad Fix crash in theme editor. 2020-05-01 16:27:55 +04:00
John Preston
4ae760dd7e Fix send files emoji panel geometry.
Fixes #7704.
2020-05-01 16:05:24 +04:00
RadRussianRus
cad4d19272 Use "subscribers" instead of "members" in channels 2020-05-01 15:48:07 +04:00
Aokromes
ae64747489 Remove whitespaces, fix spaces 2020-05-01 14:47:33 +04:00
John Preston
db5d599052 Don't resolve the actual QImage on paste check. 2020-05-01 14:43:02 +04:00
John Preston
cc463b07b1 Don't send dice / dart to channels.
Fixes #7703.
2020-05-01 14:35:20 +04:00
John Preston
d8e55081b0 Disallow revoking dice media in first 24 hours.
Fixes #7745.
2020-05-01 13:21:57 +04:00
John Preston
9c66bd553a Increment emoji cache version. 2020-05-01 12:59:23 +04:00
23rd
a6bb180e22 Fixed rendering of colored Apple emoji with gender.
Fixed #6024.
2020-05-01 12:46:31 +04:00
John Preston
38ca3ba341 Update submodules. 2020-05-01 12:32:03 +04:00
23rd
8ef00dc4ff Fixed resetting menu scroll after refresh of filter list. 2020-05-01 12:31:13 +04:00
23rd
1630ad0804 Fixed crash when user pins chat in remotely removed filter. 2020-05-01 12:31:13 +04:00
23rd
c3c482aa50 Improved peer context menu item to archive chat. 2020-05-01 12:31:13 +04:00
23rd
f4a63e1e9d Removed info display for last messages in Saved Messages. 2020-05-01 12:31:13 +04:00
Ilya Fedin
161e51757c Change color of wayland decoration according to theme 2020-05-01 12:26:10 +04:00
Ilya Fedin
46d4b03d49 Fix freeze in notifications settings when notification daemon is unavailable 2020-05-01 12:15:01 +04:00
RadRussianRus
48743a7973 Exclude files that aren't necessary for actions 2020-05-01 12:12:49 +04:00
seniorivn
6709147560 Update shortcuts.cpp 2020-05-01 12:11:14 +04:00
seniorivn
0b2d4326e7 add folder commands for custom config 2020-05-01 12:11:14 +04:00
RadRussianRus
ca49e74b6f Show bot privacy status 2020-05-01 12:10:32 +04:00
Ilya Fedin
95b4f56b86 Don't use QDesktopServices::openUrl on snap 2020-05-01 12:06:01 +04:00
Nicholas Guriev
9828262a03 Update GSL to v3.0.1 and lib_base
* Use identical types for std::min.
2020-05-01 12:03:18 +04:00
John Preston
f76e094e98 Use info toast to show proxy / psa about text. 2020-04-30 15:20:50 +04:00
John Preston
067e52f5d1 Add an icon to the psa / quiz tooltip. 2020-04-30 14:51:26 +04:00
John Preston
4efd649c27 Hide tooltip button in psa / quizes. 2020-04-30 14:11:05 +04:00
John Preston
ff25f1d5c9 Slide psa / quiz toast from the top. 2020-04-30 13:16:42 +04:00
John Preston
dd78052f92 Use new toast style structure. 2020-04-30 11:35:01 +04:00
John Preston
8a4c7e3994 Show PSA tooltip icon and tooltip. 2020-04-30 11:35:01 +04:00
John Preston
44e71dfa03 Allow hiding PSA from the chats list. 2020-04-30 11:35:01 +04:00
John Preston
b6e184d0c8 Support bots as top promoted dialog entries. 2020-04-30 11:35:01 +04:00
John Preston
042ed8f54a Support psa_message in chats list. 2020-04-30 11:35:01 +04:00
John Preston
aabc8173c3 Use similar margins in all controls. 2020-04-30 11:35:01 +04:00
John Preston
c14e20b33f Support PSA forwarded info. 2020-04-30 11:35:01 +04:00
John Preston
266c1531ce Display PSA label instead of the proxy sponsor. 2020-04-30 11:35:01 +04:00
John Preston
8d632bd2be Update API scheme to layer 103. 2020-04-30 11:35:01 +04:00
John Preston
c70a1f03de Fix applying poll updates. 2020-04-30 11:35:01 +04:00
Ilya Fedin
17de6c1ff3 Fix scaling in crash reporter 2020-04-29 15:51:24 +04:00
Stepan Skryabin
4e210e40a2 Update supported Ubuntu version 2020-04-28 19:01:05 +04:00
Ilya Fedin
e13593b095 Restore setFamily in crash report window
Since setFamily in QApplication::setFont was removed
2020-04-28 19:00:44 +04:00
Ilya Fedin
e149f10d40 Revert gtk3 dialog in snap 2020-04-26 12:28:34 +04:00
Ilya Fedin
7f890122e6 Add methods to detect appimage, static binary and forced gtk dialog 2020-04-26 12:28:34 +04:00
Ilya Fedin
422831fa79 Update snap cache 2020-04-26 12:25:01 +04:00
Ilya Fedin
7494468f1f Add cinnamon gsettings schema to snap
Fixes #7697
2020-04-26 12:25:01 +04:00
Ilya Fedin
7bc86cc9af Fix directory opening with portal and use them by default with KDE 2020-04-24 14:33:26 +04:00
John Preston
c1f3fe1961 Version 2.1.
- Access a catalog of over 20,000 stickers made by professional
artists from the updated Sticker Panel by clicking the '+' icon.
- Use sticker search to find the stickers you're looking for - or
scroll from the latest packs all the way to the classics.
- Add explanations that appear after users respond to a quiz question.
- See how much time you have left to answer a question from @QuizBot
with the new countdown animation.
- Send a single 🎯 emoji to see if you hit the bullseye.
2020-04-24 09:08:08 +04:00
John Preston
cfd733c54c Add confirmation box for suspicious urls. 2020-04-23 19:00:19 +04:00
John Preston
3fa5e004fe Allow editing messages in channels indefinitely. 2020-04-23 16:21:30 +04:00
John Preston
862e4e45ad Closed alpha version 2.0.1.3. 2020-04-21 18:55:56 +04:00
John Preston
53df4d1b10 Fix magic for initConnection. 2020-04-21 18:55:35 +04:00
John Preston
5cfd402b70 Make darker toasts for quiz solutions. 2020-04-21 18:55:35 +04:00
John Preston
57e9651a8a Fix visual glitch in poll results viewing.
We need a visible widget to mark more button height.
An invisible 'more' button doesn't receive geometry change events.
2020-04-21 18:55:35 +04:00
John Preston
53d206c12c Custom tab-order for create poll box. 2020-04-21 18:55:35 +04:00
John Preston
46f3cf3395 Load more official sets while scrolling. 2020-04-21 18:55:35 +04:00
John Preston
dfc0491524 Improve trending stickers layout and position. 2020-04-21 18:55:35 +04:00
John Preston
54f757e770 Allow sending dice from dice media tooltip. 2020-04-21 18:55:35 +04:00
John Preston
abfd3ad1b9 Use built-in zero-value dice animations. 2020-04-21 18:55:35 +04:00
John Preston
bed208d621 Send dice media based on appconfig. 2020-04-21 18:55:35 +04:00
John Preston
33c453a13c Scroll history to bottom on sending a message. 2020-04-21 18:55:35 +04:00
John Preston
e118972d5c Support generic dice media display. 2020-04-21 18:55:35 +04:00
John Preston
fb8a9a930c Closed alpha version 2.0.1.2. 2020-04-21 18:55:35 +04:00
John Preston
7a9cfcc40d Improve poll closing by timer and results reloading. 2020-04-21 18:55:35 +04:00
John Preston
e1dc15321a Work around 32-bitness of GetLastInputInfo.
Fixes #7637.
2020-04-21 18:55:35 +04:00
John Preston
2b5e575b67 Closed alpha version 2.0.1.1: Fix macOS fonts. 2020-04-21 18:55:34 +04:00
John Preston
42e216603c Closed alpha version 2.0.1.1. 2020-04-21 18:55:34 +04:00
23rd
d46e145c61 Updated Qt to 5.12.8. 2020-04-21 18:55:34 +04:00
John Preston
5dcb232b77 Force reload results on auto-closed quiz. 2020-04-21 18:55:34 +04:00
John Preston
b34d5b8306 Check solution length in CreatePollBox. 2020-04-21 18:55:34 +04:00
John Preston
76d81ff197 Improve polls solution icon color. 2020-04-21 18:55:34 +04:00
John Preston
71637d2a0e Show progress left to close by timer in polls. 2020-04-21 18:55:34 +04:00
John Preston
423daecbde Add view solution button to polls. 2020-04-21 18:55:34 +04:00
John Preston
3cb76fb80b Support poll closing by date. 2020-04-21 18:55:34 +04:00
John Preston
6882093ed1 Send init connection params. 2020-04-21 18:55:34 +04:00
John Preston
699761b42f Support poll solution display in a toast. 2020-04-21 18:55:34 +04:00
John Preston
f50c50a152 Fix path choosing for Windows Store version. 2020-04-21 18:55:34 +04:00
John Preston
13d22947df Send poll solution with entities. 2020-04-21 18:55:34 +04:00
John Preston
6c08bab550 Add explanation block to CreatePollBox. 2020-04-21 18:55:34 +04:00
John Preston
3e2f4bed50 Update scheme to layer 102.
Support different dice-like media.
2020-04-21 18:55:34 +04:00
Ilya Fedin
41d39012d2 Synchronize AppMenu availability check with Qt 2020-04-21 14:06:03 +04:00
Ilya Fedin
a7764f84f0 Proper usage of pkg-config 2020-04-21 14:05:22 +04:00
VictorienXP
85fcec2fb5 Add .opus and .oga files as song formats 2020-04-21 14:04:51 +04:00
Ilya Fedin
82e835fbc2 Fix snap action 2020-04-20 10:52:10 +04:00
Ilya Fedin
80684d9073 Remove unnecessary files from snap 2020-04-20 10:52:10 +04:00
Ilya Fedin
b04f0e0d3d Use kde-neon extension for better desktop integration 2020-04-20 10:52:10 +04:00
23rd
65cc9bcd87 Updated parser of issue closer since template was changed.
The issue template was changed in de78f4255e.
2020-04-13 17:18:59 +03:00
Ilya Fedin
bc06a3aea3 Make actions ignore .md files not only in the root of repository 2020-04-13 17:39:00 +04:00
Ilya Fedin
de78f4255e Add installation method to bug report template 2020-04-13 17:39:00 +04:00
John Preston
d67dafaccb Fix check for 4K frame size in streaming. 2020-04-13 15:32:20 +04:00
John Preston
4f8ea4c807 Allow to play in-app large videos. 2020-04-13 15:32:14 +04:00
John Preston
15b19f8565 Allow sending large images again (up to 108MP). 2020-04-13 15:32:06 +04:00
John Preston
b16696db93 Don't scroll down when read from another device. 2020-04-13 15:31:54 +04:00
John Preston
63129072ba Mark voice/video message as read on mention click.
Fixes #5623.
2020-04-13 15:30:56 +04:00
John Preston
1fdd591aa0 Change manage folders button icon. 2020-04-13 15:30:40 +04:00
John Preston
f370ca97d0 Fix folders visibility above passcode lock. 2020-04-13 15:30:23 +04:00
John Preston
f5aba5a907 Fix build with new lib_ui commits. 2020-04-13 15:26:09 +04:00
Ilya Fedin
1d613995db Disable building of dav1d tools and tests in snap 2020-04-13 15:16:33 +04:00
Ilya Fedin
5bb1c77199 Use OpenAL without direct channels 2020-04-13 15:15:29 +04:00
Ilya Fedin
5b39c7013a Better algorithm for font choosing 2020-04-13 11:48:14 +04:00
Ilya Fedin
ed91c07f99 Restore the old behavior with fallback fontconfig configuration
With current code fallback works only through time and replaces the config even if it is changed by the user.

This commit fixes that.
2020-04-13 10:49:30 +04:00
Ilya Fedin
a66b2a4056 Synchronize snap ffmpeg arguments with generic linux one 2020-04-13 10:44:29 +04:00
Ilya Fedin
a1a7399023 Don't remove SNI object when SNI is lost 2020-04-13 10:43:37 +04:00
Ilya Fedin
e71b7dd384 Don't overwrite artifacts by multiple runs 2020-04-13 10:42:32 +04:00
Ilya Fedin
664b43acd7 Fixes for linux action:
* Disable building of unneeded openal tools and tests
* Disable ffmpeg linkage with unneeded libraries
* Disable unneeded dtd validation for libwayland
* Omit Qt flags that set to default values
* Fix prefix usage
* Build dependencies in release mode to reduce build size
2020-04-12 19:21:59 +04:00
Ilya Fedin
eac867ce85 Add possibility to enable autoupdate on non-special target 2020-04-10 15:06:09 +04:00
John Preston
2ad48f18f2 Use only safe file saving in localstorage. 2020-04-02 18:31:15 +04:00
John Preston
e823fe5891 Fix support / media shortcuts. 2020-04-02 16:20:53 +04:00
459 changed files with 15223 additions and 10042 deletions

View File

@@ -25,6 +25,8 @@ Tell us what happens instead
**Version of Telegram Desktop:**
**Installation source (Linux Only)** - the official website / GitHub releases / flatpak / snap / distribution package:
**Used theme**:
<details><summary><b>Logs</b>:</summary>

View File

@@ -14,6 +14,22 @@ jobs:
echo $tag
echo ::set-env name=LATEST_TAG::$tag
- name: Get the latest macOS version.
shell: python
run: |
import subprocess;
from xml.dom import minidom;
url = "https://osx.telegram.org/updates/versions.xml";
subprocess.check_call("wget %s" % url, shell=True);
xmldoc = minidom.parse('versions.xml');
itemlist = xmldoc.getElementsByTagName('enclosure');
ver = itemlist[0].attributes['sparkle:shortVersionString'].value;
print(ver);
subprocess.check_call("echo ::set-env name=%s::%s" % ("LATEST_MACOS", ver), shell=True);
- name: Check a version from an issue.
uses: actions/github-script@0.4.0
with:
@@ -21,14 +37,24 @@ jobs:
script: |
let errorStr = "Version not found.";
function maxIndexOf(str, i) {
let index = str.indexOf(i);
return (index == -1) ? Number.MAX_SAFE_INTEGER : index;
}
let item1 = "Version of Telegram Desktop";
let item2 = "Used theme";
let item2 = "Installation source";
let item3 = "Used theme";
let item4 = "<details>";
let body = context.payload.issue.body;
console.log("Body of issue:\n" + body);
let index1 = body.indexOf(item1);
let index2 = body.indexOf(item2);
index2 = (index2 == -1) ? Number.MAX_SAFE_INTEGER : index2;
let index2 = Math.min(
Math.min(
maxIndexOf(body, item2),
maxIndexOf(body, item3)),
maxIndexOf(body, item4));
console.log("Index 1: " + index1);
console.log("Index 2: " + index2);
@@ -65,10 +91,20 @@ jobs:
let issueNum = firstNum(issueVer);
let latestNum = firstNum(latestVer);
if (issueNum <= latestNum && issueNum < 5) {
let macos_ver = process.env.LATEST_MACOS;
console.log("Telegram for MacOS version from website: " + macos_ver);
if (issueNum <= latestNum && issueNum < macos_ver) {
console.log("Seems the version of this issue is fine!");
return;
}
if (issueNum > macos_ver) {
let message = `Seems like it's neither the Telegram Desktop\
nor the Telegram for macOS version.
`;
console.log(message);
return;
}
let message = `
Sorry, but according to the version you specify in this issue, \
@@ -77,7 +113,7 @@ jobs:
You can report your issue to [the group](https://t.me/macswift) \
or to [the repository of Telegram for macOS](https://github.com/overtake/TelegramSwift).
If I made a mistake and closed your issue wrongly, please reopen it. Thanks!
**If I made a mistake and closed your issue wrongly, please reopen it. Thanks!**
`;
let params = {

View File

@@ -4,11 +4,43 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-cmake.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/linux.yml'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-cmake.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/linux.yml'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
jobs:
@@ -25,8 +57,8 @@ jobs:
env:
GIT: "https://github.com"
QT: "5_12_5"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.5"
QT: "5_12_8"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.8"
OPENSSL_VER: "1_1_1"
OPENSSL_PREFIX: "/usr/local/desktop-app/openssl-1.1.1"
CMAKE_VER: "3.17.0"
@@ -101,14 +133,6 @@ jobs:
cd Libraries
echo ::set-env name=LibrariesPath::`pwd`
- name: Range-v3.
run: |
echo "Find necessary branch from doc."
cloneRange=$(grep -A 1 "range-v3" $REPO_NAME/$DOC_PATH | sed -n 1p)
cd $LibrariesPath
echo $cloneRange
eval $cloneRange
- name: Patches.
run: |
echo "Find necessary commit from doc."
@@ -189,23 +213,29 @@ jobs:
git clone --branch release/3.4 $GIT/FFmpeg/FFmpeg ffmpeg
cd ffmpeg
./configure --prefix=$LibrariesPath/ffmpeg-cache \
--enable-protocol=file --enable-libopus \
./configure \
--disable-debug \
--disable-programs \
--disable-doc \
--disable-network \
--disable-autodetect \
--disable-everything \
--disable-neon \
--disable-alsa \
--disable-iconv \
--enable-libopus \
--enable-vaapi \
--enable-vdpau \
--enable-protocol=file \
--enable-hwaccel=h264_vaapi \
--enable-hwaccel=h264_vdpau \
--enable-hwaccel=mpeg4_vaapi \
--enable-hwaccel=mpeg4_vdpau \
--enable-decoder=aac \
--enable-decoder=aac_at \
--enable-decoder=aac_fixed \
--enable-decoder=aac_latm \
--enable-decoder=aasc \
--enable-decoder=alac \
--enable-decoder=alac_at \
--enable-decoder=flac \
--enable-decoder=gif \
--enable-decoder=h264 \
@@ -227,14 +257,12 @@ jobs:
--enable-decoder=msmpeg4v3 \
--enable-decoder=opus \
--enable-decoder=pcm_alaw \
--enable-decoder=pcm_alaw_at \
--enable-decoder=pcm_f32be \
--enable-decoder=pcm_f32le \
--enable-decoder=pcm_f64be \
--enable-decoder=pcm_f64le \
--enable-decoder=pcm_lxf \
--enable-decoder=pcm_mulaw \
--enable-decoder=pcm_mulaw_at \
--enable-decoder=pcm_s16be \
--enable-decoder=pcm_s16be_planar \
--enable-decoder=pcm_s16le \
@@ -289,7 +317,7 @@ jobs:
--enable-muxer=opus
make -j$(nproc)
sudo make install
sudo make DESTDIR="$LibrariesPath/ffmpeg-cache" install
cd ..
rm -rf ffmpeg
- name: FFmpeg install.
@@ -298,7 +326,7 @@ jobs:
#List of files from cmake/external/ffmpeg/CMakeLists.txt.
copyLib() {
mkdir -p ffmpeg/$1
yes | cp -i ffmpeg-cache/lib/$1.a ffmpeg/$1/$1.a
yes | cp -i ffmpeg-cache/usr/local/lib/$1.a ffmpeg/$1/$1.a
}
copyLib libavformat
copyLib libavcodec
@@ -306,20 +334,7 @@ jobs:
copyLib libswscale
copyLib libavutil
sudo cp -R ffmpeg-cache/. /usr/local/
- name: PortAudio.
run: |
cd $LibrariesPath
git clone https://git.assembla.com/portaudio.git
cd portaudio
git checkout 396fe4b669
./configure
make -j$(nproc)
sudo make install
cd ..
rm -rf portaudio
sudo cp -R ffmpeg-cache/. /
- name: OpenAL Soft.
run: |
@@ -327,7 +342,13 @@ jobs:
git clone -b openal-soft-1.20.1 --depth=1 $GIT/kcat/openal-soft.git
cd openal-soft/build
cmake -D LIBTYPE:STRING=STATIC ..
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DLIBTYPE:STRING=STATIC \
-DALSOFT_EXAMPLES=OFF \
-DALSOFT_TESTS=OFF \
-DALSOFT_UTILS=OFF \
-DALSOFT_CONFIG=OFF
make -j$(nproc)
sudo make install
cd -
@@ -348,28 +369,15 @@ jobs:
git clone -b OpenSSL_${OPENSSL_VER}-stable --depth=1 \
$GIT/openssl/openssl $opensslDir
cd $opensslDir
./config --prefix=$LibrariesPath/openssl-cache
./config --prefix="$OPENSSL_PREFIX"
make -j$(nproc)
sudo make install_sw
sudo make DESTDIR="$LibrariesPath/openssl-cache" install_sw
cd ..
rm -rf $opensslDir
- name: OpenSSL install.
run: |
cd $LibrariesPath
sudo mkdir -p $OPENSSL_PREFIX
sudo cp -R openssl-cache/. $OPENSSL_PREFIX/
- name: Libxkbcommon.
run: |
cd $LibrariesPath
git clone -b xkbcommon-0.8.4 --depth=1 $GIT/xkbcommon/libxkbcommon.git
cd libxkbcommon
./autogen.sh
make -j$(nproc)
sudo make install
cd ..
rm -rf libxkbcommon
sudo cp -R openssl-cache/. /
- name: Libwayland.
run: |
@@ -377,38 +385,55 @@ jobs:
git clone -b 1.16 https://gitlab.freedesktop.org/wayland/wayland
cd wayland
./autogen.sh --enable-static --disable-documentation
./autogen.sh \
--enable-static \
--disable-documentation \
--disable-dtd-validation
make -j$(nproc)
sudo make install
cd ..
rm -rf wayland
- name: Qt 5.12.5 cache.
- name: Libxkbcommon.
run: |
cd $LibrariesPath
git clone -b xkbcommon-0.8.4 --depth=1 $GIT/xkbcommon/libxkbcommon.git
cd libxkbcommon
./autogen.sh \
--disable-docs \
--disable-wayland \
--with-xkb-config-root=/usr/share/X11/xkb \
--with-x-locale-root=/usr/share/X11/locale
make -j$(nproc)
sudo make install
cd ..
rm -rf libxkbcommon
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Qt 5.12.5 build.
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qt*_5_12_8/*') }}
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
git clone -b v5.12.5 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT}
git clone -b v5.12.8 --depth=1 git://code.qt.io/qt/qt5.git qt_${QT}
cd qt_${QT}
perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg
git submodule update qtbase qtwayland qtimageformats qtsvg
perl init-repository --module-subset=qtbase,qtwayland,qtimageformats,qtsvg,qtx11extras
git submodule update qtbase qtwayland qtimageformats qtsvg qtx11extras
cd qtbase
git apply ../../patches/qtbase_${QT}.diff
cd src/plugins/platforminputcontexts
git clone $GIT/desktop-app/fcitx.git
git clone $GIT/desktop-app/hime.git
git clone $GIT/desktop-app/nimf.git
cd ../../../..
find ../../patches/qtbase_${QT} -type f -print0 | sort -z | xargs -r0 git apply
cd ..
cd qtwayland
find ../../patches/qtwayland_${QT} -type f -print0 | sort -z | xargs -r0 git apply
cd ..
./configure -prefix "$LibrariesPath/qt-cache" \
./configure -prefix "$QT_PREFIX" \
-release \
-force-debug-info \
-opensource \
-confirm-license \
-qt-zlib \
@@ -417,8 +442,6 @@ jobs:
-qt-harfbuzz \
-qt-pcre \
-qt-xcb \
-system-freetype \
-fontconfig \
-no-gtk \
-static \
-dbus-runtime \
@@ -428,14 +451,13 @@ jobs:
-nomake tests
make -j$(nproc)
sudo make install
sudo make INSTALL_ROOT="$LibrariesPath/qt-cache" install
cd ..
rm -rf qt_${QT}
- name: Qt 5.12.5 install.
- name: Qt 5.12.8 install.
run: |
cd $LibrariesPath
sudo mkdir -p $QT_PREFIX
sudo cp -R qt-cache/. $QT_PREFIX/
sudo cp -R qt-cache/. /
- name: Breakpad cache.
id: cache-breakpad
@@ -467,9 +489,9 @@ jobs:
cd ..
cd breakpad
./configure --prefix=$BreakpadCache
./configure
make -j$(nproc)
sudo make install
sudo make DESTDIR="$BreakpadCache" install
cd src
rm -r testing
git clone $GIT/google/googletest testing
@@ -486,7 +508,7 @@ jobs:
- name: Breakpad install.
run: |
cd $LibrariesPath
sudo cp -R breakpad-cache/. /usr/local/
sudo cp -R breakpad-cache/. /
mkdir -p breakpad/out/Default/
cp breakpad-cache/dump_syms breakpad/out/Default/dump_syms
@@ -499,6 +521,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
./configure.sh \
@@ -534,5 +559,5 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}/out/Debug/bin/artifact/

View File

@@ -4,11 +4,41 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-xcode.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-xcode.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/mac.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/configure.bat'
jobs:
@@ -27,9 +57,9 @@ jobs:
PREFIX: "/usr/local/macos"
MACOSX_DEPLOYMENT_TARGET: "10.12"
XZ: "xz-5.2.4"
QT: "5_12_5"
QT: "5_12_8"
OPENSSL_VER: "1_1_1"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.5"
QT_PREFIX: "/usr/local/desktop-app/Qt-5.12.8"
LIBICONV_VER: "libiconv-1.16"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
@@ -58,6 +88,7 @@ jobs:
echo $MIN_MAC >> CACHE_KEY.txt
echo $PREFIX >> CACHE_KEY.txt
echo $MANUAL_CACHING >> CACHE_KEY.txt
echo "$GITHUB_WORKSPACE" >> CACHE_KEY.txt
if [ "$AUTO_CACHING" == "1" ]; then
thisFile=$REPO_NAME/.github/workflows/mac.yml
echo `md5 -q $thisFile` >> CACHE_KEY.txt
@@ -70,14 +101,6 @@ jobs:
cd Libraries/macos
echo ::set-env name=LibrariesPath::`pwd`
- name: Range-v3.
run: |
echo "Find necessary branch from doc."
cloneRange=$(grep -A 1 "range-v3" $REPO_NAME/$DOC_PATH | sed -n 1p)
cd $LibrariesPath
echo $cloneRange
eval $cloneRange
- name: Patches.
run: |
echo "Find necessary commit from doc."
@@ -376,20 +399,20 @@ jobs:
build/gyp_crashpad.py -Dmac_deployment_target=10.10
ninja -C out/Debug
- name: Qt 5.12.5 cache.
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/qt-cache
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Use cached Qt 5.12.5.
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
- name: Use cached Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit == 'true'
run: |
cd $LibrariesPath
mv qt-cache Qt-5.12.5
mv qt-cache Qt-5.12.8
sudo mkdir -p $QT_PREFIX
sudo mv -f Qt-5.12.5 "$(dirname "$QT_PREFIX")"/
- name: Qt 5.12.5 build.
sudo mv -f Qt-5.12.8 "$(dirname "$QT_PREFIX")"/
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
run: |
cd $LibrariesPath
@@ -397,11 +420,11 @@ jobs:
git clone git://code.qt.io/qt/qt5.git qt$QT
cd qt$QT
perl init-repository --module-subset=qtbase,qtimageformats
git checkout v5.12.5
git checkout v5.12.8
git submodule update qtbase
git submodule update qtimageformats
cd qtbase
git apply ../../patches/qtbase_$QT.diff
find ../../patches/qtbase_$QT -type f -print0 | sort -z | xargs -0 git apply
cd ..
./configure \
@@ -433,6 +456,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
./configure.sh -D TDESKTOP_API_TEST=ON -D DESKTOP_APP_USE_PACKAGED=OFF $DEFINE
@@ -453,5 +479,5 @@ jobs:
if: env.UPLOAD_ARTIFACT == 'true'
name: Upload artifact.
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}/out/Debug/artifact/

35
.github/workflows/master_updater.yml vendored Normal file
View File

@@ -0,0 +1,35 @@
name: Master branch updater.
on:
release:
types: released
jobs:
updater:
runs-on: ubuntu-latest
env:
SKIP: "0"
to_branch: "master"
steps:
- uses: actions/checkout@v1
if: env.SKIP == '0'
- name: Push the code to the master branch.
if: env.SKIP == '0'
run: |
token=${{ secrets.TOKEN_FOR_MASTER_UPDATER }}
if [ -z "${token}" ]; then
echo "Token is unset. Nothing to do."
exit 0
fi
url=https://x-access-token:$token@github.com/$GITHUB_REPOSITORY
latest_tag=$(git describe --tags --abbrev=0)
echo "Latest tag: $latest_tag"
git remote set-url origin $url
git remote -v
git checkout master
git merge $latest_tag
git push origin HEAD:refs/heads/$to_branch
echo "Done!"

View File

@@ -4,11 +4,41 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/snap.yml'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/ffmpeg.diff'
- 'Telegram/Resources/uwp/**'
- 'Telegram/Resources/winrc/**'
- 'Telegram/SourceFiles/platform/win/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.bat'
- 'Telegram/Telegram.plist'
jobs:
@@ -18,8 +48,6 @@ jobs:
env:
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
MANUAL_CACHING: "3"
steps:
- name: Clone.
@@ -29,60 +57,18 @@ jobs:
- name: First set up.
run: |
# Workaround for Heroku
curl https://cli-assets.heroku.com/apt/release.key | sudo apt-key add -
# Workaround for permanent problems with third-party repository keys
sudo rm -rf /etc/apt/sources.list.d/*
sudo apt-get update
sudo apt-get install gcc-8 g++-8 -y
sudo snap install --classic snapcraft
# Workaround for snapcraft
# See https://forum.snapcraft.io/t/13258
sudo chown root:root /
md5() {
md5cache=$(md5sum $1.txt | cut -c -32)
echo ::set-env name=$1::$md5cache
}
keyFor() {
keyName="${1^^}_CACHE_KEY"
awk -v RS="" -v ORS="\n\n" '/^ '"$1"':/' snap/snapcraft.yaml > $keyName.txt
md5 $keyName
}
snapcraft --version > CACHE_KEY.txt
gcc-8 --version >> CACHE_KEY.txt
echo $MANUAL_CACHING >> CACHE_KEY.txt
md5 CACHE_KEY
keyFor cmake
keyFor ffmpeg
- name: CMake cache.
id: cache-cmake
uses: actions/cache@v1
with:
path: parts/cmake
key: ${{ runner.OS }}-cmake-${{ env.CACHE_KEY }}-${{ env.CMAKE_CACHE_KEY }}
- name: CMake build.
if: steps.cache-cmake.outputs.cache-hit != 'true'
run: sudo snapcraft build --destructive-mode cmake
- name: FFmpeg cache.
id: cache-ffmpeg
uses: actions/cache@v1
with:
path: parts/ffmpeg
key: ${{ runner.OS }}-ffmpeg-${{ env.CACHE_KEY }}-${{ env.FFMPEG_CACHE_KEY }}
- name: FFmpeg build.
if: steps.cache-ffmpeg.outputs.cache-hit != 'true'
run: sudo snapcraft build --destructive-mode ffmpeg
- name: Telegram Desktop snap build.
if: env.ONLY_CACHE == 'false'
run: sudo snapcraft --destructive-mode
run: sudo snap run snapcraft --destructive-mode
- name: Move artifact.
if: env.UPLOAD_ARTIFACT == 'true'
@@ -99,8 +85,3 @@ jobs:
with:
name: ${{ env.ARTIFACT_NAME }}
path: artifact
- name: Remove unneeded directories for cache.
run: |
sudo rm -rf parts/{cmake,ffmpeg}/{build,src,ubuntu}
sudo rm -rf parts/{cmake,ffmpeg}/state/{stage,prime}

View File

@@ -4,11 +4,46 @@ on:
push:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-msvc.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/win.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/build_ffmpeg_win.sh'
- 'Telegram/Resources/uwp/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/SourceFiles/platform/mac/**'
- 'Telegram/Telegram/**'
- 'Telegram/configure.sh'
- 'Telegram/Telegram.plist'
pull_request:
paths-ignore:
- 'docs/**'
- '*.md'
- '**.md'
- '!docs/building-msvc.md'
- 'changelog.txt'
- 'LEGAL'
- 'LICENSE'
- '.github/**'
- '!.github/workflows/win.yml'
- 'lib/xdg/**'
- 'snap/**'
- 'Telegram/build/**'
- 'Telegram/Patches/**'
- '!Telegram/Patches/build_ffmpeg_win.sh'
- 'Telegram/Resources/uwp/**'
- 'Telegram/SourceFiles/platform/linux/**'
- 'Telegram/SourceFiles/platform/mac/**'
- '!Telegram/Patches/breakpad.diff'
- 'Telegram/Telegram/**'
- 'Telegram/configure.sh'
- 'Telegram/Telegram.plist'
jobs:
@@ -24,7 +59,7 @@ jobs:
SDK: "10.0.18362.0"
VC: "call vcvars32.bat && cd Libraries"
GIT: "https://github.com"
QT: "5_12_5"
QT: "5_12_8"
OPENSSL_VER: "1_1_1"
UPLOAD_ARTIFACT: "false"
ONLY_CACHE: "false"
@@ -76,15 +111,6 @@ jobs:
run: |
choco install --no-progress -y nasm yasm jom ninja
- name: Range-v3.
shell: bash
run: |
echo "Find necessary branch from doc."
cloneRange=$(grep -A 1 "range-v3" $REPO_NAME/$DOC_PATH | sed -n 1p)
cd $LibrariesPath
echo $cloneRange
eval $cloneRange
- name: Patches.
shell: bash
run: |
@@ -263,13 +289,13 @@ jobs:
rmdir /S /Q .git
- name: Qt 5.12.5 cache.
- name: Qt 5.12.8 cache.
id: cache-qt
uses: actions/cache@v1
with:
path: ${{ env.LibrariesPath }}/Qt-5.12.5
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_5.diff') }}
- name: Configure Qt 5.12.5.
path: ${{ env.LibrariesPath }}/Qt-5.12.8
key: ${{ runner.OS }}-qt-${{ env.CACHE_KEY }}-${{ hashFiles('**/qtbase_5_12_8.diff') }}
- name: Configure Qt 5.12.8.
if: steps.cache-qt.outputs.cache-hit != 'true'
shell: cmd
run: |
@@ -278,18 +304,18 @@ jobs:
git clone git://code.qt.io/qt/qt5.git qt_%QT%
cd qt_%QT%
perl init-repository --module-subset=qtbase,qtimageformats
git checkout v5.12.5
git checkout v5.12.8
git submodule update qtbase
git submodule update qtimageformats
cd qtbase
git apply ../../patches/qtbase_%QT%.diff
for /r %%i in (..\..\patches\qtbase_%QT%\*) do git apply %%i
cd ..
SET SSL=%LibrariesPath%\openssl_1_1_1
SET LIBS=libcrypto.lib Ws2_32.lib Gdi32.lib Advapi32.lib Crypt32.lib User32.lib
configure ^
-prefix "%LibrariesPath%\Qt-5.12.5" ^
-prefix "%LibrariesPath%\Qt-5.12.8" ^
-debug ^
-force-debug-info ^
-opensource ^
@@ -304,7 +330,7 @@ jobs:
-nomake examples ^
-nomake tests ^
-platform win32-msvc
- name: Qt 5.12.5 build.
- name: Qt 5.12.8 build.
if: steps.cache-qt.outputs.cache-hit != 'true'
shell: cmd
run: |
@@ -324,6 +350,9 @@ jobs:
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
echo Define from matrix: $DEFINE
echo ::set-env name=ARTIFACT_NAME::Telegram_${{ matrix.defines }}
else
echo ::set-env name=ARTIFACT_NAME::Telegram
fi
echo "::set-env name=TDESKTOP_BUILD_DEFINE::$DEFINE"
@@ -355,5 +384,5 @@ jobs:
name: Upload artifact.
if: env.UPLOAD_ARTIFACT == 'true'
with:
name: Telegram
name: ${{ env.ARTIFACT_NAME }}
path: ${{ env.REPO_NAME }}\out\Debug\artifact\

29
.gitmodules vendored
View File

@@ -3,7 +3,7 @@
url = https://github.com/telegramdesktop/libtgvoip
[submodule "Telegram/ThirdParty/variant"]
path = Telegram/ThirdParty/variant
url = https://github.com/mapbox/variant
url = https://github.com/desktop-app/variant.git
[submodule "Telegram/ThirdParty/GSL"]
path = Telegram/ThirdParty/GSL
url = https://github.com/Microsoft/GSL.git
@@ -67,3 +67,30 @@
[submodule "Telegram/ThirdParty/hunspell"]
path = Telegram/ThirdParty/hunspell
url = https://github.com/hunspell/hunspell
[submodule "Telegram/ThirdParty/materialdecoration"]
path = Telegram/ThirdParty/materialdecoration
url = https://github.com/desktop-app/materialdecoration.git
[submodule "Telegram/ThirdParty/range-v3"]
path = Telegram/ThirdParty/range-v3
url = https://github.com/ericniebler/range-v3.git
[submodule "Telegram/ThirdParty/fcitx-qt5"]
path = Telegram/ThirdParty/fcitx-qt5
url = https://github.com/fcitx/fcitx-qt5.git
[submodule "Telegram/ThirdParty/nimf"]
path = Telegram/ThirdParty/nimf
url = https://github.com/hamonikr/nimf.git
[submodule "Telegram/ThirdParty/hime"]
path = Telegram/ThirdParty/hime
url = https://github.com/hime-ime/hime.git
[submodule "Telegram/ThirdParty/qt5ct"]
path = Telegram/ThirdParty/qt5ct
url = https://github.com/desktop-app/qt5ct.git
[submodule "Telegram/ThirdParty/lxqt-qtplugin"]
path = Telegram/ThirdParty/lxqt-qtplugin
url = https://github.com/lxqt/lxqt-qtplugin.git
[submodule "Telegram/ThirdParty/libqtxdg"]
path = Telegram/ThirdParty/libqtxdg
url = https://github.com/lxqt/libqtxdg.git
[submodule "Telegram/ThirdParty/fcitx5-qt"]
path = Telegram/ThirdParty/fcitx5-qt
url = https://github.com/fcitx/fcitx5-qt.git

View File

@@ -13,18 +13,27 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
## Supported systems
* Windows XP - Windows 10 (**not** RT)
* Mac OS X 10.8 - Mac OS X 10.15
* Mac OS X 10.6 - Mac OS X 10.7 (separate build)
* Ubuntu 12.04 - Ubuntu 19.10
* Fedora 22 - Fedora 31
* [Snappy](https://snapcraft.io/telegram-desktop)
* [Flathub](https://flathub.org/apps/details/org.telegram.desktop)
The latest version is available for
* [Windows 7 and above](https://telegram.org/dl/desktop/win) ([portable](https://telegram.org/dl/desktop/win_portable))
* [macOS 10.12 and above](https://telegram.org/dl/desktop/mac)
* [OS X 10.10 and 10.11](https://telegram.org/dl/desktop/osx)
* [Linux static build for 64 bit](https://telegram.org/dl/desktop/linux) ([32 bit](https://telegram.org/dl/desktop/linux32))
* [Snap](https://snapcraft.io/telegram-desktop)
* [Flatpak](https://flathub.org/apps/details/org.telegram.desktop)
## Old system versions
Version **1.8.15** was the last that supports older systems
* [Windows XP and Vista](https://updates.tdesktop.com/tsetup/tsetup.1.8.15.exe) ([portable](https://updates.tdesktop.com/tsetup/tportable.1.8.15.zip))
* [OS X 10.8 and 10.9](https://updates.tdesktop.com/tmac/tsetup.1.8.15.dmg)
* [OS X 10.6 and 10.7](https://updates.tdesktop.com/tmac32/tsetup32.1.8.15.dmg)
## Third-party
* Qt 5.12.5 and 5.6.2, slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
* OpenSSL 1.1.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
* Qt 5.12.8, 5.6.2 and 5.3.2 slightly patched ([LGPL](http://doc.qt.io/qt-5/lgpl.html))
* OpenSSL 1.1.1 and 1.0.1 ([OpenSSL License](https://www.openssl.org/source/license.html))
* zlib 1.2.11 ([zlib License](http://www.zlib.net/zlib_license.html))
* LZMA SDK 9.20 ([public domain](http://www.7-zip.org/sdk.html))
* liblzma ([public domain](http://tukaani.org/xz/))
@@ -39,6 +48,7 @@ The source code is published under GPLv3 with OpenSSL exception, the license is
* Mapbox Variant ([BSD License](https://github.com/mapbox/variant/blob/master/LICENSE))
* Range-v3 ([Boost License](https://github.com/ericniebler/range-v3/blob/master/LICENSE.txt))
* Open Sans font ([Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0.html))
* Vazir font ([License](https://github.com/rastikerdar/vazir-font/blob/master/LICENSE))
* Emoji alpha codes ([MIT License](https://github.com/emojione/emojione/blob/master/extras/alpha-codes/LICENSE.md))
* Catch test framework ([Boost License](https://github.com/philsquared/Catch/blob/master/LICENSE.txt))
* xxHash ([BSD License](https://github.com/Cyan4973/xxHash/blob/dev/LICENSE))

View File

@@ -67,12 +67,34 @@ generate_numbers(Telegram ${res_loc}/numbers.txt)
set_target_properties(Telegram PROPERTIES AUTOMOC ON AUTORCC ON)
if (LINUX AND NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
if (LINUX)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
desktop-app::external_dbusmenu_qt
desktop-app::external_materialdecoration
desktop-app::external_nimf_qt5
desktop-app::external_qt5ct
desktop-app::external_qt5ct_style
desktop-app::external_qt5ct_qtplugin
)
if (NOT DESKTOP_APP_DISABLE_DBUS_INTEGRATION)
# conflicts with Qt static link
if (DESKTOP_APP_USE_PACKAGED_LAZY_PLATFORMTHEMES)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_lxqt_qtplugin
)
endif()
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
desktop-app::external_dbusmenu_qt
desktop-app::external_fcitx_qt5
desktop-app::external_fcitx5_qt5
desktop-app::external_hime_qt
)
endif()
endif()
if (add_hunspell_library)
@@ -105,10 +127,6 @@ PRIVATE
desktop-app::external_openal
)
if (NOT DESKTOP_APP_USE_PACKAGED)
target_link_libraries(Telegram PRIVATE desktop-app::external_opus)
endif()
# Telegram uses long atomic types, so on some architectures libatomic is needed.
check_cxx_source_compiles("
#include <atomic>
@@ -121,11 +139,10 @@ endif()
if (DESKTOP_APP_USE_PACKAGED)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads)
find_package(Threads REQUIRED)
target_link_libraries(Telegram
PRIVATE
${CMAKE_DL_LIBS}
Threads::Threads
)
endif()
@@ -247,6 +264,9 @@ PRIVATE
calls/calls_box_controller.h
calls/calls_call.cpp
calls/calls_call.h
calls/calls_controller.cpp
calls/calls_controller.h
calls/calls_controller_tgvoip.h
calls/calls_emoji_fingerprint.cpp
calls/calls_emoji_fingerprint.h
calls/calls_instance.cpp
@@ -281,6 +301,8 @@ PRIVATE
chat_helpers/stickers_dice_pack.h
chat_helpers/stickers_list_widget.cpp
chat_helpers/stickers_list_widget.h
chat_helpers/stickers_set.cpp
chat_helpers/stickers_set.h
chat_helpers/tabbed_panel.cpp
chat_helpers/tabbed_panel.h
chat_helpers/tabbed_section.cpp
@@ -309,7 +331,6 @@ PRIVATE
core/launcher.h
core/local_url_handlers.cpp
core/local_url_handlers.h
core/media_active_cache.h
core/mime_type.cpp
core/mime_type.h
core/sandbox.cpp
@@ -335,14 +356,16 @@ PRIVATE
data/data_channel.h
data/data_channel_admins.cpp
data/data_channel_admins.h
data/data_cloud_file.cpp
data/data_cloud_file.h
data/data_cloud_themes.cpp
data/data_cloud_themes.h
data/data_countries.cpp
data/data_countries.h
data/data_document.cpp
data/data_document.h
data/data_document_good_thumbnail.cpp
data/data_document_good_thumbnail.h
data/data_document_media.cpp
data/data_document_media.h
data/data_drafts.cpp
data/data_drafts.h
data/data_folder.cpp
@@ -373,10 +396,14 @@ PRIVATE
data/data_peer_values.h
data/data_photo.cpp
data/data_photo.h
data/data_photo_media.cpp
data/data_photo_media.h
data/data_poll.cpp
data/data_poll.h
data/data_pts_waiter.cpp
data/data_pts_waiter.h
data/data_reply_preview.cpp
data/data_reply_preview.h
data/data_search_controller.cpp
data/data_search_controller.h
data/data_session.cpp
@@ -737,6 +764,7 @@ PRIVATE
mtproto/type_utils.h
overview/overview_layout.cpp
overview/overview_layout.h
overview/overview_layout_delegate.h
passport/passport_encryption.cpp
passport/passport_encryption.h
passport/passport_form_controller.cpp
@@ -779,7 +807,6 @@ PRIVATE
platform/mac/file_utilities_mac.h
platform/mac/launcher_mac.mm
platform/mac/launcher_mac.h
platform/mac/mac_iconv_helper.c
platform/mac/main_window_mac.mm
platform/mac/main_window_mac.h
platform/mac/notifications_manager_mac.mm
@@ -906,8 +933,8 @@ PRIVATE
ui/image/image.h
ui/image/image_location.cpp
ui/image/image_location.h
ui/image/image_source.cpp
ui/image/image_source.h
ui/image/image_location_factory.cpp
ui/image/image_location_factory.h
ui/widgets/continuous_sliders.cpp
ui/widgets/continuous_sliders.h
ui/widgets/discrete_sliders.cpp
@@ -1010,6 +1037,7 @@ PRIVATE
mainwindow.h
observer_peer.cpp
observer_peer.h
qt_static_plugins.cpp
settings.cpp
settings.h
)
@@ -1017,7 +1045,7 @@ PRIVATE
if (DESKTOP_APP_USE_PACKAGED)
nice_target_sources(Telegram ${src_loc} PRIVATE qt_functions.cpp)
else()
nice_target_sources(Telegram ${src_loc} PRIVATE qt_static_plugins.cpp)
nice_target_sources(Telegram ${src_loc} PRIVATE platform/mac/mac_iconv_helper.c)
endif()
nice_target_sources(Telegram ${res_loc}
@@ -1027,12 +1055,15 @@ PRIVATE
qrc/emoji_3.qrc
qrc/emoji_4.qrc
qrc/emoji_5.qrc
qrc/emoji_6.qrc
qrc/emoji_7.qrc
qrc/emoji_preview.qrc
qrc/telegram/telegram.qrc
qrc/telegram/sounds.qrc
winrc/Telegram.rc
winrc/Telegram.manifest
langs/lang.strings
langs/cloud_lang.strings
numbers.txt
)
@@ -1050,11 +1081,11 @@ if (WIN32)
# $<IF:${release},"Appending compatibility manifest.","Finalizing build.">
# )
elseif (APPLE)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_sp_media_key_tap
desktop-app::external_iconv
)
target_link_libraries(Telegram PRIVATE desktop-app::external_sp_media_key_tap)
if (NOT DESKTOP_APP_USE_PACKAGED)
target_link_libraries(Telegram PRIVATE desktop-app::external_iconv)
endif()
set(icons_path ${CMAKE_CURRENT_SOURCE_DIR}/Telegram/Images.xcassets)
set_target_properties(Telegram PROPERTIES RESOURCE ${icons_path})
@@ -1162,21 +1193,12 @@ source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/Telegram PREFIX Resources FILES ${
target_include_directories(Telegram PRIVATE ${src_loc})
if (NOT DESKTOP_APP_USE_PACKAGED)
target_include_directories(Telegram PRIVATE ${third_party_loc}/minizip)
endif()
target_compile_definitions(Telegram
PRIVATE
TDESKTOP_API_ID=${TDESKTOP_API_ID}
TDESKTOP_API_HASH=${TDESKTOP_API_HASH}
AL_ALEXT_PROTOTYPES
)
if (NOT DESKTOP_APP_USE_PACKAGED)
target_compile_definitions(Telegram PRIVATE AL_LIBTYPE_STATIC)
endif()
if (${CMAKE_GENERATOR} MATCHES "(Visual Studio|Xcode)")
set(output_folder ${CMAKE_BINARY_DIR})
elseif (DESKTOP_APP_SPECIAL_TARGET STREQUAL "")
@@ -1187,7 +1209,7 @@ endif()
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
if ((NOT disable_autoupdate OR NOT LINUX) AND NOT build_macstore AND NOT build_winstore)
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR NOT LINUX) AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_target(Updater)
@@ -1203,6 +1225,10 @@ if ((NOT disable_autoupdate OR NOT LINUX) AND NOT build_macstore AND NOT build_w
set_target_properties(Updater PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
if (WIN32 AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_link_options(Updater PRIVATE -municode)
endif()
if (LINUX)
target_link_options(Updater PRIVATE -static-libstdc++)
endif()

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 862 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 763 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 B

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -6,6 +6,11 @@ For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
"cloud_lng_badge_psa_covid" = "COVID-19";
"cloud_lng_about_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. To remove it from your chats list, right click it and select **Hide**.";
"cloud_lng_forwarded_psa_covid" = "COVID-19 Notification from {channel}";
"cloud_lng_tooltip_psa_covid" = "This message provides you with a public service announcement in relation to the ongoing COVID-19 pandemic. Learn more about this initiative at https://telegram.org/blog/coronavirus";
"cloud_lng_passport_in_ar" = "Arabic";
"cloud_lng_passport_in_az" = "Azerbaijani";
"cloud_lng_passport_in_bg" = "Bulgarian";

View File

@@ -118,6 +118,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_chat_status_online#one" = "{count} online";
"lng_chat_status_online#other" = "{count} online";
"lng_chat_status_members_online" = "{members_count}, {online_count}";
"lng_chat_status_subscribers#one" = "{count} subscriber";
"lng_chat_status_subscribers#other" = "{count} subscribers";
"lng_channel_status" = "channel";
"lng_group_status" = "group";
@@ -298,6 +300,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_notifications_position" = "Location on the screen";
"lng_settings_notifications_count" = "Notifications count";
"lng_settings_sound_notify" = "Play sound";
"lng_settings_alert_windows" = "Flash the taskbar icon";
"lng_settings_alert_mac" = "Bounce the dock icon";
"lng_settings_alert_linux" = "Draw attention to the window";
"lng_settings_badge_title" = "Badge counter";
"lng_settings_include_muted" = "Include muted chats in unread count";
"lng_settings_count_unread" = "Count unread messages";
@@ -600,6 +605,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_proxy_sponsor" = "Proxy sponsor";
"lng_proxy_sponsor_about" = "This channel is shown by your proxy server.\nTo remove this channel from your chats list,\ndisable the proxy in Telegram Settings.";
"lng_proxy_sponsor_warning" = "This proxy may display a sponsored channel in your chat list. This doesn't reveal any of your Telegram traffic.";
"lng_badge_psa_default" = "PSA";
"lng_about_psa_default" = "This message provides you with a public service announcement. To remove it from your chats list, right click it and select **Hide**.";
"lng_tooltip_psa_default" = "This message provides you with a public service announcement.";
"lng_settings_blocked_users" = "Blocked users";
"lng_settings_no_blocked_users" = "None";
@@ -764,6 +772,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_profile_common_groups#one" = "{count} group in common";
"lng_profile_common_groups#other" = "{count} groups in common";
"lng_profile_participants_section" = "Members";
"lng_profile_subscribers_section" = "Subscribers";
"lng_profile_mobile_number" = "Mobile:";
"lng_profile_username" = "Username:";
"lng_profile_link" = "Link:";
@@ -885,6 +894,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_manage_channel_info" = "Channel Info";
"lng_manage_peer_recent_actions" = "Recent Actions";
"lng_manage_peer_members" = "Members";
"lng_manage_peer_subscribers" = "Subscribers";
"lng_manage_peer_administrators" = "Administrators";
"lng_manage_peer_exceptions" = "Exceptions";
"lng_manage_peer_removed_users" = "Removed users";
@@ -1126,6 +1136,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_forwarded" = "Forwarded from {user}";
"lng_forwarded_date" = "Original: {date}";
"lng_forwarded_channel" = "Forwarded from {channel}";
"lng_forwarded_psa_default" = "Forwarded from {channel}";
"lng_forwarded_via" = "Forwarded from {user} via {inline_bot}";
"lng_forwarded_channel_via" = "Forwarded from {channel} via {inline_bot}";
"lng_forwarded_signed" = "{channel} ({user})";
@@ -1329,7 +1340,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_dialogs_skip_archive_in_search" = "Skip results from archive";
"lng_dialogs_show_archive_in_search" = "With results from archive";
"lng_about_dice" = "Send a 🎲 emoji to any chat to get a random number from Telegram.";
"lng_about_random" = "Send a {emoji} emoji to any chat to get a random number from Telegram.";
"lng_about_random_send" = "Send";
"lng_open_this_link" = "Open this link?";
"lng_open_link" = "Open";
@@ -1400,6 +1412,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_view_group" = "View group info";
"lng_context_view_channel" = "View channel info";
//"lng_context_view_feed_info" = "View feed info";
"lng_context_hide_psa" = "Hide this announcement";
"lng_context_pin_to_top" = "Pin to top";
"lng_context_unpin_from_top" = "Unpin from top";
"lng_context_mark_unread" = "Mark as unread";
@@ -1441,6 +1454,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_context_edit_msg" = "Edit";
"lng_context_forward_msg" = "Forward Message";
"lng_context_send_now_msg" = "Send now";
"lng_context_reschedule" = "Reschedule";
"lng_context_delete_msg" = "Delete Message";
"lng_context_select_msg" = "Select Message";
"lng_context_report_msg" = "Report Message";
@@ -1850,6 +1864,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_admin_log_no_results_search_text" = "No recent actions that contain '{query}' have been found.";
"lng_admin_log_no_events_title" = "No actions yet";
"lng_admin_log_no_events_text" = "There were no service actions\ntaken by the group's members\nand admins in the last 48 hours.";
"lng_admin_log_no_events_text_channel" = "There were no service actions\ntaken by the channels's admins\nin the last 48 hours.";
"lng_admin_log_empty_text" = "Empty";
"lng_admin_log_changed_title_group" = "{from} changed group name to «{title}»";
@@ -2135,6 +2150,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_export_option_size_limit" = "Size limit: {size}";
"lng_export_header_format" = "Location and format";
"lng_export_option_location" = "Download path: {path}";
"lng_export_option_format_location" = "Format: {format}, Path: {path}";
"lng_export_option_choose_format" = "Choose export format";
"lng_export_option_html" = "Human-readable HTML";
"lng_export_option_json" = "Machine-readable JSON";
"lng_export_limits" = "From: {from}, to: {till}";
@@ -2223,6 +2240,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_polls_choose_question" = "Please enter a question.";
"lng_polls_choose_answers" = "Please enter at least two options.";
"lng_polls_choose_correct" = "Please choose the correct answer.";
"lng_polls_solution_title" = "Explanation";
"lng_polls_solution_placeholder" = "Add a Comment (Optional)";
"lng_polls_solution_about" = "Users will see this comment after choosing a wrong answer, good for educational purposes.";
"lng_polls_poll_results_title" = "Poll results";
"lng_polls_quiz_results_title" = "Quiz results";
@@ -2231,6 +2251,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_polls_votes_collapse" = "Collapse";
"lng_outdated_title" = "PLEASE UPDATE YOUR OPERATING SYSTEM.";
"lng_outdated_title_bits" = "PLEASE SWITCH TO 64 BIT OPERATING SYSTEM.";
"lng_outdated_soon" = "Otherwise, Telegram Desktop will stop updating on {date}.";
"lng_outdated_now" = "So that Telegram Desktop can update to newer versions.";

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/gui">
<file alias="emoji/emoji_6.webp">../emoji/emoji_6.webp</file>
</qresource>
</RCC>

View File

@@ -0,0 +1,5 @@
<RCC>
<qresource prefix="/gui">
<file alias="emoji/emoji_7.webp">../emoji/emoji_7.webp</file>
</qresource>
</RCC>

View File

@@ -48,6 +48,7 @@
<file alias="art/logo_256_no_margin.png">../../art/logo_256_no_margin.png</file>
<file alias="art/sunrise.jpg">../../art/sunrise.jpg</file>
<file alias="art/dice_idle.tgs">../../art/dice_idle.tgs</file>
<file alias="art/dart_idle.tgs">../../art/dart_idle.tgs</file>
<file alias="day-blue.tdesktop-theme">../../day-blue.tdesktop-theme</file>
<file alias="night.tdesktop-theme">../../night.tdesktop-theme</file>
<file alias="night-green.tdesktop-theme">../../night-green.tdesktop-theme</file>

View File

@@ -71,8 +71,8 @@ inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int =
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#f4e096c3 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
inputMediaGeoLive#ce4e82fd flags:# stopped:flags.0?true geo_point:InputGeoPoint period:flags.1?int = InputMedia;
inputMediaPoll#abe9ca25 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> = InputMedia;
inputMediaDice#aeffa807 = InputMedia;
inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector<bytes> solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;
inputMediaDice#e66fbf7b emoticon:string = InputMedia;
inputChatPhotoEmpty#1ca48f57 = InputChatPhoto;
inputChatUploadedPhoto#927c55b4 file:InputFile = InputChatPhoto;
@@ -157,7 +157,7 @@ messageMediaGame#fdb19008 game:Game = MessageMedia;
messageMediaInvoice#84551347 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string = MessageMedia;
messageMediaGeoLive#7c3c2609 geo:GeoPoint period:int = MessageMedia;
messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia;
messageMediaDice#638fe46b value:int = MessageMedia;
messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia;
messageActionEmpty#b6aef7b0 = MessageAction;
messageActionChatCreate#a6638b9a title:string users:Vector<int> = MessageAction;
@@ -357,6 +357,7 @@ updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector<bytes> =
updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
updateDialogFilters#3504914f = Update;
updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -421,7 +422,7 @@ inputDocumentEmpty#72f0eaae = InputDocument;
inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument;
documentEmpty#36f8c871 id:long = Document;
document#9ba29cc1 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
document#1e87342b flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:int thumbs:flags.0?Vector<PhotoSize> video_thumbs:flags.1?Vector<VideoSize> dc_id:int attributes:Vector<DocumentAttribute> = Document;
help.support#17c6b5f6 phone_number:string user:User = help.Support;
@@ -533,7 +534,7 @@ inputStickerSetEmpty#ffb62b95 = InputStickerSet;
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet;
inputStickerSetDice#79e21a53 = InputStickerSet;
inputStickerSetDice#e67f520e emoticon:string = InputStickerSet;
stickerSet#eeb46f27 flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true animated:flags.5?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumb:flags.4?PhotoSize thumb_dc_id:flags.4?int count:int hash:int = StickerSet;
@@ -651,7 +652,7 @@ messages.botResults#947ca848 flags:# gallery:flags.0?true query_id:long next_off
exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink;
messageFwdHeader#ec338270 flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int = MessageFwdHeader;
messageFwdHeader#353a686b flags:# from_id:flags.0?int from_name:flags.5?string date:int channel_id:flags.1?int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int psa_type:flags.6?string = MessageFwdHeader;
auth.codeTypeSms#72a3158c = auth.CodeType;
auth.codeTypeCall#741cd3e3 = auth.CodeType;
@@ -692,8 +693,8 @@ contacts.topPeersDisabled#b52c939d = contacts.TopPeers;
draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage;
draftMessage#fd8e711f flags:# no_webpage:flags.1?true reply_to_msg_id:flags.0?int message:string entities:flags.3?Vector<MessageEntity> date:int = DraftMessage;
messages.featuredStickersNotModified#4ede3cf = messages.FeaturedStickers;
messages.featuredStickers#f89d88e5 hash:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers;
messages.featuredStickers#b6abc341 hash:int count:int sets:Vector<StickerSetCovered> unread:Vector<long> = messages.FeaturedStickers;
messages.recentStickersNotModified#b17f890 = messages.RecentStickers;
messages.recentStickers#22f3afb3 hash:int packs:Vector<StickerPack> stickers:Vector<Document> dates:Vector<int> = messages.RecentStickers;
@@ -912,9 +913,6 @@ fileHash#6242c773 offset:int limit:int hash:bytes = FileHash;
inputClientProxy#75588b3f address:string port:int = InputClientProxy;
help.proxyDataEmpty#e09e1fb8 expires:int = help.ProxyData;
help.proxyDataPromo#2bf7ee23 expires:int peer:Peer chats:Vector<Chat> users:Vector<User> = help.ProxyData;
help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate;
help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate;
@@ -1024,11 +1022,11 @@ help.userInfo#1eb3758 message:string entities:Vector<MessageEntity> author:strin
pollAnswer#6ca9c2e9 text:string option:bytes = PollAnswer;
poll#d5529d06 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> = Poll;
poll#86e18161 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:string answers:Vector<PollAnswer> close_period:flags.4?int close_date:flags.5?int = Poll;
pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters;
pollResults#c87024a2 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> = PollResults;
pollResults#badcc1a3 flags:# min:flags.0?true results:flags.1?Vector<PollAnswerVoters> total_voters:flags.2?int recent_voters:flags.3?Vector<int> solution:flags.4?string solution_entities:flags.4?Vector<MessageEntity> = PollResults;
chatOnlines#f041e250 onlines:int = ChatOnlines;
@@ -1140,11 +1138,16 @@ messageInteractionCounters#ad4fc9bd msg_id:int views:int forwards:int = MessageI
stats.broadcastStats#bdf78394 period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph recent_message_interactions:Vector<MessageInteractionCounters> = stats.BroadcastStats;
help.promoDataEmpty#98f6ac75 expires:int = help.PromoData;
help.promoData#8c39793f flags:# proxy:flags.0?true expires:int peer:Peer chats:Vector<Chat> users:Vector<User> psa_type:flags.1?string psa_message:flags.2?string = help.PromoData;
videoSize#435bb987 type:string location:FileLocation w:int h:int size:int = VideoSize;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector<long> query:!X = X;
initConnection#785188b8 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy query:!X = X;
initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X;
invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X;
invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X;
@@ -1382,6 +1385,7 @@ messages.getDialogFilters#f19ed96d = Vector<DialogFilter>;
messages.getSuggestedDialogFilters#a29cd42c = Vector<DialogFilterSuggested>;
messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool;
messages.updateDialogFiltersOrder#c563c1e4 order:Vector<int> = Bool;
messages.getOldFeaturedStickers#5fe7025b offset:int limit:int hash:int = messages.FeaturedStickers;
updates.getState#edd4882a = updates.State;
updates.getDifference#25939651 flags:# pts:int pts_total_limit:flags.0?int date:int qts:int = updates.Difference;
@@ -1410,7 +1414,6 @@ help.getAppChangelog#9010ef6f prev_app_version:string = Updates;
help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool;
help.getCdnConfig#52029342 = CdnConfig;
help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls;
help.getProxyData#3d7758e1 = help.ProxyData;
help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate;
help.acceptTermsOfService#ee72f79a id:DataJSON = Bool;
help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo;
@@ -1420,6 +1423,8 @@ help.getPassportConfig#c661ad08 hash:int = help.PassportConfig;
help.getSupportName#d360e72c = help.SupportName;
help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo;
help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector<MessageEntity> = help.UserInfo;
help.getPromoData#c0977421 = help.PromoData;
help.hidePromoData#1e251c95 peer:InputPeer = Bool;
channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool;
channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector<int> = messages.AffectedMessages;
@@ -1459,6 +1464,7 @@ channels.getInactiveChannels#11e831ee = messages.InactiveChats;
bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON;
bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool;
bots.setBotCommands#805d46f6 commands:Vector<BotCommand> = Bool;
payments.getPaymentForm#99f09745 msg_id:int = payments.PaymentForm;
payments.getPaymentReceipt#a092a980 msg_id:int = payments.PaymentReceipt;
@@ -1468,10 +1474,11 @@ payments.getSavedInfo#227d824b = payments.SavedInfo;
payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool;
payments.getBankCardData#2e79d779 number:string = payments.BankCardData;
stickers.createStickerSet#9bd86e6a flags:# masks:flags.0?true user_id:InputUser title:string short_name:string stickers:Vector<InputStickerSetItem> = messages.StickerSet;
stickers.createStickerSet#f1036780 flags:# masks:flags.0?true animated:flags.1?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector<InputStickerSetItem> = messages.StickerSet;
stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet;
stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet;
stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet;
stickers.setStickerSetThumb#9a364e30 stickerset:InputStickerSet thumb:InputDocument = messages.StickerSet;
phone.getCallConfig#55451fa9 = DataJSON;
phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall;
@@ -1481,6 +1488,7 @@ phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool;
phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates;
phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates;
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
@@ -1494,4 +1502,4 @@ folders.deleteFolder#1c295881 folder_id:int = Updates;
stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats;
stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph;
// LAYER 111
// LAYER 114

View File

@@ -9,7 +9,7 @@
<Identity Name="TelegramMessengerLLP.TelegramDesktop"
ProcessorArchitecture="ARCHITECTURE"
Publisher="CN=536BC709-8EE1-4478-AF22-F0F0F26FF64A"
Version="2.0.1.0" />
Version="2.1.8.0" />
<Properties>
<DisplayName>Telegram Desktop</DisplayName>
<PublisherDisplayName>Telegram FZ-LLC</PublisherDisplayName>

View File

@@ -6,7 +6,18 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
#if defined(__MINGW64__) || defined(__MINGW32__)
// MinGW-w64, MinGW
#if defined(__has_include) && __has_include(<winres.h>)
#include <winres.h>
#else
#include <afxres.h>
#include <winresrc.h>
#endif
#else
// MSVC, Windows SDK
#include <winres.h>
#endif
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -33,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,1,0
PRODUCTVERSION 2,0,1,0
FILEVERSION 2,1,8,0
PRODUCTVERSION 2,1,8,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -51,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "2.0.1.0"
VALUE "FileVersion", "2.1.8.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.0.1.0"
VALUE "ProductVersion", "2.1.8.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -6,7 +6,18 @@
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
#if defined(__MINGW64__) || defined(__MINGW32__)
// MinGW-w64, MinGW
#if defined(__has_include) && __has_include(<winres.h>)
#include <winres.h>
#else
#include <afxres.h>
#include <winresrc.h>
#endif
#else
// MSVC, Windows SDK
#include <winres.h>
#endif
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
@@ -24,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,0,1,0
PRODUCTVERSION 2,0,1,0
FILEVERSION 2,1,8,0
PRODUCTVERSION 2,1,8,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -42,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "2.0.1.0"
VALUE "FileVersion", "2.1.8.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2020"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.0.1.0"
VALUE "ProductVersion", "2.1.8.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -268,7 +268,7 @@ int main(int argc, char *argv[])
cout << "Compression start, size: " << resultSize << "\n";
QByteArray compressed, resultCheck;
#ifdef Q_OS_WIN // use Lzma SDK for win
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
const int32 hSigLen = 128, hShaLen = 20, hPropsLen = LZMA_PROPS_SIZE, hOriginalSizeLen = sizeof(int32), hSize = hSigLen + hShaLen + hPropsLen + hOriginalSizeLen; // header
compressed.resize(hSize + resultSize + 1024 * 1024); // rsa signature + sha1 + lzma props + max compressed size

View File

@@ -27,7 +27,7 @@ extern "C" {
#include <openssl/evp.h>
} // extern "C"
#ifdef Q_OS_WIN // use Lzma SDK for win
#if defined Q_OS_WIN && !defined DESKTOP_APP_USE_PACKAGED // use Lzma SDK for win
#include <LzmaLib.h>
#else
#include <lzma.h>

View File

@@ -90,7 +90,7 @@ int main(int argc, const char * argv[]) {
openLog();
pid_t procId = 0;
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO, externalUpdater = NO;
BOOL update = YES, toSettings = NO, autoStart = NO, startInTray = NO, testMode = NO, freeType = NO, externalUpdater = NO;
BOOL customWorkingDir = NO;
NSString *key = nil;
for (int i = 0; i < argc; ++i) {
@@ -116,6 +116,8 @@ int main(int argc, const char * argv[]) {
startInTray = YES;
} else if ([@"-testmode" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
testMode = YES;
} else if ([@"-freetype" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
freeType = YES;
} else if ([@"-externalupdater" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
externalUpdater = YES;
} else if ([@"-workdir_custom" isEqualToString:[NSString stringWithUTF8String:argv[i]]]) {
@@ -255,6 +257,7 @@ int main(int argc, const char * argv[]) {
if (_debug) [args addObject:@"-debug"];
if (startInTray) [args addObject:@"-startintray"];
if (testMode) [args addObject:@"-testmode"];
if (freeType) [args addObject:@"-freetype"];
if (externalUpdater) [args addObject:@"-externalupdater"];
if (autoStart) [args addObject:@"-autostart"];
if (key) {

View File

@@ -339,7 +339,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
LPWSTR *args;
int argsCount;
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false, externalupdater = false;
bool needupdate = false, autostart = false, debug = false, writeprotected = false, startintray = false, testmode = false, freetype = false, externalupdater = false;
args = CommandLineToArgvW(GetCommandLine(), &argsCount);
if (args) {
for (int i = 1; i < argsCount; ++i) {
@@ -355,6 +355,8 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
startintray = true;
} else if (equal(args[i], L"-testmode")) {
testmode = true;
} else if (equal(args[i], L"-freetype")) {
freetype = true;
} else if (equal(args[i], L"-externalupdater")) {
externalupdater = true;
} else if (equal(args[i], L"-writeprotected") && ++i < argsCount) {
@@ -427,6 +429,7 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdPara
if (debug) targs += L" -debug";
if (startintray) targs += L" -startintray";
if (testmode) targs += L" -testmode";
if (freetype) targs += L" -freetype";
if (externalupdater) targs += L" -externalupdater";
if (!customWorkingDir.empty()) {
targs += L" -workdir \"" + customWorkingDir + L"\"";

View File

@@ -21,6 +21,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "chat_helpers/message_field.h" // ConvertTextTagsToEntities.
#include "ui/text/text_entity.h" // TextWithEntities.
#include "main/main_session.h"
#include "main/main_account.h"
#include "main/main_app_config.h"
#include "mainwidget.h"
#include "apiwrap.h"
#include "app.h"
@@ -28,6 +30,26 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Api {
namespace {
void InnerFillMessagePostFlags(
const Api::SendOptions &options,
not_null<PeerData*> peer,
MTPDmessage::Flags &flags) {
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
return;
}
flags |= MTPDmessage::Flag::f_post;
// Don't display views and author of a new post when it's scheduled.
if (options.scheduled) {
return;
}
flags |= MTPDmessage::Flag::f_views;
if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
}
template <typename MediaData>
void SendExistingMedia(
Api::MessageToSend &&message,
@@ -58,15 +80,7 @@ void SendExistingMedia(
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
@@ -199,8 +213,23 @@ void SendExistingPhoto(
}
bool SendDice(Api::MessageToSend &message) {
static const auto kDiceString = QString::fromUtf8("\xF0\x9F\x8E\xB2");
if (message.textWithTags.text.midRef(0).trimmed() != kDiceString) {
const auto full = message.textWithTags.text.midRef(0).trimmed();
auto length = 0;
if (!Ui::Emoji::Find(full.data(), full.data() + full.size(), &length)
|| length != full.size()) {
return false;
}
auto &account = message.action.history->session().account();
auto &config = account.appConfig();
static const auto hardcoded = std::vector<QString>{
QString::fromUtf8("\xF0\x9F\x8E\xB2"),
QString::fromUtf8("\xF0\x9F\x8E\xAF")
};
const auto list = config.get<std::vector<QString>>(
"emojies_send_dice",
hardcoded);
const auto emoji = full.toString();
if (!ranges::contains(list, emoji)) {
return false;
}
const auto history = message.action.history;
@@ -229,15 +258,7 @@ bool SendDice(Api::MessageToSend &message) {
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = message.action.options.silent
|| (channelPost && session->data().notifySilentPosts(peer));
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
InnerFillMessagePostFlags(message.action.options, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMedia::Flag::f_silent;
}
@@ -266,7 +287,7 @@ bool SendDice(Api::MessageToSend &message) {
MTP_int(HistoryItem::NewMessageDate(
message.action.options.scheduled)),
MTP_string(),
MTP_messageMediaDice(MTP_int(0)),
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
MTPReplyMarkup(),
MTP_vector<MTPMessageEntity>(),
MTP_int(1),
@@ -284,7 +305,7 @@ bool SendDice(Api::MessageToSend &message) {
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaDice(),
MTP_inputMediaDice(MTP_string(emoji)),
MTP_string(),
MTP_long(randomId),
MTPReplyMarkup(),
@@ -303,4 +324,11 @@ bool SendDice(Api::MessageToSend &message) {
return true;
}
void FillMessagePostFlags(
const Api::SendAction &action,
not_null<PeerData*> peer,
MTPDmessage::Flags &flags) {
InnerFillMessagePostFlags(action.options, peer, flags);
}
} // namespace Api

View File

@@ -23,6 +23,11 @@ void SendExistingPhoto(
Api::MessageToSend &&message,
not_null<PhotoData*> photo);
[[nodiscard]] bool SendDice(Api::MessageToSend &message);
bool SendDice(Api::MessageToSend &message);
void FillMessagePostFlags(
const SendAction &action,
not_null<PeerData*> peer,
MTPDmessage::Flags &flags);
} // namespace Api

View File

@@ -82,6 +82,7 @@ MTPVector<MTPMessageEntity> EntitiesToMTP(
if (entity.length() <= 0) continue;
if (option == ConvertOption::SkipLocal
&& entity.type() != EntityType::Bold
//&& entity.type() != EntityType::Semibold // Not in API.
&& entity.type() != EntityType::Italic
&& entity.type() != EntityType::Underline
&& entity.type() != EntityType::StrikeOut

View File

@@ -88,8 +88,8 @@ constexpr auto kMaxUsersPerInvite = 100;
// that was added to this chat.
constexpr auto kForwardMessagesOnAdd = 100;
constexpr auto kProxyPromotionInterval = TimeId(60 * 60);
constexpr auto kProxyPromotionMinDelay = TimeId(10);
constexpr auto kTopPromotionInterval = TimeId(60 * 60);
constexpr auto kTopPromotionMinDelay = TimeId(10);
constexpr auto kSmallDelayMs = 5;
constexpr auto kUnreadMentionsPreloadIfLess = 5;
constexpr auto kUnreadMentionsFirstRequestLimit = 10;
@@ -237,7 +237,7 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
, _dialogsLoadState(std::make_unique<DialogsLoadState>())
, _fileLoader(std::make_unique<TaskQueue>(kFileLoaderQueueStopTimeout))
//, _feedReadTimer([=] { readFeeds(); }) // #feed
, _proxyPromotionTimer([=] { refreshProxyPromotion(); })
, _topPromotionTimer([=] { refreshTopPromotion(); })
, _updateNotifySettingsTimer([=] { sendNotifySettingsUpdates(); })
, _selfDestruct(std::make_unique<Api::SelfDestruct>(this))
, _sensitiveContent(std::make_unique<Api::SensitiveContent>(this)) {
@@ -288,13 +288,13 @@ void ApiWrap::requestChangelog(
).send();
}
void ApiWrap::refreshProxyPromotion() {
void ApiWrap::refreshTopPromotion() {
const auto now = base::unixtime::now();
const auto next = (_proxyPromotionNextRequestTime != 0)
? _proxyPromotionNextRequestTime
const auto next = (_topPromotionNextRequestTime != 0)
? _topPromotionNextRequestTime
: now;
if (_proxyPromotionRequestId) {
getProxyPromotionDelayed(now, next);
if (_topPromotionRequestId) {
getTopPromotionDelayed(now, next);
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
@@ -307,51 +307,51 @@ void ApiWrap::refreshProxyPromotion() {
}
return { proxy.host, proxy.port };
}();
if (_proxyPromotionKey == key && now < next) {
getProxyPromotionDelayed(now, next);
if (_topPromotionKey == key && now < next) {
getTopPromotionDelayed(now, next);
return;
}
_proxyPromotionKey = key;
if (key.first.isEmpty() || !key.second) {
proxyPromotionDone(MTP_help_proxyDataEmpty(
MTP_int(base::unixtime::now() + kProxyPromotionInterval)));
return;
}
_proxyPromotionRequestId = request(MTPhelp_GetProxyData(
)).done([=](const MTPhelp_ProxyData &result) {
_proxyPromotionRequestId = 0;
proxyPromotionDone(result);
_topPromotionKey = key;
_topPromotionRequestId = request(MTPhelp_GetPromoData(
)).done([=](const MTPhelp_PromoData &result) {
_topPromotionRequestId = 0;
topPromotionDone(result);
}).fail([=](const RPCError &error) {
_proxyPromotionRequestId = 0;
_topPromotionRequestId = 0;
const auto now = base::unixtime::now();
const auto next = _proxyPromotionNextRequestTime = now
+ kProxyPromotionInterval;
if (!_proxyPromotionTimer.isActive()) {
getProxyPromotionDelayed(now, next);
const auto next = _topPromotionNextRequestTime = now
+ kTopPromotionInterval;
if (!_topPromotionTimer.isActive()) {
getTopPromotionDelayed(now, next);
}
}).send();
}
void ApiWrap::getProxyPromotionDelayed(TimeId now, TimeId next) {
_proxyPromotionTimer.callOnce(std::min(
std::max(next - now, kProxyPromotionMinDelay),
kProxyPromotionInterval) * crl::time(1000));
void ApiWrap::getTopPromotionDelayed(TimeId now, TimeId next) {
_topPromotionTimer.callOnce(std::min(
std::max(next - now, kTopPromotionMinDelay),
kTopPromotionInterval) * crl::time(1000));
};
void ApiWrap::proxyPromotionDone(const MTPhelp_ProxyData &proxy) {
_proxyPromotionNextRequestTime = proxy.match([&](const auto &data) {
void ApiWrap::topPromotionDone(const MTPhelp_PromoData &proxy) {
_topPromotionNextRequestTime = proxy.match([&](const auto &data) {
return data.vexpires().v;
});
getProxyPromotionDelayed(base::unixtime::now(), _proxyPromotionNextRequestTime);
getTopPromotionDelayed(
base::unixtime::now(),
_topPromotionNextRequestTime);
proxy.match([&](const MTPDhelp_proxyDataEmpty &data) {
_session->data().setProxyPromoted(nullptr);
}, [&](const MTPDhelp_proxyDataPromo &data) {
proxy.match([&](const MTPDhelp_promoDataEmpty &data) {
_session->data().setTopPromoted(nullptr, QString(), QString());
}, [&](const MTPDhelp_promoData &data) {
_session->data().processChats(data.vchats());
_session->data().processUsers(data.vusers());
const auto peerId = peerFromMTP(data.vpeer());
const auto peer = _session->data().peer(peerId);
_session->data().setProxyPromoted(peer);
_session->data().setTopPromoted(
peer,
data.vpsa_type().value_or_empty(),
data.vpsa_message().value_or_empty());
if (const auto history = _session->data().historyLoaded(peer)) {
history->owner().histories().requestDialogEntry(history);
}
@@ -1865,7 +1865,7 @@ void ApiWrap::saveStickerSets(
auto &sets = _session->data().stickerSetsRef();
_stickersOrder = localOrder;
for_const (auto removedSetId, localRemoved) {
for (const auto removedSetId : localRemoved) {
if (removedSetId == Stickers::CloudRecentSetId) {
if (sets.remove(Stickers::CloudRecentSetId) != 0) {
writeCloudRecent = true;
@@ -1890,16 +1890,17 @@ void ApiWrap::saveStickerSets(
auto it = sets.find(removedSetId);
if (it != sets.cend()) {
const auto set = it->second.get();
for (auto i = recent.begin(); i != recent.cend();) {
if (it->stickers.indexOf(i->first) >= 0) {
if (set->stickers.indexOf(i->first) >= 0) {
i = recent.erase(i);
writeRecent = true;
} else {
++i;
}
}
if (!(it->flags & MTPDstickerSet::Flag::f_archived)) {
MTPInputStickerSet setId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
const auto setId = set->mtpInput();
auto requestId = request(MTPmessages_UninstallStickerSet(setId)).done([this](const MTPBool &result, mtpRequestId requestId) {
stickerSetDisenabled(requestId);
@@ -1909,60 +1910,69 @@ void ApiWrap::saveStickerSets(
_stickerSetDisenableRequests.insert(requestId);
int removeIndex = _session->data().stickerSetsOrder().indexOf(it->id);
int removeIndex = _session->data().stickerSetsOrder().indexOf(set->id);
if (removeIndex >= 0) _session->data().stickerSetsOrderRef().removeAt(removeIndex);
if (!(it->flags & MTPDstickerSet_ClientFlag::f_featured)
&& !(it->flags & MTPDstickerSet_ClientFlag::f_special)) {
if (!(set->flags & MTPDstickerSet_ClientFlag::f_featured)
&& !(set->flags & MTPDstickerSet_ClientFlag::f_special)) {
sets.erase(it);
} else {
if (it->flags & MTPDstickerSet::Flag::f_archived) {
if (set->flags & MTPDstickerSet::Flag::f_archived) {
writeArchived = true;
}
it->flags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet::Flag::f_archived);
it->installDate = TimeId(0);
set->flags &= ~(MTPDstickerSet::Flag::f_installed_date | MTPDstickerSet::Flag::f_archived);
set->installDate = TimeId(0);
}
}
}
}
// Clear all installed flags, set only for sets from order.
for (auto &set : sets) {
if (!(set.flags & MTPDstickerSet::Flag::f_archived)) {
set.flags &= ~MTPDstickerSet::Flag::f_installed_date;
for (auto &[id, set] : sets) {
if (!(set->flags & MTPDstickerSet::Flag::f_archived)) {
set->flags &= ~MTPDstickerSet::Flag::f_installed_date;
}
}
auto &order = _session->data().stickerSetsOrderRef();
order.clear();
for_const (auto setId, _stickersOrder) {
for (const auto setId : std::as_const(_stickersOrder)) {
auto it = sets.find(setId);
if (it != sets.cend()) {
if ((it->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(it->id)) {
MTPInputStickerSet mtpSetId = (it->id && it->access) ? MTP_inputStickerSetID(MTP_long(it->id), MTP_long(it->access)) : MTP_inputStickerSetShortName(MTP_string(it->shortName));
const auto set = it->second.get();
if ((set->flags & MTPDstickerSet::Flag::f_archived) && !localRemoved.contains(set->id)) {
const auto mtpSetId = set->mtpInput();
auto requestId = request(MTPmessages_InstallStickerSet(mtpSetId, MTP_boolFalse())).done([this](const MTPmessages_StickerSetInstallResult &result, mtpRequestId requestId) {
const auto requestId = request(MTPmessages_InstallStickerSet(
mtpSetId,
MTP_boolFalse()
)).done([=](
const MTPmessages_StickerSetInstallResult &result,
mtpRequestId requestId) {
stickerSetDisenabled(requestId);
}).fail([this](const RPCError &error, mtpRequestId requestId) {
}).fail([=](
const RPCError &error,
mtpRequestId requestId) {
stickerSetDisenabled(requestId);
}).afterDelay(kSmallDelayMs).send();
_stickerSetDisenableRequests.insert(requestId);
it->flags &= ~MTPDstickerSet::Flag::f_archived;
set->flags &= ~MTPDstickerSet::Flag::f_archived;
writeArchived = true;
}
order.push_back(setId);
it->flags |= MTPDstickerSet::Flag::f_installed_date;
if (!it->installDate) {
it->installDate = base::unixtime::now();
set->flags |= MTPDstickerSet::Flag::f_installed_date;
if (!set->installDate) {
set->installDate = base::unixtime::now();
}
}
}
for (auto it = sets.begin(); it != sets.cend();) {
if ((it->flags & MTPDstickerSet_ClientFlag::f_featured)
|| (it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)
|| (it->flags & MTPDstickerSet_ClientFlag::f_special)) {
const auto set = it->second.get();
if ((set->flags & MTPDstickerSet_ClientFlag::f_featured)
|| (set->flags & MTPDstickerSet::Flag::f_installed_date)
|| (set->flags & MTPDstickerSet::Flag::f_archived)
|| (set->flags & MTPDstickerSet_ClientFlag::f_special)) {
++it;
} else {
it = sets.erase(it);
@@ -3334,14 +3344,14 @@ void ApiWrap::readFeaturedSetDelayed(uint64 setId) {
}
void ApiWrap::readFeaturedSets() {
auto &sets = _session->data().stickerSetsRef();
const auto &sets = _session->data().stickerSets();
auto count = _session->data().featuredStickerSetsUnreadCount();
QVector<MTPlong> wrappedIds;
wrappedIds.reserve(_featuredSetsRead.size());
for (auto setId : _featuredSetsRead) {
auto it = sets.find(setId);
for (const auto setId : _featuredSetsRead) {
const auto it = sets.find(setId);
if (it != sets.cend()) {
it->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
it->second->flags &= ~MTPDstickerSet_ClientFlag::f_unread;
wrappedIds.append(MTP_long(setId));
if (count) {
--count;
@@ -4328,15 +4338,7 @@ void ApiWrap::forwardMessages(
auto flags = MTPDmessage::Flags(0);
auto clientFlags = MTPDmessage_ClientFlags();
auto sendFlags = MTPmessages_ForwardMessages::Flags(0);
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_ForwardMessages::Flag::f_silent;
}
@@ -4489,15 +4491,7 @@ void ApiWrap::sendSharedContact(
if (action.replyTo) {
flags |= MTPDmessage::Flag::f_reply_to_msg_id;
}
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
} else {
flags |= MTPDmessage::Flag::f_from_id;
}
FillMessagePostFlags(action, peer, flags);
if (action.options.scheduled) {
flags |= MTPDmessage::Flag::f_from_scheduled;
} else {
@@ -4874,15 +4868,7 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
const auto channelPost = peer->isChannel() && !peer->isMegagroup();
const auto silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendMessage::Flag::f_silent;
}
@@ -5019,15 +5005,7 @@ void ApiWrap::sendInlineResult(
bool channelPost = peer->isChannel() && !peer->isMegagroup();
bool silentPost = action.options.silent
|| (channelPost && _session->data().notifySilentPosts(peer));
if (channelPost) {
flags |= MTPDmessage::Flag::f_views;
flags |= MTPDmessage::Flag::f_post;
}
if (!channelPost) {
flags |= MTPDmessage::Flag::f_from_id;
} else if (peer->asChannel()->addsSignature()) {
flags |= MTPDmessage::Flag::f_post_author;
}
FillMessagePostFlags(action, peer, flags);
if (silentPost) {
sendFlags |= MTPmessages_SendInlineBotResult::Flag::f_silent;
}
@@ -5754,16 +5732,6 @@ void ApiWrap::createPoll(
if (action.options.scheduled) {
sendFlags |= MTPmessages_SendMedia::Flag::f_schedule_date;
}
const auto inputFlags = data.quiz()
? MTPDinputMediaPoll::Flag::f_correct_answers
: MTPDinputMediaPoll::Flag(0);
auto correct = QVector<MTPbytes>();
for (const auto &answer : data.answers) {
if (answer.correct) {
correct.push_back(MTP_bytes(answer.option));
}
}
auto &histories = history->owner().histories();
const auto requestType = Data::Histories::RequestType::Send;
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
@@ -5772,10 +5740,7 @@ void ApiWrap::createPoll(
MTP_flags(sendFlags),
peer->input,
MTP_int(replyTo),
MTP_inputMediaPoll(
MTP_flags(inputFlags),
PollDataToMTP(&data),
MTP_vector<MTPbytes>(correct)),
PollDataToInputMedia(&data),
MTP_string(),
MTP_long(rand_value<uint64>()),
MTPReplyMarkup(),
@@ -5852,25 +5817,12 @@ void ApiWrap::closePoll(not_null<HistoryItem*> item) {
if (!poll) {
return;
}
const auto inputFlags = poll->quiz()
? MTPDinputMediaPoll::Flag::f_correct_answers
: MTPDinputMediaPoll::Flag(0);
auto correct = QVector<MTPbytes>();
for (const auto &answer : poll->answers) {
if (answer.correct) {
correct.push_back(MTP_bytes(answer.option));
}
}
const auto requestId = request(MTPmessages_EditMessage(
MTP_flags(MTPmessages_EditMessage::Flag::f_media),
item->history()->peer->input,
MTP_int(item->id),
MTPstring(),
MTP_inputMediaPoll(
MTP_flags(inputFlags),
PollDataToMTP(poll, true),
MTP_vector<MTPbytes>(correct)),
PollDataToInputMedia(poll, true),
MTPReplyMarkup(),
MTPVector<MTPMessageEntity>(),
MTP_int(0) // schedule_date
@@ -5883,6 +5835,43 @@ void ApiWrap::closePoll(not_null<HistoryItem*> item) {
_pollCloseRequestIds.emplace(itemId, requestId);
}
void ApiWrap::rescheduleMessage(
not_null<HistoryItem*> item,
Api::SendOptions options) {
const auto text = item->originalText().text;
const auto sentEntities = Api::EntitiesToMTP(
item->originalText().entities,
Api::ConvertOption::SkipLocal);
const auto media = item->media();
const auto emptyFlag = MTPmessages_EditMessage::Flag(0);
const auto flags = MTPmessages_EditMessage::Flag::f_schedule_date
| (!text.isEmpty()
? MTPmessages_EditMessage::Flag::f_message
: emptyFlag)
| ((!media || !media->webpage())
? MTPmessages_EditMessage::Flag::f_no_webpage
: emptyFlag)
| (!sentEntities.v.isEmpty()
? MTPmessages_EditMessage::Flag::f_entities
: emptyFlag);
const auto id = _session->data().scheduledMessages().lookupId(item);
request(MTPmessages_EditMessage(
MTP_flags(flags),
item->history()->peer->input,
MTP_int(id),
MTP_string(text),
MTPInputMedia(),
MTPReplyMarkup(),
sentEntities,
MTP_int(options.scheduled)
)).done([=](const MTPUpdates &result) {
applyUpdates(result);
}).fail([](const RPCError &error) {
}).send();
}
void ApiWrap::reloadPollResults(not_null<HistoryItem*> item) {
const auto itemId = item->fullId();
if (!IsServerMsgId(item->id)

View File

@@ -12,7 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/flat_map.h"
#include "base/flat_set.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "data/data_messages.h"
class TaskQueue;
@@ -208,7 +208,7 @@ public:
void requestChangelog(
const QString &sinceVersion,
Fn<void(const MTPUpdates &result)> callback);
void refreshProxyPromotion();
void refreshTopPromotion();
void requestDeepLinkInfo(
const QString &path,
Fn<void(const MTPDhelp_deepLinkInfo &result)> callback);
@@ -476,6 +476,10 @@ public:
void closePoll(not_null<HistoryItem*> item);
void reloadPollResults(not_null<HistoryItem*> item);
void rescheduleMessage(
not_null<HistoryItem*> item,
Api::SendOptions options);
private:
struct MessageDataRequest {
using Callbacks = QList<RequestMessageDataCallback>;
@@ -646,8 +650,8 @@ private:
//void readFeeds(); // #feed
void getProxyPromotionDelayed(TimeId now, TimeId next);
void proxyPromotionDone(const MTPhelp_ProxyData &proxy);
void getTopPromotionDelayed(TimeId now, TimeId next);
void topPromotionDone(const MTPhelp_PromoData &proxy);
void sendNotifySettingsUpdates();
@@ -787,10 +791,10 @@ private:
//base::flat_map<not_null<Data::Feed*>, mtpRequestId> _feedReadRequests;
//base::Timer _feedReadTimer;
mtpRequestId _proxyPromotionRequestId = 0;
std::pair<QString, uint32> _proxyPromotionKey;
TimeId _proxyPromotionNextRequestTime = TimeId(0);
base::Timer _proxyPromotionTimer;
mtpRequestId _topPromotionRequestId = 0;
std::pair<QString, uint32> _topPromotionKey;
TimeId _topPromotionNextRequestTime = TimeId(0);
base::Timer _topPromotionTimer;
base::flat_set<not_null<const PeerData*>> _updateNotifySettingsPeers;
base::Timer _updateNotifySettingsTimer;

View File

@@ -57,7 +57,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace {
constexpr auto kImageAreaLimit = 6'016 * 3'384;
constexpr auto kImageAreaLimit = 12'032 * 9'024;
App::LaunchState _launchState = App::Launched;
@@ -227,8 +227,6 @@ namespace App {
clearCorners();
Data::clearGlobalStructures();
Images::ClearAll();
}
void hoveredItem(HistoryView::Element *item) {
@@ -322,6 +320,9 @@ namespace App {
}
QImage readImage(QByteArray data, QByteArray *format, bool opaque, bool *animated) {
if (data.isEmpty()) {
return QImage();
}
QByteArray tmpFormat;
QImage result;
QBuffer buffer(&data);

View File

@@ -11,23 +11,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/rect_part.h"
enum class ImageRoundRadius;
class MainWindow;
class MainWidget;
class HistoryItem;
class History;
namespace HistoryView {
class Element;
} // namespace HistoryView
namespace Media {
namespace Clip {
class Reader;
} // namespace Clip
} // namespace Media
using HistoryItemsMap = base::flat_set<not_null<HistoryItem*>>;
using GifItems = QHash<Media::Clip::Reader*, HistoryItem*>;
enum RoundCorners : int {
SmallMaskCorners = 0x00, // for images
LargeMaskCorners,

View File

@@ -14,7 +14,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/labels.h"
#include "ui/text/text_utilities.h"
#include "platform/platform_file_utilities.h"
#include "core/file_utilities.h"
#include "base/platform/base_platform_info.h"
#include "core/click_handler_types.h"
#include "core/update_checker.h"
@@ -23,7 +23,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtGui/QGuiApplication>
#include <QtGui/QClipboard>
#include <QtGui/QDesktopServices>
namespace {
@@ -109,7 +108,7 @@ void AboutBox::showVersionHistory() {
Ui::show(Box<InformBox>("The link to the current private alpha version of Telegram Desktop was copied to the clipboard."));
} else {
QDesktopServices::openUrl(qsl("https://desktop.telegram.org/changelog"));
File::OpenUrl(qsl("https://desktop.telegram.org/changelog"));
}
}

View File

@@ -34,6 +34,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_chat.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "data/data_cloud_file.h"
#include "mainwidget.h"
#include "mainwindow.h"
#include "apiwrap.h"
@@ -222,6 +223,7 @@ private:
}
not_null<PeerData*> peer;
mutable std::shared_ptr<Data::CloudImageView> userpic;
Ui::Text::String name, status;
};
void paintChat(Painter &p, const ChatRow &row, bool selected) const;
@@ -1438,7 +1440,7 @@ void RevokePublicLinkBox::resizeEvent(QResizeEvent *e) {
void RevokePublicLinkBox::Inner::paintChat(Painter &p, const ChatRow &row, bool selected) const {
auto peer = row.peer;
peer->paintUserpicLeft(p, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
peer->paintUserpicLeft(p, row.userpic, st::contactsPadding.left(), st::contactsPadding.top(), width(), st::contactsPhotoSize);
p.setPen(st::contactsNameFg);

View File

@@ -16,6 +16,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "mtproto/sender.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "boxes/background_preview_box.h"
#include "boxes/confirm_box.h"
#include "app.h"
@@ -53,28 +55,33 @@ QImage TakeMiddleSample(QImage original, QSize size) {
} // namespace
class BackgroundBox::Inner : public Ui::RpWidget, private base::Subscriber {
class BackgroundBox::Inner final
: public Ui::RpWidget
, private base::Subscriber {
public:
Inner(
QWidget *parent,
not_null<Main::Session*> session);
~Inner();
rpl::producer<Data::WallPaper> chooseEvents() const;
rpl::producer<Data::WallPaper> removeRequests() const;
void removePaper(const Data::WallPaper &data);
~Inner();
protected:
private:
void paintEvent(QPaintEvent *e) override;
void mouseMoveEvent(QMouseEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
private:
void visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) override;
struct Paper {
Data::WallPaper data;
mutable std::shared_ptr<Data::DocumentMedia> dataMedia;
mutable QPixmap thumbnail;
};
struct Selected {
@@ -252,11 +259,19 @@ void BackgroundBox::Inner::resizeToContentAndPreload() {
const auto rows = (count / kBackgroundsInRow)
+ (count % kBackgroundsInRow ? 1 : 0);
resize(st::boxWideWidth, rows * (st::backgroundSize.height() + st::backgroundPadding) + st::backgroundPadding);
resize(
st::boxWideWidth,
(rows * (st::backgroundSize.height() + st::backgroundPadding)
+ st::backgroundPadding));
const auto preload = kBackgroundsInRow * 3;
for (const auto &paper : _papers | ranges::view::take(preload)) {
paper.data.loadThumbnail();
if (!paper.data.localThumbnail() && !paper.dataMedia) {
if (const auto document = paper.data.document()) {
paper.dataMedia = document->createMediaView();
paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
}
}
}
update();
}
@@ -292,15 +307,24 @@ void BackgroundBox::Inner::paintEvent(QPaintEvent *e) {
void BackgroundBox::Inner::validatePaperThumbnail(
const Paper &paper) const {
Expects(paper.data.thumbnail() != nullptr);
const auto thumbnail = paper.data.thumbnail();
if (!paper.thumbnail.isNull()) {
return;
} else if (!thumbnail->loaded()) {
thumbnail->load(paper.data.fileOrigin());
return;
}
const auto localThumbnail = paper.data.localThumbnail();
if (!localThumbnail) {
if (const auto document = paper.data.document()) {
if (!paper.dataMedia) {
paper.dataMedia = document->createMediaView();
paper.dataMedia->thumbnailWanted(paper.data.fileOrigin());
}
}
if (!paper.dataMedia || !paper.dataMedia->thumbnail()) {
return;
}
}
const auto thumbnail = localThumbnail
? localThumbnail
: paper.dataMedia->thumbnail();
auto original = thumbnail->original();
if (paper.data.isPattern()) {
const auto color = *paper.data.backgroundColor();
@@ -428,7 +452,14 @@ void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (base::get_if<DeleteSelected>(&_over)) {
_backgroundRemove.fire_copy(_papers[index].data);
} else if (base::get_if<Selected>(&_over)) {
_backgroundChosen.fire_copy(_papers[index].data);
auto &paper = _papers[index];
if (!paper.dataMedia) {
if (const auto document = paper.data.document()) {
// Keep it alive while it is on the screen.
paper.dataMedia = document->createMediaView();
}
}
_backgroundChosen.fire_copy(paper.data);
}
}
} else if (!_over.has_value()) {
@@ -436,6 +467,22 @@ void BackgroundBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
}
}
void BackgroundBox::Inner::visibleTopBottomUpdated(
int visibleTop,
int visibleBottom) {
for (auto i = 0, count = int(_papers.size()); i != count; ++i) {
const auto row = (i / kBackgroundsInRow);
const auto height = st::backgroundSize.height();
const auto skip = st::backgroundPadding;
const auto top = skip + row * (height + skip);
const auto bottom = top + height;
if ((bottom <= visibleTop || top >= visibleBottom)
&& !_papers[i].thumbnail.isNull()) {
_papers[i].dataMedia = nullptr;
}
}
}
rpl::producer<Data::WallPaper> BackgroundBox::Inner::chooseEvents() const {
return _backgroundChosen.events();
}

View File

@@ -22,6 +22,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_user.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_file_origin.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
#include "boxes/background_preview_box.h"
@@ -410,7 +412,11 @@ BackgroundPreviewBox::BackgroundPreviewBox(
tr::lng_background_text2(tr::now),
true))
, _paper(paper)
, _media(_paper.document() ? _paper.document()->createMediaView() : nullptr)
, _radial([=](crl::time now) { radialAnimationCallback(now); }) {
if (_media) {
_media->thumbnailWanted(_paper.fileOrigin());
}
subscribe(_session->downloaderTaskFinished(), [=] { update(); });
}
@@ -428,12 +434,14 @@ void BackgroundPreviewBox::prepare() {
}
updateServiceBg(_paper.backgroundColor());
_paper.loadThumbnail();
_paper.loadDocument();
if (_paper.document() && _paper.document()->loading()) {
_radial.start(_paper.document()->progress());
const auto document = _paper.document();
if (document && document->loading()) {
_radial.start(_media->progress());
}
if (_paper.thumbnail() && !_paper.isPattern()) {
if (!_paper.isPattern()
&& (_paper.localThumbnail()
|| (document && document->hasThumbnail()))) {
createBlurCheckbox();
}
setScaledFromThumb();
@@ -634,7 +642,7 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
const auto document = _paper.document();
const auto wasAnimating = _radial.animating();
const auto updated = _radial.update(
document->progress(),
_media->progress(),
!document->loading(),
now);
if ((wasAnimating || _radial.animating())
@@ -645,8 +653,13 @@ void BackgroundPreviewBox::radialAnimationCallback(crl::time now) {
}
bool BackgroundPreviewBox::setScaledFromThumb() {
const auto thumbnail = _paper.thumbnail();
if (!thumbnail || !thumbnail->loaded()) {
const auto localThumbnail = _paper.localThumbnail();
const auto thumbnail = localThumbnail
? localThumbnail
: _media
? _media->thumbnail()
: nullptr;
if (!thumbnail) {
return false;
} else if (_paper.isPattern() && _paper.document() != nullptr) {
return false;
@@ -710,7 +723,7 @@ void BackgroundPreviewBox::checkLoadedDocument() {
const auto document = _paper.document();
if (!_full.isNull()
|| !document
|| !document->loaded(DocumentData::FilePathResolve::Checked)
|| !_media->loaded(true)
|| _generating) {
return;
}
@@ -744,7 +757,7 @@ void BackgroundPreviewBox::checkLoadedDocument() {
});
};
_generating = Data::ReadImageAsync(
document,
_media.get(),
Window::Theme::ProcessBackgroundImage,
generateCallback);
}

View File

@@ -15,6 +15,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
@@ -71,6 +75,7 @@ private:
AdminLog::OwnedItem _text1;
AdminLog::OwnedItem _text2;
Data::WallPaper _paper;
std::shared_ptr<Data::DocumentMedia> _media;
QImage _full;
QPixmap _scaled, _blurred, _fadeOutThumbnail;
Ui::Animations::Simple _fadeIn;

View File

@@ -252,7 +252,7 @@ peerListBox: PeerList(defaultPeerList) {
}
localStorageRowHeight: 50px;
localStorageRowPadding: margins(23px, 5px, 20px, 5px);
localStorageRowPadding: margins(22px, 5px, 20px, 5px);
localStorageRowTitle: FlatLabel(defaultFlatLabel) {
textFg: windowBoldFg;
maxHeight: 20px;
@@ -275,11 +275,11 @@ localStorageClear: defaultBoxButton;
localStorageLimitLabel: LabelSimple(defaultLabelSimple) {
font: boxTextFont;
}
localStorageLimitLabelMargin: margins(23px, 10px, 20px, 5px);
localStorageLimitLabelMargin: margins(22px, 10px, 20px, 5px);
localStorageLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
}
localStorageLimitMargin: margins(23px, 5px, 20px, 10px);
localStorageLimitMargin: margins(22px, 5px, 20px, 10px);
shareRowsTop: 12px;
shareRowHeight: 108px;
@@ -340,7 +340,7 @@ sessionsHeight: 350px;
sessionHeight: 70px;
sessionCurrentPadding: margins(0px, 7px, 0px, 4px);
sessionCurrentHeight: 118px;
sessionPadding: margins(23px, 10px, 23px, 0px);
sessionPadding: margins(22px, 10px, 22px, 0px);
sessionNameFont: msgNameFont;
sessionNameFg: boxTextFg;
sessionWhenFont: msgDateFont;
@@ -428,7 +428,7 @@ aboutLabel: FlatLabel(defaultFlatLabel) {
}
autoDownloadTopDelta: 10px;
autoDownloadTitlePosition: point(23px, 18px);
autoDownloadTitlePosition: point(22px, 18px);
autoDownloadTitleFont: font(15px semibold);
autoDownloadLimitSlider: MediaSlider(defaultContinuousSlider) {
seekSize: size(15px, 15px);
@@ -562,7 +562,7 @@ passcodeTextStyle: TextStyle(defaultTextStyle) {
lineHeight: 20px;
}
usernamePadding: margins(23px, 6px, 21px, 12px);
usernamePadding: margins(22px, 6px, 21px, 12px);
usernameSkip: 49px;
usernameTextStyle: TextStyle(boxTextStyle, passcodeTextStyle) {
}
@@ -642,9 +642,9 @@ rightsToggle: Toggle(defaultToggle) {
}
rightsDividerHeight: boxDividerHeight;
rightsDividerMargin: margins(0px, 0px, 0px, 20px);
rightsHeaderMargin: margins(23px, 0px, 23px, 8px);
rightsToggleMargin: margins(23px, 8px, 23px, 8px);
rightsAboutMargin: margins(23px, 8px, 23px, 8px);
rightsHeaderMargin: margins(22px, 0px, 22px, 8px);
rightsToggleMargin: margins(22px, 8px, 22px, 8px);
rightsAboutMargin: margins(22px, 8px, 22px, 8px);
rightsPhotoButton: UserpicButton(defaultUserpicButton) {
size: size(60px, 60px);
photoSize: 60px;
@@ -773,8 +773,8 @@ markdownLinkFieldPadding: margins(22px, 0px, 22px, 10px);
termsContent: FlatLabel(defaultFlatLabel) {
minWidth: 285px;
}
termsPadding: margins(23px, 4px, 16px, 16px);
termsAgePadding: margins(23px, 16px, 16px, 0px);
termsPadding: margins(22px, 4px, 16px, 16px);
termsAgePadding: margins(22px, 16px, 16px, 0px);
themesSmallSkip: 10px;
themesBackgroundSize: 120px;
@@ -800,7 +800,7 @@ themesMenuPosition: point(-2px, 25px);
createPollField: InputField(defaultInputField) {
font: boxTextFont;
textMargins: margins(0px, 0px, 0px, 0px);
textMargins: margins(0px, 4px, 0px, 4px);
textAlign: align(left);
heightMin: 36px;
heightMax: 86px;
@@ -822,6 +822,11 @@ createPollOptionField: InputField(createPollField) {
placeholderMargins: margins(2px, 0px, 2px, 0px);
heightMax: 68px;
}
createPollSolutionField: InputField(createPollField) {
textMargins: margins(0px, 4px, 0px, 4px);
border: 1px;
borderActive: 2px;
}
createPollLimitLabel: FlatLabel(defaultFlatLabel) {
minWidth: 274px;
align: align(topleft);
@@ -855,7 +860,7 @@ createPollWarning: FlatLabel(defaultFlatLabel) {
}
}
createPollWarningPosition: point(16px, 6px);
createPollCheckboxMargin: margins(23px, 10px, 23px, 10px);
createPollCheckboxMargin: margins(22px, 10px, 22px, 10px);
createPollFieldTitlePadding: margins(22px, 7px, 10px, 6px);
callSettingsButton: IconButton {
@@ -910,7 +915,7 @@ blockUserConfirmation: FlatLabel(boxLabel) {
minWidth: 240px;
}
transferCheckWidth: 300px;
transferCheckWidth: 320px;
slowmodeLabelsMargin: margins(0px, 5px, 0px, 0px);
slowmodeLabel: LabelSimple(defaultLabelSimple) {

View File

@@ -599,4 +599,19 @@ void CalendarBox::keyPressEvent(QKeyEvent *e) {
}
}
void CalendarBox::wheelEvent(QWheelEvent *e) {
// Only a mouse wheel is accepted.
constexpr auto step = static_cast<int>(QWheelEvent::DefaultDeltasPerStep);
const auto delta = e->angleDelta().y();
if (std::abs(delta) != step) {
return;
}
if (delta < 0) {
goPreviousMonth();
} else {
goNextMonth();
}
}
CalendarBox::~CalendarBox() = default;

View File

@@ -46,6 +46,7 @@ protected:
void keyPressEvent(QKeyEvent *e) override;
void resizeEvent(QResizeEvent *e) override;
void wheelEvent(QWheelEvent *e) override;
private:
void monthChanged(QDate month);

View File

@@ -19,6 +19,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "mtproto/facade.h"
#include "app.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"

View File

@@ -32,6 +32,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_file_origin.h"
#include "data/data_histories.h"
#include "data/data_photo_media.h"
#include "base/unixtime.h"
#include "main/main_session.h"
#include "observer_peer.h"
@@ -894,12 +895,12 @@ ConfirmInviteBox::ConfirmInviteBox(
const auto photo = _session->data().processPhoto(data.vphoto());
if (!photo->isNull()) {
_photo = photo->thumbnail();
if (!_photo->loaded()) {
_photo = photo->createMediaView();
_photo->wanted(Data::PhotoSize::Small, Data::FileOrigin());
if (!_photo->image(Data::PhotoSize::Small)) {
subscribe(_session->downloaderTaskFinished(), [=] {
update();
});
_photo->load(Data::FileOrigin());
}
} else {
_photoEmpty = std::make_unique<Ui::EmptyUserpic>(
@@ -908,19 +909,20 @@ ConfirmInviteBox::ConfirmInviteBox(
}
}
std::vector<not_null<UserData*>> ConfirmInviteBox::GetParticipants(
not_null<Main::Session*> session,
const MTPDchatInvite &data) {
auto ConfirmInviteBox::GetParticipants(
not_null<Main::Session*> session,
const MTPDchatInvite &data)
-> std::vector<Participant> {
const auto participants = data.vparticipants();
if (!participants) {
return {};
}
const auto &v = participants->v;
auto result = std::vector<not_null<UserData*>>();
auto result = std::vector<Participant>();
result.reserve(v.size());
for (const auto &participant : v) {
if (const auto user = session->data().processUser(participant)) {
result.push_back(user);
result.push_back(Participant{ user });
}
}
return result;
@@ -945,12 +947,12 @@ void ConfirmInviteBox::prepare() {
_userWidth = (st::confirmInviteUserPhotoSize + 2 * padding);
int sumWidth = _participants.size() * _userWidth;
int left = (st::boxWideWidth - sumWidth) / 2;
for (const auto user : _participants) {
for (const auto &participant : _participants) {
auto name = new Ui::FlatLabel(this, st::confirmInviteUserName);
name->resizeToWidth(st::confirmInviteUserPhotoSize + padding);
name->setText(user->firstName.isEmpty()
? user->name
: user->firstName);
name->setText(participant.user->firstName.isEmpty()
? participant.user->name
: participant.user->firstName);
name->moveToLeft(left + (padding / 2), st::confirmInviteUserNameTop);
left += _userWidth;
}
@@ -972,14 +974,15 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
Painter p(this);
if (_photo) {
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
_photo->pixCircled(
Data::FileOrigin(),
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
} else {
if (const auto image = _photo->image(Data::PhotoSize::Small)) {
p.drawPixmap(
(width() - st::confirmInvitePhotoSize) / 2,
st::confirmInvitePhotoTop,
image->pixCircled(
st::confirmInvitePhotoSize,
st::confirmInvitePhotoSize));
}
} else if (_photoEmpty) {
_photoEmpty->paint(
p,
(width() - st::confirmInvitePhotoSize) / 2,
@@ -990,9 +993,10 @@ void ConfirmInviteBox::paintEvent(QPaintEvent *e) {
int sumWidth = _participants.size() * _userWidth;
int left = (width() - sumWidth) / 2;
for_const (auto user, _participants) {
user->paintUserpicLeft(
for (auto &participant : _participants) {
participant.user->paintUserpicLeft(
p,
participant.userpic,
left + (_userWidth - st::confirmInviteUserPhotoSize) / 2,
st::confirmInviteUserPhotoTop,
width(),

View File

@@ -10,6 +10,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "mtproto/mtproto_rpc_sender.h"
namespace Data {
class PhotoMedia;
class CloudImageView;
} // namespace Data
namespace Main {
class Session;
} // namespace Main
@@ -221,7 +226,11 @@ protected:
void paintEvent(QPaintEvent *e) override;
private:
static std::vector<not_null<UserData*>> GetParticipants(
struct Participant {
not_null<UserData*> user;
std::shared_ptr<Data::CloudImageView> userpic;
};
static std::vector<Participant> GetParticipants(
not_null<Main::Session*> session,
const MTPDchatInvite &data);
@@ -230,9 +239,9 @@ private:
Fn<void()> _submit;
object_ptr<Ui::FlatLabel> _title;
object_ptr<Ui::FlatLabel> _status;
Image *_photo = nullptr;
std::shared_ptr<Data::PhotoMedia> _photo;
std::unique_ptr<Ui::EmptyUserpic> _photoEmpty;
std::vector<not_null<UserData*>> _participants;
std::vector<Participant> _participants;
bool _isChannel = false;
int _userWidth = 0;

View File

@@ -38,6 +38,8 @@ constexpr auto kMaxOptionsCount = PollData::kMaxOptions;
constexpr auto kOptionLimit = 100;
constexpr auto kWarnQuestionLimit = 80;
constexpr auto kWarnOptionLimit = 30;
constexpr auto kSolutionLimit = 200;
constexpr auto kWarnSolutionLimit = 60;
constexpr auto kErrorLimit = 99;
class Options {
@@ -59,6 +61,7 @@ public:
[[nodiscard]] rpl::producer<int> usedCount() const;
[[nodiscard]] rpl::producer<not_null<QWidget*>> scrollToWidget() const;
[[nodiscard]] rpl::producer<> backspaceInFront() const;
[[nodiscard]] rpl::producer<> tabbed() const;
private:
class Option {
@@ -80,7 +83,7 @@ private:
void show(anim::type animated);
void destroy(FnMut<void()> done);
[[nodisacrd]] bool hasShadow() const;
[[nodiscard]] bool hasShadow() const;
void createShadow();
void destroyShadow();
@@ -146,6 +149,7 @@ private:
bool _hasCorrect = false;
rpl::event_stream<not_null<QWidget*>> _scrollToWidget;
rpl::event_stream<> _backspaceInFront;
rpl::event_stream<> _tabbed;
};
@@ -217,6 +221,7 @@ Options::Option::Option(
InitField(outer, _field, session);
_field->setMaxLength(kOptionLimit + kErrorLimit);
_field->show();
_field->customTab(true);
_wrap->hide(anim::type::instant);
@@ -497,6 +502,10 @@ rpl::producer<> Options::backspaceInFront() const {
return _backspaceInFront.events();
}
rpl::producer<> Options::tabbed() const {
return _tabbed.events();
}
void Options::Option::show(anim::type animated) {
_wrap->show(animated);
}
@@ -647,6 +656,14 @@ void Options::addEmptyOption() {
QObject::connect(field, &Ui::InputField::focused, [=] {
_scrollToWidget.fire_copy(field);
});
QObject::connect(field, &Ui::InputField::tabbed, [=] {
const auto index = findField(field);
if (index + 1 < _list.size()) {
_list[index + 1]->setFocus();
} else {
_tabbed.fire({});
}
});
base::install_event_filter(field, [=](not_null<QEvent*> event) {
if (event->type() != QEvent::KeyPress
|| !field->getLastText().isEmpty()) {
@@ -768,6 +785,7 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
InitField(getDelegate()->outerContainer(), question, _session);
question->setMaxLength(kQuestionLimit + kErrorLimit);
question->setSubmitSettings(Ui::InputField::SubmitSettings::Both);
question->customTab(true);
const auto warning = CreateWarningLabel(
container,
@@ -794,6 +812,69 @@ not_null<Ui::InputField*> CreatePollBox::setupQuestion(
return question;
}
not_null<Ui::InputField*> CreatePollBox::setupSolution(
not_null<Ui::VerticalLayout*> container,
rpl::producer<bool> shown) {
using namespace Settings;
const auto outer = container->add(
object_ptr<Ui::SlideWrap<Ui::VerticalLayout>>(
container,
object_ptr<Ui::VerticalLayout>(container))
)->setDuration(0)->toggleOn(std::move(shown));
const auto inner = outer->entity();
AddSkip(inner);
AddSubsectionTitle(inner, tr::lng_polls_solution_title());
const auto solution = inner->add(
object_ptr<Ui::InputField>(
inner,
st::createPollSolutionField,
Ui::InputField::Mode::MultiLine,
tr::lng_polls_solution_placeholder()),
st::createPollFieldPadding);
InitField(getDelegate()->outerContainer(), solution, _session);
solution->setMaxLength(kSolutionLimit + kErrorLimit);
solution->setInstantReplaces(Ui::InstantReplaces::Default());
solution->setInstantReplacesEnabled(
_session->settings().replaceEmojiValue());
solution->setMarkdownReplacesEnabled(rpl::single(true));
solution->setEditLinkCallback(
DefaultEditLinkCallback(_session, solution));
solution->customTab(true);
const auto warning = CreateWarningLabel(
inner,
solution,
kSolutionLimit,
kWarnSolutionLimit);
rpl::combine(
solution->geometryValue(),
warning->sizeValue()
) | rpl::start_with_next([=](QRect geometry, QSize label) {
warning->moveToLeft(
(inner->width()
- label.width()
- st::createPollWarningPosition.x()),
(geometry.y()
- st::createPollFieldPadding.top()
- st::settingsSubsectionTitlePadding.bottom()
- st::settingsSubsectionTitle.style.font->height
+ st::settingsSubsectionTitle.style.font->ascent
- st::createPollWarning.style.font->ascent),
geometry.width());
}, warning->lifetime());
inner->add(
object_ptr<Ui::FlatLabel>(
inner,
tr::lng_polls_solution_about(),
st::boxDividerLabel),
st::createPollFieldTitlePadding);
return solution;
}
object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
using namespace Settings;
@@ -836,6 +917,10 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
st::boxDividerLabel),
st::createPollLimitPadding));
connect(question, &Ui::InputField::tabbed, [=] {
options->focusFirst();
});
AddSkip(container);
AddSubsectionTitle(container, tr::lng_polls_create_settings());
@@ -866,6 +951,24 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
(_chosen & PollData::Flag::Quiz),
st::defaultCheckbox),
st::createPollCheckboxMargin);
const auto solution = setupSolution(
container,
rpl::single(quiz->checked()) | rpl::then(quiz->checkedChanges()));
options->tabbed(
) | rpl::start_with_next([=] {
if (quiz->checked()) {
solution->setFocus();
} else {
question->setFocus();
}
}, question->lifetime());
connect(solution, &Ui::InputField::tabbed, [=] {
question->setFocus();
});
quiz->setDisabled(_disabled & PollData::Flag::Quiz);
if (multiple) {
multiple->setDisabled((_disabled & PollData::Flag::MultiChoice)
@@ -911,6 +1014,13 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
auto result = PollData(&_session->data(), id);
result.question = question->getLastText().trimmed();
result.answers = options->toPollAnswers();
const auto solutionWithTags = quiz->checked()
? solution->getTextWithAppliedMarkdown()
: TextWithTags();
result.solution = TextWithEntities{
solutionWithTags.text,
TextUtilities::ConvertTextTagsToEntities(solutionWithTags.tags)
};
const auto publicVotes = (anonymous && !anonymous->checked());
const auto multiChoice = (multiple && multiple->checked());
result.setFlags(Flag(0)
@@ -937,6 +1047,12 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
} else {
*error &= ~Error::Correct;
}
if (quiz->checked()
&& solution->getLastText().trimmed().size() > kSolutionLimit) {
*error |= Error::Solution;
} else {
*error &= ~Error::Solution;
}
};
const auto showError = [=](const QString &text) {
Ui::Toast::Show(text);
@@ -951,6 +1067,8 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
options->focusFirst();
} else if (*error & Error::Correct) {
showError(tr::lng_polls_choose_correct(tr::now));
} else if (*error & Error::Solution) {
solution->showError();
} else if (!*error) {
_submitRequests.fire({ collectResult(), sendOptions });
}

View File

@@ -36,7 +36,7 @@ public:
PollData::Flags disabled,
Api::SendType sendType);
rpl::producer<Result> submitRequests() const;
[[nodiscard]] rpl::producer<Result> submitRequests() const;
void submitFailed(const QString &error);
void setInnerFocus() override;
@@ -50,13 +50,17 @@ private:
Options = 0x02,
Correct = 0x04,
Other = 0x08,
Solution = 0x10,
};
friend constexpr inline bool is_flag_type(Error) { return true; }
using Errors = base::flags<Error>;
object_ptr<Ui::RpWidget> setupContent();
not_null<Ui::InputField*> setupQuestion(
[[nodiscard]] object_ptr<Ui::RpWidget> setupContent();
[[nodiscard]] not_null<Ui::InputField*> setupQuestion(
not_null<Ui::VerticalLayout*> container);
[[nodiscard]] not_null<Ui::InputField*> setupSolution(
not_null<Ui::VerticalLayout*> container,
rpl::producer<bool> shown);
const not_null<Main::Session*> _session;
const PollData::Flags _chosen = PollData::Flags();

View File

@@ -22,12 +22,19 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_photo.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "data/data_streaming.h"
#include "data/data_file_origin.h"
#include "data/data_photo_media.h"
#include "data/data_document_media.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "layout.h"
#include "media/clip/media_clip_reader.h"
#include "media/streaming/media_streaming_instance.h"
#include "media/streaming/media_streaming_player.h"
#include "media/streaming/media_streaming_document.h"
#include "media/streaming/media_streaming_loader_local.h"
#include "storage/localimageloader.h"
#include "storage/storage_media_prepare.h"
#include "ui/image/image.h"
#include "ui/widgets/input_fields.h"
@@ -46,6 +53,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtCore/QMimeData>
namespace {
using namespace ::Media::Streaming;
using Data::PhotoSize;
} // namespace
EditCaptionBox::EditCaptionBox(
QWidget*,
not_null<Window::SessionController*> controller,
@@ -60,32 +74,46 @@ EditCaptionBox::EditCaptionBox(
QSize dimensions;
auto image = (Image*)nullptr;
DocumentData *doc = nullptr;
const auto media = item->media();
if (const auto photo = media->photo()) {
_photoMedia = photo->createMediaView();
_photoMedia->wanted(PhotoSize::Large, _msgId);
image = _photoMedia->image(PhotoSize::Large);
if (!image) {
image = _photoMedia->image(PhotoSize::Thumbnail);
if (!image) {
image = _photoMedia->image(PhotoSize::Small);
if (!image) {
image = _photoMedia->thumbnailInline();
}
}
}
dimensions = _photoMedia->size(PhotoSize::Large);
_photo = true;
dimensions = QSize(photo->width(), photo->height());
image = photo->large();
} else if (const auto document = media->document()) {
image = document->thumbnail();
_documentMedia = document->createMediaView();
_documentMedia->thumbnailWanted(_msgId);
image = _documentMedia->thumbnail();
dimensions = image
? image->size()
: document->dimensions;
if (document->isAnimation()) {
_gifw = document->dimensions.width();
_gifh = document->dimensions.height();
_gifw = style::ConvertScale(document->dimensions.width());
_gifh = style::ConvertScale(document->dimensions.height());
_animated = true;
} else if (document->isVideoFile()) {
_animated = true;
} else {
_doc = true;
}
doc = document;
}
const auto editData = PrepareEditText(item);
if (!_animated && (dimensions.isEmpty() || doc || !image)) {
if (!_animated
&& (dimensions.isEmpty()
|| _documentMedia
|| (!_photoMedia && !image))) {
if (!image) {
_thumbw = 0;
} else {
@@ -104,7 +132,7 @@ EditCaptionBox::EditCaptionBox(
| Images::Option::RoundedBottomLeft
| Images::Option::RoundedBottomRight;
_thumb = App::pixmapFromImageInPlace(Images::prepare(
image->pix(_msgId).toImage(),
image->original(),
_thumbw * cIntRetinaFactor(),
0,
options,
@@ -113,19 +141,21 @@ EditCaptionBox::EditCaptionBox(
};
}
if (doc) {
const auto nameString = doc->isVoiceMessage()
if (_documentMedia) {
const auto document = _documentMedia->owner();
const auto nameString = document->isVoiceMessage()
? tr::lng_media_audio(tr::now)
: doc->composeNameString();
setName(nameString, doc->size);
_isImage = doc->isImage();
_isAudio = (doc->isVoiceMessage() || doc->isAudioFile());
: document->composeNameString();
setName(nameString, document->size);
_isImage = document->isImage();
_isAudio = document->isVoiceMessage()
|| document->isAudioFile();
}
if (_refreshThumbnail) {
_refreshThumbnail();
}
} else {
if (!image) {
if (!image && !_photoMedia) {
image = Image::BlankMedia();
}
auto maxW = 0, maxH = 0;
@@ -150,24 +180,34 @@ EditCaptionBox::EditCaptionBox(
const auto options = Images::Option::Smooth
| Images::Option::Blurred;
_thumb = image->pixNoCache(
_msgId,
maxW * cIntRetinaFactor(),
maxH * cIntRetinaFactor(),
options,
maxW,
maxH);
};
prepareGifPreview(doc);
prepareStreamedPreview();
} else {
maxW = dimensions.width();
maxH = dimensions.height();
_thumbnailImage = image;
_refreshThumbnail = [=] {
_thumb = image->pixNoCache(
_msgId,
const auto photo = _photoMedia
? _photoMedia->image(Data::PhotoSize::Large)
: nullptr;
const auto use = photo
? photo
: _thumbnailImage
? _thumbnailImage
: Image::BlankMedia().get();
const auto options = Images::Option::Smooth
| ((_photoMedia && !photo)
? Images::Option::Blurred
: Images::Option(0));
_thumb = use->pixNoCache(
maxW * cIntRetinaFactor(),
maxH * cIntRetinaFactor(),
Images::Option::Smooth,
options,
maxW,
maxH);
};
@@ -205,7 +245,7 @@ EditCaptionBox::EditCaptionBox(
thumbX = (st::boxWideWidth - thumbWidth) / 2;
};
if (doc && doc->isAnimation()) {
if (_documentMedia && _documentMedia->owner()->isAnimation()) {
resizeDimensions(_gifw, _gifh, _gifx);
}
limitH = std::min(st::confirmMaxHeight, _gifh ? _gifh : INT_MAX);
@@ -237,22 +277,36 @@ EditCaptionBox::EditCaptionBox(
}
Assert(_animated || _photo || _doc);
_thumbnailImageLoaded = _thumbnailImage
? _thumbnailImage->loaded()
_thumbnailImageLoaded = _photoMedia
? (_photoMedia->image(Data::PhotoSize::Large) != nullptr)
: _thumbnailImage
? true
: _documentMedia
? !_documentMedia->owner()->hasThumbnail()
: true;
subscribe(_controller->session().downloaderTaskFinished(), [=] {
if (!_thumbnailImageLoaded
&& _thumbnailImage
&& _thumbnailImage->loaded()) {
_thumbnailImageLoaded = true;
_refreshThumbnail();
update();
}
if (doc && doc->isAnimation() && doc->loaded() && !_gifPreview) {
prepareGifPreview(doc);
}
});
if (!_thumbnailImageLoaded) {
subscribe(_controller->session().downloaderTaskFinished(), [=] {
if (_thumbnailImageLoaded) {
return;
} else if (!_thumbnailImage
&& _photoMedia
&& _photoMedia->image(PhotoSize::Large)) {
_thumbnailImage = _photoMedia->image(PhotoSize::Large);
} else if (!_thumbnailImage
&& _documentMedia
&& _documentMedia->owner()->hasThumbnail()) {
_thumbnailImage = _documentMedia->thumbnail();
}
if (_thumbnailImage) {
_thumbnailImageLoaded = !_photoMedia
|| _photoMedia->image(PhotoSize::Large);
if (_thumbnailImageLoaded) {
_refreshThumbnail();
update();
}
}
});
}
_field.create(
this,
st::confirmCaptionArea,
@@ -287,6 +341,8 @@ EditCaptionBox::EditCaptionBox(
}, _wayWrap->lifetime());
}
EditCaptionBox::~EditCaptionBox() = default;
void EditCaptionBox::emojiFilterForGeometry(not_null<QEvent*> event) {
const auto type = event->type();
if (type == QEvent::Move || type == QEvent::Resize) {
@@ -305,74 +361,86 @@ void EditCaptionBox::updateEmojiPanelGeometry() {
local.x() + _emojiToggle->width() * 3);
}
void EditCaptionBox::prepareGifPreview(DocumentData* document) {
void EditCaptionBox::prepareStreamedPreview() {
const auto isListEmpty = _preparedList.files.empty();
if (_gifPreview) {
if (_streamed) {
return;
} else if (!document && isListEmpty) {
} else if (!_documentMedia && isListEmpty) {
return;
}
const auto callback = [=](Media::Clip::Notification notification) {
clipCallback(notification);
};
if (document && document->isAnimation() && document->loaded()) {
_gifPreview = Media::Clip::MakeReader(
document,
_msgId,
callback);
const auto document = _documentMedia
? _documentMedia->owner().get()
: nullptr;
if (document && document->isAnimation()) {
setupStreamedPreview(
document->owner().streaming().sharedDocument(
document,
_msgId));
} else if (!isListEmpty) {
const auto file = &_preparedList.files.front();
if (file->path.isEmpty()) {
_gifPreview = Media::Clip::MakeReader(
file->content,
callback);
} else {
_gifPreview = Media::Clip::MakeReader(
file->path,
callback);
}
auto loader = file->path.isEmpty()
? MakeBytesLoader(file->content)
: MakeFileLoader(file->path);
setupStreamedPreview(std::make_shared<Document>(std::move(loader)));
}
if (_gifPreview) _gifPreview->setAutoplay();
}
void EditCaptionBox::clipCallback(Media::Clip::Notification notification) {
using namespace Media::Clip;
switch (notification) {
case NotificationReinit: {
if (_gifPreview && _gifPreview->state() == State::Error) {
_gifPreview.setBad();
}
void EditCaptionBox::setupStreamedPreview(std::shared_ptr<Document> shared) {
if (!shared) {
return;
}
_streamed = std::make_unique<Instance>(
std::move(shared),
[=] { update(); });
_streamed->lockPlayer();
_streamed->player().updates(
) | rpl::start_with_next_error([=](Update &&update) {
handleStreamingUpdate(std::move(update));
}, [=](Error &&error) {
handleStreamingError(std::move(error));
}, _streamed->lifetime());
if (_gifPreview && _gifPreview->ready() && !_gifPreview->started()) {
const auto calculateGifDimensions = [&]() {
const auto scaled = QSize(
_gifPreview->width(),
_gifPreview->height()).scaled(
st::sendMediaPreviewSize * cIntRetinaFactor(),
st::confirmMaxHeight * cIntRetinaFactor(),
Qt::KeepAspectRatio);
_thumbw = _gifw = scaled.width();
_thumbh = _gifh = scaled.height();
_thumbx = _gifx = (st::boxWideWidth - _gifw) / 2;
updateBoxSize();
};
// If gif file is not mp4,
// Its dimension values will be known only after reading.
if (_gifw <= 0 || _gifh <= 0) {
calculateGifDimensions();
}
const auto s = QSize(_gifw, _gifh);
_gifPreview->start(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None);
}
if (_streamed->ready()) {
streamingReady(base::duplicate(_streamed->info()));
}
checkStreamedIsStarted();
}
update();
} break;
void EditCaptionBox::handleStreamingUpdate(Update &&update) {
update.data.match([&](Information &update) {
streamingReady(std::move(update));
}, [&](const PreloadedVideo &update) {
}, [&](const UpdateVideo &update) {
this->update();
}, [&](const PreloadedAudio &update) {
}, [&](const UpdateAudio &update) {
}, [&](const WaitingForData &update) {
}, [&](MutedByOther) {
}, [&](Finished) {
});
}
case NotificationRepaint: {
if (_gifPreview && !_gifPreview->currentDisplayed()) {
update();
}
} break;
void EditCaptionBox::handleStreamingError(Error &&error) {
}
void EditCaptionBox::streamingReady(Information &&info) {
const auto calculateGifDimensions = [&]() {
const auto scaled = QSize(
info.video.size.width(),
info.video.size.height()
).scaled(
st::sendMediaPreviewSize * cIntRetinaFactor(),
st::confirmMaxHeight * cIntRetinaFactor(),
Qt::KeepAspectRatio);
_thumbw = _gifw = scaled.width();
_thumbh = _gifh = scaled.height();
_thumbx = _gifx = (st::boxWideWidth - _gifw) / 2;
updateBoxSize();
};
// If gif file is not mp4,
// Its dimension values will be known only after reading.
if (_gifw <= 0 || _gifh <= 0) {
calculateGifDimensions();
}
}
@@ -390,7 +458,7 @@ void EditCaptionBox::updateEditPreview() {
_animated = false;
_photo = false;
_doc = false;
_gifPreview = nullptr;
_streamed = nullptr;
_thumbw = _thumbh = _thumbx = 0;
_gifw = _gifh = _gifx = 0;
@@ -469,7 +537,7 @@ void EditCaptionBox::updateEditPreview() {
_gifw = _thumbw;
_gifh = _thumbh;
_gifx = _thumbx;
prepareGifPreview();
prepareStreamedPreview();
}
}
updateEditMediaButton();
@@ -548,18 +616,10 @@ void EditCaptionBox::prepare() {
if (action == Ui::InputField::MimeAction::Check) {
if (!data->hasText() && !_isAllowedEditMedia) {
return false;
}
if (data->hasImage()) {
const auto image = qvariant_cast<QImage>(data->imageData());
if (!image.isNull()) {
return true;
}
}
if (const auto urls = data->urls(); !urls.empty()) {
if (ranges::find_if(
urls,
[](const QUrl &url) { return !url.isLocalFile(); }
) == urls.end()) {
} else if (data->hasImage()) {
return true;
} else if (const auto urls = data->urls(); !urls.empty()) {
if (ranges::all_of(urls, &QUrl::isLocalFile)) {
return true;
}
}
@@ -692,6 +752,31 @@ int EditCaptionBox::errorTopSkip() const {
return (st::defaultBox.buttonPadding.top() / 2);
}
void EditCaptionBox::checkStreamedIsStarted() {
if (!_streamed) {
return;
}
if (_streamed->paused()) {
_streamed->resume();
}
if (!_streamed->active() && !_streamed->failed()) {
startStreamedPlayer();
}
}
void EditCaptionBox::startStreamedPlayer() {
auto options = ::Media::Streaming::PlaybackOptions();
options.audioId = _documentMedia
? AudioMsgId(_documentMedia->owner(), _msgId)
: AudioMsgId();
options.waitForMarkAsShown = true;
//if (!_streamed->withSound) {
options.mode = ::Media::Streaming::Mode::Video;
options.loop = true;
//}
_streamed->play(options);
}
void EditCaptionBox::paintEvent(QPaintEvent *e) {
BoxContent::paintEvent(e);
@@ -705,16 +790,27 @@ void EditCaptionBox::paintEvent(QPaintEvent *e) {
if (_thumbx + _thumbw < width() - st::boxPhotoPadding.right()) {
p.fillRect(_thumbx + _thumbw, st::boxPhotoPadding.top(), width() - st::boxPhotoPadding.right() - _thumbx - _thumbw, th, st::confirmBg);
}
if (_gifPreview && _gifPreview->started()) {
checkStreamedIsStarted();
if (_streamed
&& _streamed->player().ready()
&& !_streamed->player().videoSize().isEmpty()) {
const auto s = QSize(_gifw, _gifh);
const auto paused = _controller->isGifPausedAtLeastFor(Window::GifPauseReason::Layer);
const auto frame = _gifPreview->current(s.width(), s.height(), s.width(), s.height(), ImageRoundRadius::None, RectPart::None, paused ? 0 : crl::now());
p.drawPixmap(_gifx, st::boxPhotoPadding.top(), frame);
auto request = ::Media::Streaming::FrameRequest();
request.outer = s * cIntRetinaFactor();
request.resize = s * cIntRetinaFactor();
p.drawImage(
QRect(_gifx, st::boxPhotoPadding.top(), _gifw, _gifh),
_streamed->frame(request));
if (!paused) {
_streamed->markFrameShown();
}
} else {
const auto offset = _gifh ? ((_gifh - _thumbh) / 2) : 0;
p.drawPixmap(_thumbx, st::boxPhotoPadding.top() + offset, _thumb);
}
if (_animated && !_gifPreview) {
if (_animated && !_streamed) {
QRect inner(_thumbx + (_thumbw - st::msgFileSize) / 2, st::boxPhotoPadding.top() + (th - st::msgFileSize) / 2, st::msgFileSize, st::msgFileSize);
p.setPen(Qt::NoPen);
p.setBrush(st::msgDateImgBg);

View File

@@ -10,9 +10,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "storage/storage_media_prepare.h"
#include "ui/wrap/slide_wrap.h"
#include "media/clip/media_clip_reader.h"
#include "mtproto/mtproto_rpc_sender.h"
class Image;
namespace ChatHelpers {
class TabbedPanel;
} // namespace ChatHelpers
@@ -23,6 +24,8 @@ class SessionController;
namespace Data {
class Media;
class PhotoMedia;
class DocumentMedia;
} // namespace Data
namespace Ui {
@@ -36,6 +39,16 @@ namespace Window {
class SessionController;
} // namespace Window
namespace Media {
namespace Streaming {
class Instance;
class Document;
struct Update;
enum class Error;
struct Information;
} // namespace Streaming
} // namespace Media
class EditCaptionBox
: public Ui::BoxContent
, public RPCSender
@@ -45,6 +58,7 @@ public:
QWidget*,
not_null<Window::SessionController*> controller,
not_null<HistoryItem*> item);
~EditCaptionBox();
protected:
void prepare() override;
@@ -56,8 +70,14 @@ protected:
private:
void updateBoxSize();
void prepareGifPreview(DocumentData* document = nullptr);
void clipCallback(Media::Clip::Notification notification);
void prepareStreamedPreview();
void checkStreamedIsStarted();
void setupStreamedPreview(
std::shared_ptr<::Media::Streaming::Document> shared);
void handleStreamingUpdate(::Media::Streaming::Update &&update);
void handleStreamingError(::Media::Streaming::Error &&error);
void streamingReady(::Media::Streaming::Information &&info);
void startStreamedPlayer();
void setupEmojiPanel();
void updateEmojiPanelGeometry();
@@ -86,6 +106,8 @@ private:
not_null<Window::SessionController*> _controller;
FullMsgId _msgId;
std::shared_ptr<Data::PhotoMedia> _photoMedia;
std::shared_ptr<Data::DocumentMedia> _documentMedia;
Image *_thumbnailImage = nullptr;
bool _thumbnailImageLoaded = false;
Fn<void()> _refreshThumbnail;
@@ -94,7 +116,7 @@ private:
bool _doc = false;
QPixmap _thumb;
Media::Clip::ReaderPointer _gifPreview;
std::unique_ptr<::Media::Streaming::Instance> _streamed;
object_ptr<Ui::InputField> _field = { nullptr };
object_ptr<Ui::EmojiButton> _emojiToggle = { nullptr };

View File

@@ -78,6 +78,7 @@ private:
};
struct PeerButton {
not_null<History*> history;
std::shared_ptr<Data::CloudImageView> userpic;
Button button;
};
@@ -184,9 +185,10 @@ void FilterChatsPreview::updateData(
}
}
for (const auto history : peers) {
_removePeer.push_back({
history,
makeButton([=] { removePeer(history); }) });
_removePeer.push_back(PeerButton{
.history = history,
.button = makeButton([=] { removePeer(history); })
});
}
refresh();
}
@@ -203,7 +205,7 @@ int FilterChatsPreview::resizeGetHeight(int newWidth) {
for (const auto &[flag, button] : _removeFlag) {
moveNextButton(button.get());
}
for (const auto &[history, button] : _removePeer) {
for (const auto &[history, userpic, button] : _removePeer) {
moveNextButton(button.get());
}
return top;
@@ -235,7 +237,7 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
FilterChatsTypeName(flag));
top += st.height;
}
for (const auto &[history, button] : _removePeer) {
for (auto &[history, userpic, button] : _removePeer) {
const auto savedMessages = history->peer->isSelf();
if (savedMessages) {
Ui::EmptyUserpic::PaintSavedMessages(
@@ -253,6 +255,7 @@ void FilterChatsPreview::paintEvent(QPaintEvent *e) {
} else {
history->peer->paintUserpicLeft(
p,
userpic,
iconLeft,
top + iconTop,
width(),

View File

@@ -180,11 +180,12 @@ QString ExceptionRow::generateShortName() {
PaintRoundImageCallback ExceptionRow::generatePaintUserpicCallback() {
const auto peer = this->peer();
const auto saved = peer->isSelf();
return [=](Painter &p, int x, int y, int outerWidth, int size) {
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, x, y, outerWidth, size);
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}
};
}

View File

@@ -41,8 +41,9 @@ PaintRoundImageCallback PaintUserpicCallback(
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
};
}
return [=](Painter &p, int x, int y, int outerWidth, int size) {
peer->paintUserpicLeft(p, x, y, outerWidth, size);
auto userpic = std::shared_ptr<Data::CloudImageView>();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
};
}
@@ -483,14 +484,22 @@ QString PeerListRow::generateShortName() {
: peer()->shortName();
}
std::shared_ptr<Data::CloudImageView> PeerListRow::ensureUserpicView() {
if (!_userpic) {
_userpic = peer()->createUserpicView();
}
return _userpic;
}
PaintRoundImageCallback PeerListRow::generatePaintUserpicCallback() {
const auto saved = _isSavedMessagesChat;
const auto peer = this->peer();
return [=](Painter &p, int x, int y, int outerWidth, int size) {
auto userpic = saved ? nullptr : ensureUserpicView();
return [=](Painter &p, int x, int y, int outerWidth, int size) mutable {
if (saved) {
Ui::EmptyUserpic::PaintSavedMessages(p, x, y, outerWidth, size);
} else {
peer->paintUserpicLeft(p, x, y, outerWidth, size);
peer->paintUserpicLeft(p, userpic, x, y, outerWidth, size);
}
};
}
@@ -595,7 +604,7 @@ void PeerListRow::paintDisabledCheckUserpic(
if (_isSavedMessagesChat) {
Ui::EmptyUserpic::PaintSavedMessages(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
} else {
peer()->paintUserpicLeft(p, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
peer()->paintUserpicLeft(p, _userpic, userpicLeft, userpicTop, outerWidth, userpicRadius * 2);
}
{

View File

@@ -7,11 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#pragma once
#include <rpl/event_stream.h>
#include "ui/rp_widget.h"
#include "ui/empty_userpic.h"
#include "boxes/abstract_box.h"
#include "mtproto/sender.h"
#include "data/data_cloud_file.h"
#include "base/timer.h"
namespace style {
@@ -85,6 +85,8 @@ public:
return _id;
}
[[nodiscard]] std::shared_ptr<Data::CloudImageView> ensureUserpicView();
[[nodiscard]] virtual QString generateName();
[[nodiscard]] virtual QString generateShortName();
[[nodiscard]] virtual auto generatePaintUserpicCallback()
@@ -130,7 +132,7 @@ public:
LastSeen,
Custom,
};
void refreshStatus();
virtual void refreshStatus();
crl::time refreshStatusTime() const;
void setAbsoluteIndex(int index) {
@@ -223,6 +225,7 @@ private:
PeerListRowId _id = 0;
PeerData *_peer = nullptr;
mutable std::shared_ptr<Data::CloudImageView> _userpic;
std::unique_ptr<Ui::RippleAnimation> _ripple;
std::unique_ptr<Ui::RoundImageCheckbox> _checkbox;
Ui::Text::String _name;

View File

@@ -584,5 +584,9 @@ void ChooseRecipientBoxController::rowClicked(not_null<PeerListRow*> row) {
auto ChooseRecipientBoxController::createRow(
not_null<History*> history) -> std::unique_ptr<Row> {
return std::make_unique<Row>(history);
const auto peer = history->peer;
const auto skip = peer->isChannel()
&& !peer->isMegagroup()
&& !peer->canWrite();
return skip ? nullptr : std::make_unique<Row>(history);
}

View File

@@ -354,6 +354,16 @@ bool ParticipantsAdditionalData::canRestrictUser(
Unexpected("Peer in ParticipantsAdditionalData::canRestrictUser.");
}
bool ParticipantsAdditionalData::canRemoveUser(
not_null<UserData*> user) const {
if (canRestrictUser(user)) {
return true;
} else if (const auto chat = _peer->asChat()) {
return chat->invitedByMe.contains(user);
}
return false;
}
auto ParticipantsAdditionalData::adminRights(
not_null<UserData*> user) const
-> std::optional<MTPChatAdminRights> {
@@ -1056,7 +1066,9 @@ void ParticipantsBoxController::prepare() {
switch (_role) {
case Role::Admins: return tr::lng_channel_admins();
case Role::Profile:
case Role::Members: return tr::lng_profile_participants_section();
case Role::Members: return (_peer->isChannel() && !_peer->isMegagroup()
? tr::lng_profile_subscribers_section()
: tr::lng_profile_participants_section());
case Role::Restricted: return tr::lng_exceptions_list_title();
case Role::Kicked: return tr::lng_removed_list_title();
}
@@ -1434,6 +1446,8 @@ base::unique_qptr<Ui::PopupMenu> ParticipantsBoxController::rowContextMenu(
tr::lng_context_restrict_user(tr::now),
crl::guard(this, [=] { showRestricted(user); }));
}
}
if (_additional.canRemoveUser(user)) {
if (!_additional.isKicked(user)) {
const auto isGroup = _peer->isChat() || _peer->isMegagroup();
result->addAction(
@@ -1786,6 +1800,12 @@ std::unique_ptr<PeerListRow> ParticipantsBoxController::createRow(
|| _additional.canEditAdmin(user))) {
row->setActionLink(tr::lng_profile_kick(tr::now));
}
if (_role == Role::Members && user->isBot()) {
auto seesAllMessages = (user->botInfo->readsAllHistory || _additional.adminRights(user).has_value());
row->setCustomStatus(seesAllMessages
? tr::lng_status_bot_reads_all(tr::now)
: tr::lng_status_bot_not_reads_all(tr::now));
}
}
return row;
}
@@ -1798,7 +1818,7 @@ auto ParticipantsBoxController::computeType(
: _additional.adminRights(user).has_value()
? Rights::Admin
: Rights::Normal;
result.canRemove = _additional.canRestrictUser(user);
result.canRemove = _additional.canRemoveUser(user);
return result;
}

View File

@@ -88,6 +88,7 @@ public:
[[nodiscard]] bool canEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canAddOrEditAdmin(not_null<UserData*> user) const;
[[nodiscard]] bool canRestrictUser(not_null<UserData*> user) const;
[[nodiscard]] bool canRemoveUser(not_null<UserData*> user) const;
[[nodiscard]] std::optional<MTPChatAdminRights> adminRights(
not_null<UserData*> user) const;
QString adminRank(not_null<UserData*> user) const;

View File

@@ -967,7 +967,7 @@ void Controller::fillManageSection() {
if (canViewMembers) {
AddButtonWithCount(
_controls.buttonsLayout,
tr::lng_manage_peer_members(),
(_isGroup ? tr::lng_manage_peer_members() : tr::lng_manage_peer_subscribers()),
Info::Profile::MigratedOrMeValue(
_peer
) | rpl::map(

View File

@@ -888,7 +888,6 @@ void SingleMediaPreview::prepareAnimatedPreview(
_gifPreview = Media::Clip::MakeReader(
animatedPreviewPath,
std::move(callback));
if (_gifPreview) _gifPreview->setAutoplay();
}
}
@@ -1934,6 +1933,7 @@ void SendFilesBox::initSendWay() {
if (_albumPreview) {
_albumPreview->setSendWay(value);
}
updateEmojiPanelGeometry();
setInnerFocus();
});
}

View File

@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_document.h"
#include "data/data_session.h"
#include "data/data_file_origin.h"
#include "data/data_document_media.h"
#include "lang/lang_keys.h"
#include "chat_helpers/stickers.h"
#include "boxes/confirm_box.h"
@@ -20,6 +21,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/buttons.h"
#include "ui/widgets/scroll_area.h"
#include "ui/image/image.h"
#include "ui/image/image_location_factory.h"
#include "ui/text/text_utilities.h"
#include "ui/emoji_config.h"
#include "lottie/lottie_multi_player.h"
@@ -72,6 +74,7 @@ protected:
private:
struct Element {
not_null<DocumentData*> document;
std::shared_ptr<Data::DocumentMedia> documentMedia;
Lottie::Animation *animated = nullptr;
Ui::Animations::Simple overAnimation;
};
@@ -113,7 +116,7 @@ private:
int32 _setHash = 0;
MTPDstickerSet::Flags _setFlags = 0;
TimeId _setInstallDate = TimeId(0);
ImagePtr _setThumbnail;
ImageWithLocation _setThumbnail;
MTPInputStickerSet _input;
@@ -267,7 +270,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
continue;
}
_pack.push_back(document);
_elements.push_back({ document });
_elements.push_back({ document, document->createMediaView() });
}
for (const auto &pack : data.vpacks().v) {
pack.match([&](const MTPDstickerPack &pack) {
@@ -297,25 +300,29 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
_setFlags = set.vflags().v;
_setInstallDate = set.vinstalled_date().value_or(0);
if (const auto thumb = set.vthumb()) {
_setThumbnail = Images::Create(set, *thumb);
_setThumbnail = Images::FromPhotoSize(
&_controller->session(),
set,
*thumb);
} else {
_setThumbnail = ImagePtr();
_setThumbnail = ImageWithLocation();
}
auto &sets = _controller->session().data().stickerSetsRef();
const auto &sets = _controller->session().data().stickerSets();
const auto it = sets.find(_setId);
if (it != sets.cend()) {
const auto set = it->second.get();
using ClientFlag = MTPDstickerSet_ClientFlag;
const auto clientFlags = it->flags
const auto clientFlags = set->flags
& (ClientFlag::f_featured
| ClientFlag::f_not_loaded
| ClientFlag::f_unread
| ClientFlag::f_special);
_setFlags |= clientFlags;
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->stickers = _pack;
it->emoji = _emoji;
it->thumbnail = _setThumbnail;
set->flags = _setFlags;
set->installDate = _setInstallDate;
set->stickers = _pack;
set->emoji = _emoji;
set->setThumbnail(_setThumbnail);
}
});
});
@@ -357,9 +364,10 @@ void StickerSetBox::Inner::installDone(
_setFlags |= MTPDstickerSet::Flag::f_installed_date;
auto it = sets.find(_setId);
if (it == sets.cend()) {
it = sets.insert(
it = sets.emplace(
_setId,
Stickers::Set(
std::make_unique<Stickers::Set>(
&_controller->session().data(),
_setId,
_setAccess,
_setTitle,
@@ -367,14 +375,15 @@ void StickerSetBox::Inner::installDone(
_setCount,
_setHash,
_setFlags,
_setInstallDate,
_setThumbnail));
_setInstallDate)).first;
} else {
it->flags = _setFlags;
it->installDate = _setInstallDate;
it->second->flags = _setFlags;
it->second->installDate = _setInstallDate;
}
it->stickers = _pack;
it->emoji = _emoji;
const auto set = it->second.get();
set->setThumbnail(_setThumbnail);
set->stickers = _pack;
set->emoji = _emoji;
auto &order = _controller->session().data().stickerSetsOrderRef();
int insertAtIndex = 0, currentIndex = order.indexOf(_setId);
@@ -385,14 +394,15 @@ void StickerSetBox::Inner::installDone(
order.insert(insertAtIndex, _setId);
}
auto custom = sets.find(Stickers::CustomSetId);
if (custom != sets.cend()) {
for_const (auto sticker, _pack) {
const auto customIt = sets.find(Stickers::CustomSetId);
if (customIt != sets.cend()) {
const auto custom = customIt->second.get();
for (const auto sticker : std::as_const(_pack)) {
int removeIndex = custom->stickers.indexOf(sticker);
if (removeIndex >= 0) custom->stickers.removeAt(removeIndex);
}
if (custom->stickers.isEmpty()) {
sets.erase(custom);
sets.erase(customIt);
}
}
@@ -602,7 +612,7 @@ void StickerSetBox::Inner::setupLottie(int index) {
element.animated = Stickers::LottieAnimationFromDocument(
getLottiePlayer(),
document,
element.documentMedia.get(),
Stickers::LottieSize::StickerSet,
boundingBoxSize() * cIntRetinaFactor());
}
@@ -621,11 +631,12 @@ void StickerSetBox::Inner::paintSticker(
const auto &element = _elements[index];
const auto document = element.document;
document->checkStickerSmall();
const auto &media = element.documentMedia;
media->checkStickerSmall();
if (document->sticker()->animated
&& !element.animated
&& document->loaded()) {
&& media->loaded()) {
const_cast<Inner*>(this)->setupLottie(index);
}
@@ -650,11 +661,11 @@ void StickerSetBox::Inner::paintSticker(
frame);
_lottiePlayer->unpause(element.animated);
} else if (const auto image = document->getStickerSmall()) {
} else if (const auto image = media->getStickerSmall()) {
p.drawPixmapLeft(
ppos,
width(),
image->pix(document->stickerSetOrigin(), w, h));
image->pix(w, h));
}
}
@@ -666,10 +677,11 @@ bool StickerSetBox::Inner::notInstalled() const {
if (!_loaded) {
return false;
}
const auto it = _controller->session().data().stickerSets().constFind(_setId);
if ((it == _controller->session().data().stickerSets().cend())
|| !(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
const auto &sets = _controller->session().data().stickerSets();
const auto it = sets.find(_setId);
if ((it == sets.cend())
|| !(it->second->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->second->flags & MTPDstickerSet::Flag::f_archived)) {
return !_pack.empty();
}
return false;

View File

@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_session.h"
#include "data/data_channel.h"
#include "data/data_file_origin.h"
#include "data/data_document_media.h"
#include "core/application.h"
#include "lang/lang_keys.h"
#include "mainwidget.h"
@@ -165,7 +166,7 @@ void StickersBox::showAttachedStickers() {
});
if (const auto set = Stickers::FeedSet(*setData)) {
if (_attached.widget()->appendSet(*set)) {
if (_attached.widget()->appendSet(set)) {
addedSet = true;
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set->id, set->access);
@@ -220,8 +221,8 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
}
if (!setData) continue;
if (auto set = Stickers::FeedSet(*setData)) {
auto index = archived.indexOf(set->id);
if (const auto set = Stickers::FeedSet(*setData)) {
const auto index = archived.indexOf(set->id);
if (archived.isEmpty() || index != archived.size() - 1) {
changedSets = true;
if (index < archived.size() - 1) {
@@ -229,7 +230,7 @@ void StickersBox::getArchivedDone(uint64 offsetId, const MTPmessages_ArchivedSti
}
archived.push_back(set->id);
}
if (_archived.widget()->appendSet(*set)) {
if (_archived.widget()->appendSet(set)) {
addedSet = true;
if (set->stickers.isEmpty() || (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set->id, set->access);
@@ -373,17 +374,24 @@ void StickersBox::loadMoreArchived() {
}
uint64 lastId = 0;
for (auto setIt = _session->data().archivedStickerSetsOrder().cend(), e = _session->data().archivedStickerSetsOrder().cbegin(); setIt != e;) {
const auto &order = _session->data().archivedStickerSetsOrder();
const auto &sets = _session->data().stickerSets();
for (auto setIt = order.cend(), e = order.cbegin(); setIt != e;) {
--setIt;
auto it = _session->data().stickerSets().constFind(*setIt);
if (it != _session->data().stickerSets().cend()) {
if (it->flags & MTPDstickerSet::Flag::f_archived) {
lastId = it->id;
auto it = sets.find(*setIt);
if (it != sets.cend()) {
if (it->second->flags & MTPDstickerSet::Flag::f_archived) {
lastId = it->second->id;
break;
}
}
}
_archivedRequestId = MTP::send(MTPmessages_GetArchivedStickers(MTP_flags(0), MTP_long(lastId), MTP_int(kArchivedLimitPerPage)), rpcDone(&StickersBox::getArchivedDone, lastId));
_archivedRequestId = MTP::send(
MTPmessages_GetArchivedStickers(
MTP_flags(0),
MTP_long(lastId),
MTP_int(kArchivedLimitPerPage)),
rpcDone(&StickersBox::getArchivedDone, lastId));
}
void StickersBox::paintEvent(QPaintEvent *e) {
@@ -489,13 +497,14 @@ QPixmap StickersBox::grabContentCache() {
}
void StickersBox::installSet(uint64 setId) {
auto &sets = _session->data().stickerSetsRef();
auto it = sets.find(setId);
const auto &sets = _session->data().stickerSets();
const auto it = sets.find(setId);
if (it == sets.cend()) {
rebuildList();
return;
}
const auto set = it->second.get();
if (_localRemoved.contains(setId)) {
_localRemoved.removeOne(setId);
if (_installed.widget()) _installed.widget()->setRemovedSets(_localRemoved);
@@ -503,11 +512,11 @@ void StickersBox::installSet(uint64 setId) {
if (_archived.widget()) _archived.widget()->setRemovedSets(_localRemoved);
if (_attached.widget()) _attached.widget()->setRemovedSets(_localRemoved);
}
if (!(it->flags & MTPDstickerSet::Flag::f_installed_date)
|| (it->flags & MTPDstickerSet::Flag::f_archived)) {
if (!(set->flags & MTPDstickerSet::Flag::f_installed_date)
|| (set->flags & MTPDstickerSet::Flag::f_archived)) {
MTP::send(
MTPmessages_InstallStickerSet(
Stickers::inputSetId(*it),
set->mtpInput(),
MTP_boolFalse()),
rpcDone(&StickersBox::installDone),
rpcFail(&StickersBox::installFail, setId));
@@ -526,8 +535,8 @@ void StickersBox::installDone(const MTPmessages_StickerSetInstallResult &result)
bool StickersBox::installFail(uint64 setId, const RPCError &error) {
if (MTP::isDefaultHandledError(error)) return false;
auto &sets = _session->data().stickerSetsRef();
auto it = sets.find(setId);
const auto &sets = _session->data().stickerSets();
const auto it = sets.find(setId);
if (it == sets.cend()) {
rebuildList();
return true;
@@ -550,12 +559,14 @@ void StickersBox::requestArchivedSets() {
preloadArchivedSets();
}
auto &sets = _session->data().stickerSets();
for_const (auto setId, _session->data().archivedStickerSetsOrder()) {
auto it = sets.constFind(setId);
const auto &sets = _session->data().stickerSets();
const auto &order = _session->data().archivedStickerSetsOrder();
for (const auto setId : order) {
auto it = sets.find(setId);
if (it != sets.cend()) {
if (it->stickers.isEmpty() && (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(setId, it->access);
const auto set = it->second.get();
if (set->stickers.isEmpty() && (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(setId, set->access);
}
}
}
@@ -624,9 +635,7 @@ void StickersBox::setInnerFocus() {
StickersBox::~StickersBox() = default;
StickersBox::Inner::Row::Row(
uint64 id,
uint64 accessHash,
ImagePtr thumbnail,
not_null<Stickers::Set*> set,
DocumentData *sticker,
int32 count,
const QString &title,
@@ -638,9 +647,7 @@ StickersBox::Inner::Row::Row(
bool removed,
int32 pixw,
int32 pixh)
: id(id)
, accessHash(accessHash)
, thumbnail(thumbnail)
: set(set)
, sticker(sticker)
, count(count)
, title(title)
@@ -656,6 +663,10 @@ StickersBox::Inner::Row::Row(
StickersBox::Inner::Row::~Row() = default;
bool StickersBox::Inner::Row::isRecentSet() const {
return (set->id == Stickers::CloudRecentSetId);
}
StickersBox::Inner::Inner(
QWidget *parent,
not_null<Main::Session*> session,
@@ -804,8 +815,8 @@ QRect StickersBox::Inner::relativeButtonRect(bool removeButton) const {
return QRect(buttonx, buttony, buttonw, buttonh);
}
void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
auto xadd = 0, yadd = qRound(set->yadd.current());
void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> row, int index) {
auto xadd = 0, yadd = qRound(row->yadd.current());
if (xadd || yadd) p.translate(xadd, yadd);
if (_megagroupSet) {
@@ -817,8 +828,8 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
}();
if (index >= 0 && index == selectedIndex) {
p.fillRect(0, 0, width(), _rowHeight, st::contactsBgOver);
if (set->ripple) {
set->ripple->paint(p, 0, 0, width());
if (row->ripple) {
row->ripple->paint(p, 0, 0, width());
}
}
}
@@ -833,24 +844,24 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
current = reachedOpacity;
}
}
auto row = myrtlrect(st::contactsPadding.left() / 2, st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - st::contactsPadding.left() / 2, _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2));
auto rect = myrtlrect(st::contactsPadding.left() / 2, st::contactsPadding.top() / 2, width() - (st::contactsPadding.left() / 2) - _scrollbar - st::contactsPadding.left() / 2, _rowHeight - ((st::contactsPadding.top() + st::contactsPadding.bottom()) / 2));
p.setOpacity(current);
Ui::Shadow::paint(p, row, width(), st::boxRoundShadow);
Ui::Shadow::paint(p, rect, width(), st::boxRoundShadow);
p.setOpacity(1);
App::roundRect(p, row, st::boxBg, BoxCorners);
App::roundRect(p, rect, st::boxBg, BoxCorners);
p.setOpacity(1. - current);
paintFakeButton(p, set, index);
paintFakeButton(p, row, index);
p.setOpacity(1.);
} else if (!_megagroupSet) {
paintFakeButton(p, set, index);
paintFakeButton(p, row, index);
}
} else if (!_megagroupSet) {
paintFakeButton(p, set, index);
paintFakeButton(p, row, index);
}
if (set->removed && _section == Section::Installed) {
if (row->removed && _section == Section::Installed) {
p.setOpacity(st::stickersRowDisabledOpacity);
}
@@ -858,13 +869,13 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
if (!_megagroupSet && _section == Section::Installed) {
stickerx += st::stickersReorderIcon.width() + st::stickersReorderSkip;
if (!set->isRecentSet()) {
if (!row->isRecentSet()) {
st::stickersReorderIcon.paint(p, st::contactsPadding.left(), (_rowHeight - st::stickersReorderIcon.height()) / 2, width());
}
}
if (set->sticker) {
paintRowThumbnail(p, set, stickerx);
if (row->sticker) {
paintRowThumbnail(p, row, stickerx);
}
int namex = stickerx + st::contactsPhotoSize + st::contactsPadding.left();
@@ -875,19 +886,19 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
p.setFont(st::contactsNameStyle.font);
p.setPen(st::contactsNameFg);
p.drawTextLeft(namex, namey, width(), set->title, set->titleWidth);
p.drawTextLeft(namex, namey, width(), row->title, row->titleWidth);
if (set->unread) {
if (row->unread) {
p.setPen(Qt::NoPen);
p.setBrush(st::stickersFeaturedUnreadBg);
{
PainterHighQualityEnabler hq(p);
p.drawEllipse(style::rtlrect(namex + set->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
p.drawEllipse(style::rtlrect(namex + row->titleWidth + st::stickersFeaturedUnreadSkip, namey + st::stickersFeaturedUnreadTop, st::stickersFeaturedUnreadSize, st::stickersFeaturedUnreadSize, width()));
}
}
auto statusText = (set->count > 0) ? tr::lng_stickers_count(tr::now, lt_count, set->count) : tr::lng_contacts_loading(tr::now);
auto statusText = (row->count > 0) ? tr::lng_stickers_count(tr::now, lt_count, row->count) : tr::lng_contacts_loading(tr::now);
p.setFont(st::contactsStatusFont);
p.setPen(st::contactsStatusFg);
@@ -899,30 +910,39 @@ void StickersBox::Inner::paintRow(Painter &p, not_null<Row*> set, int index) {
void StickersBox::Inner::paintRowThumbnail(
Painter &p,
not_null<Row*> set,
not_null<Row*> row,
int left) {
const auto origin = Data::FileOriginStickerSet(
set->id,
set->accessHash);
const auto thumb = set->thumbnail
? set->thumbnail.get()
: set->sticker->thumbnail();
if (!thumb) {
return;
row->set->id,
row->set->access);
if (row->set->hasThumbnail()) {
if (!row->thumbnailMedia) {
row->thumbnailMedia = row->set->createThumbnailView();
row->set->loadThumbnail();
}
} else if (row->sticker) {
if (!row->stickerMedia) {
row->stickerMedia = row->sticker->createMediaView();
row->stickerMedia->thumbnailWanted(origin);
}
}
thumb->load(origin);
validateLottieAnimation(set);
if (!set->lottie) {
if (!thumb->loaded()) {
validateLottieAnimation(row);
if (!row->lottie) {
const auto thumb = row->thumbnailMedia
? row->thumbnailMedia->image()
: row->stickerMedia
? row->stickerMedia->thumbnail()
: nullptr;
if (!thumb) {
return;
}
p.drawPixmapLeft(
left + (st::contactsPhotoSize - set->pixw) / 2,
st::contactsPadding.top() + (st::contactsPhotoSize - set->pixh) / 2,
left + (st::contactsPhotoSize - row->pixw) / 2,
st::contactsPadding.top() + (st::contactsPhotoSize - row->pixh) / 2,
width(),
thumb->pix(origin, set->pixw, set->pixh));
} else if (set->lottie->ready()) {
const auto frame = set->lottie->frame();
thumb->pix(row->pixw, row->pixh));
} else if (row->lottie->ready()) {
const auto frame = row->lottie->frame();
const auto size = frame.size() / cIntRetinaFactor();
p.drawImage(
QRect(
@@ -935,19 +955,21 @@ void StickersBox::Inner::paintRowThumbnail(
const auto paused = controller->isGifPausedAtLeastFor(
Window::GifPauseReason::Layer);
if (!paused) {
set->lottie->markFrameShown();
row->lottie->markFrameShown();
}
}
}
void StickersBox::Inner::validateLottieAnimation(not_null<Row*> set) {
if (set->lottie
|| !Stickers::HasLottieThumbnail(set->thumbnail, set->sticker)) {
void StickersBox::Inner::validateLottieAnimation(not_null<Row*> row) {
if (row->lottie
|| !Stickers::HasLottieThumbnail(
row->thumbnailMedia.get(),
row->stickerMedia.get())) {
return;
}
auto player = Stickers::LottieThumbnail(
set->thumbnail,
set->sticker,
row->thumbnailMedia.get(),
row->stickerMedia.get(),
Stickers::LottieSize::SetsListThumbnail,
QSize(
st::contactsPhotoSize,
@@ -955,21 +977,21 @@ void StickersBox::Inner::validateLottieAnimation(not_null<Row*> set) {
if (!player) {
return;
}
set->lottie = std::move(player);
set->lottie->updates(
row->lottie = std::move(player);
row->lottie->updates(
) | rpl::start_with_next([=] {
updateRowThumbnail(set);
updateRowThumbnail(row);
}, lifetime());
}
void StickersBox::Inner::updateRowThumbnail(not_null<Row*> set) {
void StickersBox::Inner::updateRowThumbnail(not_null<Row*> row) {
const auto rowTop = [&] {
if (set == _megagroupSelectedSet.get()) {
if (row == _megagroupSelectedSet.get()) {
return _megagroupDivider->y() - _rowHeight;
}
auto top = _itemsTop;
for (const auto &row : _rows) {
if (row.get() == set) {
for (const auto &entry : _rows) {
if (entry.get() == row) {
return top + qRound(row->yadd.current());
}
top += _rowHeight;
@@ -987,10 +1009,10 @@ void StickersBox::Inner::updateRowThumbnail(not_null<Row*> set) {
st::contactsPhotoSize);
}
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> set, int index) {
auto removeButton = (_section == Section::Installed && !set->removed);
void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> row, int index) {
auto removeButton = (_section == Section::Installed && !row->removed);
auto rect = relativeButtonRect(removeButton);
if (_section != Section::Installed && set->installed && !set->archived && !set->removed) {
if (_section != Section::Installed && row->installed && !row->archived && !row->removed) {
// Checkbox after installed from Trending or Archived.
int checkx = width() - (st::contactsPadding.right() + st::contactsCheckPosition.x() + (rect.width() + st::stickersFeaturedInstalled.width()) / 2);
int checky = st::contactsPadding.top() + (st::contactsPhotoSize - st::stickersFeaturedInstalled.height()) / 2;
@@ -999,10 +1021,10 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> set, int ind
auto selected = (index == _actionSel && _actionDown < 0) || (index == _actionDown);
if (removeButton) {
// Trash icon button when not disabled in Installed.
if (set->ripple) {
set->ripple->paint(p, rect.x(), rect.y(), width());
if (set->ripple->empty()) {
set->ripple.reset();
if (row->ripple) {
row->ripple->paint(p, rect.x(), rect.y(), width());
if (row->ripple->empty()) {
row->ripple.reset();
}
}
auto &icon = selected ? st::stickersRemove.iconOver : st::stickersRemove.icon;
@@ -1018,10 +1040,10 @@ void StickersBox::Inner::paintFakeButton(Painter &p, not_null<Row*> set, int ind
auto &text = (_section == Section::Installed) ? _undoText : _addText;
auto &textBg = selected ? st.textBgOver : st.textBg;
App::roundRect(p, myrtlrect(rect), textBg, ImageRoundRadius::Small);
if (set->ripple) {
set->ripple->paint(p, rect.x(), rect.y(), width());
if (set->ripple->empty()) {
set->ripple.reset();
if (row->ripple) {
row->ripple->paint(p, rect.x(), rect.y(), width());
if (row->ripple->empty()) {
row->ripple.reset();
}
}
p.setFont(st.font);
@@ -1054,19 +1076,19 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
}
if (_actionDown >= 0 && _actionDown < _rows.size()) {
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
auto &set = _rows[_actionDown];
if (set->ripple) {
set->ripple->lastStop();
const auto row = _rows[_actionDown].get();
if (row->ripple) {
row->ripple->lastStop();
}
}
_actionDown = newActionDown;
if (_actionDown >= 0 && _actionDown < _rows.size()) {
update(0, _itemsTop + _actionDown * _rowHeight, width(), _rowHeight);
auto &set = _rows[_actionDown];
auto removeButton = (_section == Section::Installed && !set->removed);
if (!set->ripple) {
const auto row = _rows[_actionDown].get();
auto removeButton = (_section == Section::Installed && !row->removed);
if (!row->ripple) {
if (_section == Section::Installed) {
if (set->removed) {
if (row->removed) {
auto rippleSize = QSize(_undoWidth - st::stickersUndoRemove.width, st::stickersUndoRemove.height);
auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::buttonRadius);
ensureRipple(st::stickersUndoRemove.ripple, std::move(rippleMask), removeButton);
@@ -1075,15 +1097,15 @@ void StickersBox::Inner::setActionDown(int newActionDown) {
auto rippleMask = Ui::RippleAnimation::ellipseMask(QSize(rippleSize, rippleSize));
ensureRipple(st::stickersRemove.ripple, std::move(rippleMask), removeButton);
}
} else if (!set->installed || set->archived || set->removed) {
} else if (!row->installed || row->archived || row->removed) {
auto rippleSize = QSize(_addWidth - st::stickersTrendingAdd.width, st::stickersTrendingAdd.height);
auto rippleMask = Ui::RippleAnimation::roundRectMask(rippleSize, st::buttonRadius);
ensureRipple(st::stickersTrendingAdd.ripple, std::move(rippleMask), removeButton);
}
}
if (set->ripple) {
if (row->ripple) {
auto rect = relativeButtonRect(removeButton);
set->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(myrtlrect(rect).x(), _itemsTop + _actionDown * _rowHeight + rect.y()));
row->ripple->add(mapFromGlobal(QCursor::pos()) - QPoint(myrtlrect(rect).x(), _itemsTop + _actionDown * _rowHeight + rect.y()));
}
}
}
@@ -1092,14 +1114,6 @@ void StickersBox::Inner::setSelected(SelectedRow selected) {
if (_selected == selected) {
return;
}
if ((_megagroupSet || _section != Section::Installed)
&& ((_selected.has_value() || _pressed.has_value()) != (selected.has_value() || _pressed.has_value()))) {
if (!_inDragArea) {
setCursor((selected.has_value() || _pressed.has_value())
? style::cur_pointer
: style::cur_default);
}
}
auto countSelectedIndex = [&] {
if (auto index = base::get_if<int>(&_selected)) {
return *index;
@@ -1111,6 +1125,7 @@ void StickersBox::Inner::setSelected(SelectedRow selected) {
update(0, _itemsTop + selectedIndex * _rowHeight, width(), _rowHeight);
}
_selected = selected;
updateCursor();
selectedIndex = countSelectedIndex();
if (_megagroupSet && selectedIndex >= 0 && selectedIndex < _rows.size()) {
update(0, _itemsTop + selectedIndex * _rowHeight, width(), _rowHeight);
@@ -1130,9 +1145,9 @@ void StickersBox::Inner::setPressed(SelectedRow pressed) {
auto pressedIndex = countPressedIndex();
if (_megagroupSet && pressedIndex >= 0 && pressedIndex < _rows.size()) {
update(0, _itemsTop + pressedIndex * _rowHeight, width(), _rowHeight);
auto &set = _rows[pressedIndex];
if (set->ripple) {
set->ripple->lastStop();
const auto row = _rows[pressedIndex].get();
if (row->ripple) {
row->ripple->lastStop();
}
}
_pressed = pressed;
@@ -1216,15 +1231,15 @@ void StickersBox::Inner::onUpdateSelected() {
auto selectedIndex = floorclamp(local.y() - _itemsTop, _rowHeight, 0, _rows.size() - 1);
selected = selectedIndex;
local.setY(local.y() - _itemsTop - selectedIndex * _rowHeight);
auto &set = _rows[selectedIndex];
if (!_megagroupSet && (_section == Section::Installed || !set->installed || set->archived || set->removed)) {
auto removeButton = (_section == Section::Installed && !set->removed);
const auto row = _rows[selectedIndex].get();
if (!_megagroupSet && (_section == Section::Installed || !row->installed || row->archived || row->removed)) {
auto removeButton = (_section == Section::Installed && !row->removed);
auto rect = myrtlrect(relativeButtonRect(removeButton));
actionSel = rect.contains(local) ? selectedIndex : -1;
} else {
actionSel = -1;
}
if (!_megagroupSet && _section == Section::Installed && !set->isRecentSet()) {
if (!_megagroupSet && _section == Section::Installed && !row->isRecentSet()) {
auto dragAreaWidth = st::contactsPadding.left() + st::stickersReorderIcon.width() + st::stickersReorderSkip;
auto dragArea = myrtlrect(0, 0, dragAreaWidth, _rowHeight);
inDragArea = dragArea.contains(local);
@@ -1238,17 +1253,25 @@ void StickersBox::Inner::onUpdateSelected() {
setSelected(selected);
if (_inDragArea != inDragArea) {
_inDragArea = inDragArea;
setCursor(_inDragArea
? style::cur_sizeall
: ((_selected.has_value() || _pressed.has_value())
? style::cur_pointer
: style::cur_default));
updateCursor();
}
setActionSel(actionSel);
emit draggingScrollDelta(0);
}
}
void StickersBox::Inner::updateCursor() {
setCursor(_inDragArea
? style::cur_sizeall
: (!_megagroupSet && _section == Section::Installed)
? ((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel))
? style::cur_pointer
: style::cur_default)
: (_selected.has_value() || _pressed.has_value())
? style::cur_pointer
: style::cur_default);
}
float64 StickersBox::Inner::aboveShadowOpacity() const {
if (_above < 0) return 0;
@@ -1260,9 +1283,7 @@ float64 StickersBox::Inner::aboveShadowOpacity() const {
void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
auto pressed = std::exchange(_pressed, SelectedRow());
if (_section != Section::Installed && !_selected.has_value() && pressed.has_value()) {
setCursor(style::cur_default);
}
updateCursor();
_mouse = e->globalPos();
onUpdateSelected();
@@ -1270,7 +1291,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
if (_section == Section::Installed) {
setRowRemoved(_actionDown, !_rows[_actionDown]->removed);
} else if (_installSetCallback) {
_installSetCallback(_rows[_actionDown]->id);
_installSetCallback(_rows[_actionDown]->set->id);
}
} else if (_dragging >= 0) {
QPoint local(mapFromGlobal(_mouse));
@@ -1283,42 +1304,28 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
_dragging = _started = -1;
} else if (pressed == _selected && _actionSel < 0 && _actionDown < 0) {
auto selectedIndex = [&] {
const auto selectedIndex = [&] {
if (auto index = base::get_if<int>(&_selected)) {
return *index;
}
return -1;
}();
auto getSetByRow = [&](const Row &row) -> const Stickers::Set* {
auto &sets = _session->data().stickerSetsRef();
if (!row.isRecentSet()) {
auto it = sets.find(row.id);
if (it != sets.cend()) {
return &*it;
}
}
return nullptr;
};
auto showSetByRow = [&](const Row &row) {
if (auto set = getSetByRow(row)) {
setSelected(SelectedRow());
Ui::show(
Box<StickerSetBox>(
App::wnd()->sessionController(),
Stickers::inputSetId(*set)),
Ui::LayerOption::KeepOther);
}
const auto showSetByRow = [&](const Row &row) {
setSelected(SelectedRow());
Ui::show(
Box<StickerSetBox>(
App::wnd()->sessionController(),
row.set->mtpInput()),
Ui::LayerOption::KeepOther);
};
if (selectedIndex >= 0 && !_inDragArea) {
auto &row = *_rows[selectedIndex];
if (_megagroupSet) {
if (auto set = getSetByRow(row)) {
setMegagroupSelectedSet(MTP_inputStickerSetID(
MTP_long(set->id),
MTP_long(set->access)));
const auto row = _rows[selectedIndex].get();
if (!row->isRecentSet()) {
if (_megagroupSet) {
setMegagroupSelectedSet(row->set->mtpInput());
} else {
showSetByRow(*row);
}
} else {
showSetByRow(row);
}
} else if (_megagroupSelectedSet && _selected.is<MegagroupSet>()) {
showSetByRow(*_megagroupSelectedSet);
@@ -1429,9 +1436,7 @@ void StickersBox::Inner::setActionSel(int32 actionSel) {
if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
_actionSel = actionSel;
if (_actionSel >= 0) update(0, _itemsTop + _actionSel * _rowHeight, width(), _rowHeight);
if (_section == Section::Installed) {
setCursor((_actionSel >= 0 && (_actionDown < 0 || _actionDown == _actionSel)) ? style::cur_pointer : style::cur_default);
}
updateCursor();
}
}
@@ -1466,8 +1471,9 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
auto text = _megagroupSetField->getLastText().trimmed();
if (text.isEmpty()) {
if (_megagroupSelectedSet) {
auto it = _session->data().stickerSets().constFind(_megagroupSelectedSet->id);
if (it != _session->data().stickerSets().cend() && !it->shortName.isEmpty()) {
const auto &sets = _session->data().stickerSets();
const auto it = sets.find(_megagroupSelectedSet->set->id);
if (it != sets.cend() && !it->second->shortName.isEmpty()) {
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
}
}
@@ -1477,7 +1483,9 @@ void StickersBox::Inner::handleMegagroupSetAddressChange() {
)).done([=](const MTPmessages_StickerSet &result) {
_megagroupSetRequestId = 0;
auto set = Stickers::FeedSetFull(result);
setMegagroupSelectedSet(MTP_inputStickerSetID(MTP_long(set->id), MTP_long(set->access)));
setMegagroupSelectedSet(MTP_inputStickerSetID(
MTP_long(set->id),
MTP_long(set->access)));
}).fail([=](const RPCError &error) {
_megagroupSetRequestId = 0;
setMegagroupSelectedSet(MTP_inputStickerSetEmpty());
@@ -1499,32 +1507,33 @@ void StickersBox::Inner::rebuildMegagroupSet() {
_megagroupSelectedShadow.destroy();
return;
}
auto &set = _megagroupSetInput.c_inputStickerSetID();
auto setId = set.vid().v;
auto &sets = _session->data().stickerSets();
auto &inputId = _megagroupSetInput.c_inputStickerSetID();
auto setId = inputId.vid().v;
const auto &sets = _session->data().stickerSets();
auto it = sets.find(setId);
if (it == sets.cend() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set.vid().v, set.vaccess_hash().v);
if (it == sets.cend()
|| (it->second->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(
inputId.vid().v,
inputId.vaccess_hash().v);
return;
}
const auto set = it->second.get();
auto maxNameWidth = countMaxNameWidth();
auto titleWidth = 0;
auto title = fillSetTitle(*it, maxNameWidth, &titleWidth);
auto count = fillSetCount(*it);
auto thumbnail = ImagePtr();
auto title = fillSetTitle(set, maxNameWidth, &titleWidth);
auto count = fillSetCount(set);
auto sticker = (DocumentData*)nullptr;
auto pixw = 0, pixh = 0;
fillSetCover(*it, &thumbnail, &sticker, &pixw, &pixh);
fillSetCover(set, &sticker, &pixw, &pixh);
auto installed = true, official = false, unread = false, archived = false, removed = false;
if (!_megagroupSelectedSet || _megagroupSelectedSet->id != it->id) {
_megagroupSetField->setText(it->shortName);
if (!_megagroupSelectedSet || _megagroupSelectedSet->set->id != set->id) {
_megagroupSetField->setText(set->shortName);
_megagroupSetField->finishAnimating();
}
_megagroupSelectedSet = std::make_unique<Row>(
it->id,
it->access,
thumbnail,
set,
sticker,
count,
title,
@@ -1561,7 +1570,7 @@ void StickersBox::Inner::rebuild() {
auto maxNameWidth = countMaxNameWidth();
clear();
auto &order = ([&]() -> const Stickers::Order & {
const auto &order = ([&]() -> const Stickers::Order & {
if (_section == Section::Installed) {
auto &result = _session->data().stickerSetsOrder();
if (_megagroupSet && result.empty()) {
@@ -1576,7 +1585,7 @@ void StickersBox::Inner::rebuild() {
_rows.reserve(order.size() + 1);
_shiftingStartTimes.reserve(order.size() + 1);
auto &sets = _session->data().stickerSets();
const auto &sets = _session->data().stickerSets();
if (_megagroupSet) {
auto usingFeatured = _session->data().stickerSetsOrder().empty();
_megagroupSubTitle->setText(usingFeatured
@@ -1584,21 +1593,23 @@ void StickersBox::Inner::rebuild() {
: tr::lng_stickers_group_from_your(tr::now));
updateControlsGeometry();
} else if (_section == Section::Installed) {
auto cloudIt = sets.constFind(Stickers::CloudRecentSetId);
if (cloudIt != sets.cend() && !cloudIt->stickers.isEmpty()) {
rebuildAppendSet(cloudIt.value(), maxNameWidth);
auto cloudIt = sets.find(Stickers::CloudRecentSetId);
if (cloudIt != sets.cend() && !cloudIt->second->stickers.isEmpty()) {
rebuildAppendSet(cloudIt->second.get(), maxNameWidth);
}
}
for_const (auto setId, order) {
auto it = sets.constFind(setId);
for (const auto setId : order) {
auto it = sets.find(setId);
if (it == sets.cend()) {
continue;
}
rebuildAppendSet(it.value(), maxNameWidth);
const auto set = it->second.get();
rebuildAppendSet(set, maxNameWidth);
if (it->stickers.isEmpty() || (it->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(it->id, it->access);
if (set->stickers.isEmpty()
|| (set->flags & MTPDstickerSet_ClientFlag::f_not_loaded)) {
_session->api().scheduleStickerSetRequest(set->id, set->access);
}
}
_session->api().requestStickerSets();
@@ -1626,24 +1637,22 @@ void StickersBox::Inner::updateSize(int newWidth) {
void StickersBox::Inner::updateRows() {
int maxNameWidth = countMaxNameWidth();
auto &sets = _session->data().stickerSets();
const auto &sets = _session->data().stickerSets();
for (const auto &row : _rows) {
const auto it = sets.constFind(row->id);
const auto it = sets.find(row->set->id);
if (it == sets.cend()) {
continue;
}
const auto &set = it.value();
const auto set = it->second.get();
if (!row->sticker) {
auto thumbnail = ImagePtr();
auto sticker = (DocumentData*)nullptr;
auto pixw = 0, pixh = 0;
fillSetCover(set, &thumbnail, &sticker, &pixw, &pixh);
fillSetCover(set, &sticker, &pixw, &pixh);
if (sticker) {
if ((row->thumbnail.get() != thumbnail.get())
|| (!thumbnail && row->sticker != sticker)) {
if (row->sticker != sticker && !row->thumbnailMedia) {
row->lottie = nullptr;
row->stickerMedia = nullptr;
}
row->thumbnail = thumbnail;
row->sticker = sticker;
row->pixw = pixw;
row->pixh = pixh;
@@ -1666,9 +1675,9 @@ void StickersBox::Inner::updateRows() {
update();
}
bool StickersBox::Inner::appendSet(const Stickers::Set &set) {
for_const (auto &row, _rows) {
if (row->id == set.id) {
bool StickersBox::Inner::appendSet(not_null<Stickers::Set*> set) {
for (const auto &row : _rows) {
if (row->set == set) {
return false;
}
}
@@ -1695,28 +1704,27 @@ int StickersBox::Inner::countMaxNameWidth() const {
return namew;
}
void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameWidth) {
void StickersBox::Inner::rebuildAppendSet(
not_null<Stickers::Set*> set,
int maxNameWidth) {
bool installed = true, official = true, unread = false, archived = false, removed = false;
if (set.id != Stickers::CloudRecentSetId) {
if (set->id != Stickers::CloudRecentSetId) {
fillSetFlags(set, &installed, &official, &unread, &archived);
}
if (_section == Section::Installed && archived) {
return;
}
ImagePtr thumbnail;
DocumentData *sticker = nullptr;
int pixw = 0, pixh = 0;
fillSetCover(set, &thumbnail, &sticker, &pixw, &pixh);
fillSetCover(set, &sticker, &pixw, &pixh);
int titleWidth = 0;
QString title = fillSetTitle(set, maxNameWidth, &titleWidth);
int count = fillSetCount(set);
_rows.push_back(std::make_unique<Row>(
set.id,
set.access,
thumbnail,
set,
sticker,
count,
title,
@@ -1731,19 +1739,26 @@ void StickersBox::Inner::rebuildAppendSet(const Stickers::Set &set, int maxNameW
_shiftingStartTimes.push_back(0);
}
void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbnail, DocumentData **outSticker, int *outWidth, int *outHeight) const {
*thumbnail = set.thumbnail;
if (set.stickers.isEmpty()) {
void StickersBox::Inner::fillSetCover(
not_null<Stickers::Set*> set,
DocumentData **outSticker,
int *outWidth,
int *outHeight) const {
if (set->stickers.isEmpty()) {
*outSticker = nullptr;
*outWidth = *outHeight = 0;
return;
}
auto sticker = *outSticker = set.stickers.front();
auto sticker = *outSticker = set->stickers.front();
const auto size = set.thumbnail
? set.thumbnail->size()
: sticker->thumbnail()
? sticker->thumbnail()->size()
const auto size = set->hasThumbnail()
? QSize(
set->thumbnailLocation().width(),
set->thumbnailLocation().height())
: sticker->hasThumbnail()
? QSize(
sticker->thumbnailLocation().width(),
sticker->thumbnailLocation().height())
: QSize(1, 1);
auto pixw = size.width();
auto pixh = size.height();
@@ -1763,14 +1778,19 @@ void StickersBox::Inner::fillSetCover(const Stickers::Set &set, ImagePtr *thumbn
*outHeight = pixh;
}
int StickersBox::Inner::fillSetCount(const Stickers::Set &set) const {
int result = set.stickers.isEmpty() ? set.count : set.stickers.size(), added = 0;
if (set.id == Stickers::CloudRecentSetId) {
auto customIt = _session->data().stickerSets().constFind(Stickers::CustomSetId);
if (customIt != _session->data().stickerSets().cend()) {
added = customIt->stickers.size();
for_const (auto &sticker, Stickers::GetRecentPack()) {
if (customIt->stickers.indexOf(sticker.first) < 0) {
int StickersBox::Inner::fillSetCount(not_null<Stickers::Set*> set) const {
int result = set->stickers.isEmpty()
? set->count
: set->stickers.size();
auto added = 0;
if (set->id == Stickers::CloudRecentSetId) {
const auto &sets = _session->data().stickerSets();
auto customIt = sets.find(Stickers::CustomSetId);
if (customIt != sets.cend()) {
added = customIt->second->stickers.size();
const auto &recent = Stickers::GetRecentPack();
for (const auto &sticker : recent) {
if (customIt->second->stickers.indexOf(sticker.first) < 0) {
++added;
}
}
@@ -1781,8 +1801,11 @@ int StickersBox::Inner::fillSetCount(const Stickers::Set &set) const {
return result + added;
}
QString StickersBox::Inner::fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const {
auto result = set.title;
QString StickersBox::Inner::fillSetTitle(
not_null<Stickers::Set*> set,
int maxNameWidth,
int *outTitleWidth) const {
auto result = set->title;
int titleWidth = st::contactsNameStyle.font->width(result);
if (titleWidth > maxNameWidth) {
result = st::contactsNameStyle.font->elided(result, maxNameWidth);
@@ -1795,16 +1818,16 @@ QString StickersBox::Inner::fillSetTitle(const Stickers::Set &set, int maxNameWi
}
void StickersBox::Inner::fillSetFlags(
const Stickers::Set &set,
not_null<Stickers::Set*> set,
bool *outInstalled,
bool *outOfficial,
bool *outUnread,
bool *outArchived) {
*outInstalled = (set.flags & MTPDstickerSet::Flag::f_installed_date);
*outOfficial = (set.flags & MTPDstickerSet::Flag::f_official);
*outArchived = (set.flags & MTPDstickerSet::Flag::f_archived);
*outInstalled = (set->flags & MTPDstickerSet::Flag::f_installed_date);
*outOfficial = (set->flags & MTPDstickerSet::Flag::f_official);
*outArchived = (set->flags & MTPDstickerSet::Flag::f_archived);
if (_section == Section::Featured) {
*outUnread = (set.flags & MTPDstickerSet_ClientFlag::f_unread);
*outUnread = (set->flags & MTPDstickerSet_ClientFlag::f_unread);
} else {
*outUnread = false;
}
@@ -1816,7 +1839,7 @@ Stickers::Order StickersBox::Inner::collectSets(Check check) const {
result.reserve(_rows.size());
for_const (auto &row, _rows) {
if (check(row.get())) {
result.push_back(row->id);
result.push_back(row->set->id);
}
}
return result;
@@ -1843,7 +1866,7 @@ Stickers::Order StickersBox::Inner::getRemovedSets() const {
int StickersBox::Inner::getRowIndex(uint64 setId) const {
for (auto i = 0, count = int(_rows.size()); i != count; ++i) {
auto &row = _rows[i];
if (row->id == setId) {
if (row->set->id == setId) {
return i;
}
}
@@ -1866,7 +1889,7 @@ void StickersBox::Inner::setFullOrder(const Stickers::Order &order) {
void StickersBox::Inner::setRemovedSets(const Stickers::Order &removed) {
for (auto i = 0, count = int(_rows.size()); i != count; ++i) {
setRowRemoved(i, removed.contains(_rows[i]->id));
setRowRemoved(i, removed.contains(_rows[i]->set->id));
}
}
@@ -1904,15 +1927,14 @@ void StickersBox::Inner::readVisibleSets() {
if (i * _rowHeight < itemsVisibleTop || (i + 1) * _rowHeight > itemsVisibleBottom) {
continue;
}
const auto thumbnail = !_rows[i]->sticker
? nullptr
: _rows[i]->thumbnail
? _rows[i]->thumbnail.get()
: _rows[i]->sticker->thumbnail();
if (!thumbnail
|| thumbnail->loaded()
|| _rows[i]->sticker->loaded()) {
_session->api().readFeaturedSetDelayed(_rows[i]->id);
const auto thumbnailLoading = _rows[i]->set->hasThumbnail()
? _rows[i]->set->thumbnailLoading()
: _rows[i]->sticker
? ((_rows[i]->stickerMedia && _rows[i]->stickerMedia->loaded())
|| _rows[i]->sticker->thumbnailLoading())
: false;
if (!thumbnailLoading || _rows[i]->stickerMedia->loaded()) {
_session->api().readFeaturedSetDelayed(_rows[i]->set->id);
}
}
}

View File

@@ -10,7 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
#include "base/timer.h"
#include "mtproto/sender.h"
#include "chat_helpers/stickers.h"
#include "chat_helpers/stickers_set.h"
#include "ui/effects/animations.h"
#include "ui/special_fields.h"
@@ -33,6 +33,18 @@ namespace Main {
class Session;
} // namespace Main
namespace Data {
class DocumentMedia;
} // namespace Data
namespace Lottie {
class SinglePlayer;
} // namespace Lottie
namespace Stickers {
class Set;
} // namespace Stickers
class StickersBox final
: public Ui::BoxContent
, public RPCSender
@@ -173,7 +185,7 @@ public:
void rebuild();
void updateSize(int newWidth = 0);
void updateRows(); // refresh only pack cover stickers
bool appendSet(const Stickers::Set &set);
bool appendSet(not_null<Stickers::Set*> set);
Stickers::Order getOrder() const;
Stickers::Order getFullOrder() const;
@@ -219,9 +231,7 @@ public slots:
private:
struct Row {
Row(
uint64 id,
uint64 accessHash,
ImagePtr thumbnail,
not_null<Stickers::Set*> set,
DocumentData *sticker,
int32 count,
const QString &title,
@@ -233,15 +243,14 @@ private:
bool removed,
int32 pixw,
int32 pixh);
bool isRecentSet() const {
return (id == Stickers::CloudRecentSetId);
}
~Row();
uint64 id = 0;
uint64 accessHash = 0;
ImagePtr thumbnail;
bool isRecentSet() const;
const not_null<Stickers::Set*> set;
DocumentData *sticker = nullptr;
std::shared_ptr<Data::DocumentMedia> stickerMedia;
std::shared_ptr<Stickers::SetThumbnailView> thumbnailMedia;
int32 count = 0;
QString title;
int titleWidth = 0;
@@ -294,23 +303,24 @@ private:
void ensureRipple(const style::RippleAnimation &st, QImage mask, bool removeButton);
bool shiftingAnimationCallback(crl::time now);
void paintRow(Painter &p, not_null<Row*> set, int index);
void paintRowThumbnail(Painter &p, not_null<Row*> set, int left);
void paintFakeButton(Painter &p, not_null<Row*> set, int index);
void paintRow(Painter &p, not_null<Row*> row, int index);
void paintRowThumbnail(Painter &p, not_null<Row*> row, int left);
void paintFakeButton(Painter &p, not_null<Row*> row, int index);
void clear();
void updateCursor();
void setActionSel(int32 actionSel);
float64 aboveShadowOpacity() const;
void validateLottieAnimation(not_null<Row*> set);
void updateRowThumbnail(not_null<Row*> set);
void validateLottieAnimation(not_null<Row*> row);
void updateRowThumbnail(not_null<Row*> row);
void readVisibleSets();
void updateControlsGeometry();
void rebuildAppendSet(const Stickers::Set &set, int maxNameWidth);
void fillSetCover(const Stickers::Set &set, ImagePtr *thumbnail, DocumentData **outSticker, int *outWidth, int *outHeight) const;
int fillSetCount(const Stickers::Set &set) const;
QString fillSetTitle(const Stickers::Set &set, int maxNameWidth, int *outTitleWidth) const;
void fillSetFlags(const Stickers::Set &set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived);
void rebuildAppendSet(not_null<Stickers::Set*> set, int maxNameWidth);
void fillSetCover(not_null<Stickers::Set*> set, DocumentData **outSticker, int *outWidth, int *outHeight) const;
int fillSetCount(not_null<Stickers::Set*> set) const;
QString fillSetTitle(not_null<Stickers::Set*> set, int maxNameWidth, int *outTitleWidth) const;
void fillSetFlags(not_null<Stickers::Set*> set, bool *outInstalled, bool *outOfficial, bool *outUnread, bool *outArchived);
void rebuildMegagroupSet();
void fixupMegagroupSetAddress();
void handleMegagroupSetAddressChange();

View File

@@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "main/main_session.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "mtproto/facade.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"

View File

@@ -109,7 +109,7 @@ public:
bool actionSelected) override;
private:
void refreshStatus();
void refreshStatus() override;
static Type ComputeType(not_null<const HistoryItem*> item);
std::vector<not_null<HistoryItem*>> _items;

View File

@@ -18,23 +18,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "media/audio/media_audio_track.h"
#include "base/platform/base_platform_info.h"
#include "calls/calls_panel.h"
#include "calls/calls_controller.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "facades.h"
#ifdef slots
#undef slots
#define NEED_TO_RESTORE_SLOTS
#endif // slots
#include <VoIPController.h>
#include <VoIPServerConfig.h>
#ifdef NEED_TO_RESTORE_SLOTS
#define slots Q_SLOTS
#undef NEED_TO_RESTORE_SLOTS
#endif // NEED_TO_RESTORE_SLOTS
namespace Calls {
namespace {
@@ -43,25 +31,25 @@ constexpr auto kHangupTimeoutMs = 5000;
constexpr auto kSha256Size = 32;
void AppendEndpoint(
std::vector<tgvoip::Endpoint> &list,
std::vector<TgVoipEndpoint> &list,
const MTPPhoneConnection &connection) {
connection.match([&](const MTPDphoneConnection &data) {
if (data.vpeer_tag().v.length() != 16) {
return;
}
const auto ipv4 = tgvoip::IPv4Address(std::string(
data.vip().v.constData(),
data.vip().v.size()));
const auto ipv6 = tgvoip::IPv6Address(std::string(
data.vipv6().v.constData(),
data.vipv6().v.size()));
list.emplace_back(
(int64_t)data.vid().v,
(uint16_t)data.vport().v,
ipv4,
ipv6,
tgvoip::Endpoint::Type::UDP_RELAY,
(unsigned char*)data.vpeer_tag().v.data());
auto endpoint = TgVoipEndpoint{
.endpointId = (int64_t)data.vid().v,
.host = TgVoipEdpointHost{
.ipv4 = data.vip().v.toStdString(),
.ipv6 = data.vipv6().v.toStdString() },
.port = (uint16_t)data.vport().v,
.type = TgVoipEndpointType::UdpRelay
};
const auto tag = data.vpeer_tag().v;
if (tag.size() >= 16) {
memcpy(endpoint.peerTag, tag.data(), 16);
}
list.push_back(std::move(endpoint));
});
}
@@ -80,47 +68,25 @@ uint64 ComputeFingerprint(bytes::const_span authKey) {
| (gsl::to_integer<uint64>(hash[12]));
}
} // namespace
void Call::ControllerPointer::create() {
Expects(_data == nullptr);
_data = std::make_unique<tgvoip::VoIPController>();
[[nodiscard]] std::vector<std::string> CollectVersions() {
return { TgVoip::getVersion() };
}
void Call::ControllerPointer::reset() {
if (const auto controller = base::take(_data)) {
controller->Stop();
[[nodiscard]] QVector<MTPstring> WrapVersions(
const std::vector<std::string> &data) {
auto result = QVector<MTPstring>();
result.reserve(data.size());
for (const auto &version : data) {
result.push_back(MTP_string(version));
}
return result;
}
bool Call::ControllerPointer::empty() const {
return (_data == nullptr);
[[nodiscard]] QVector<MTPstring> CollectVersionsForApi() {
return WrapVersions(CollectVersions());
}
bool Call::ControllerPointer::operator==(std::nullptr_t) const {
return empty();
}
Call::ControllerPointer::operator bool() const {
return !empty();
}
tgvoip::VoIPController *Call::ControllerPointer::operator->() const {
Expects(!empty());
return _data.get();
}
tgvoip::VoIPController &Call::ControllerPointer::operator*() const {
Expects(!empty());
return *_data;
}
Call::ControllerPointer::~ControllerPointer() {
reset();
}
} // namespace
Call::Delegate::~Delegate() = default;
@@ -199,8 +165,8 @@ void Call::startOutgoing() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4")))
MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
@@ -278,8 +244,8 @@ void Call::actuallyAnswer() {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4")))
MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([=](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
auto &call = result.c_phone_phoneCall();
@@ -300,7 +266,7 @@ void Call::actuallyAnswer() {
void Call::setMute(bool mute) {
_mute = mute;
if (_controller) {
_controller->SetMicMute(_mute);
_controller->setMuteMicrophone(_mute);
}
_muteChanged.notify(_mute);
}
@@ -334,8 +300,7 @@ void Call::redial() {
}
QString Call::getDebugLog() const {
const auto debug = _controller->GetDebugString();
return QString::fromUtf8(debug.data(), debug.size());
return QString::fromStdString(_controller->getDebugInfo());
}
void Call::startWaitingTrack() {
@@ -441,7 +406,9 @@ bool Call::handleUpdate(const MTPPhoneCall &call) {
return false;
}
if (data.is_need_debug()) {
auto debugLog = _controller ? _controller->GetDebugLog() : std::string();
auto debugLog = _controller
? _controller->getDebugInfo()
: std::string();
if (!debugLog.empty()) {
MTP::send(
MTPphone_SaveCallDebug(
@@ -517,8 +484,8 @@ void Call::confirmAcceptedCall(const MTPDphoneCallAccepted &call) {
MTP_flags(MTPDphoneCallProtocol::Flag::f_udp_p2p
| MTPDphoneCallProtocol::Flag::f_udp_reflector),
MTP_int(kMinLayer),
MTP_int(tgvoip::VoIPController::GetConnectionMaxLayer()),
MTP_vector(1, MTP_string("2.4.4")))
MTP_int(TgVoip::getConnectionMaxLayer()),
MTP_vector(CollectVersionsForApi()))
)).done([this](const MTPphone_PhoneCall &result) {
Expects(result.type() == mtpc_phone_phoneCall);
@@ -566,126 +533,123 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
return;
}
tgvoip::VoIPController::Config config;
config.dataSaving = tgvoip::DATA_SAVING_NEVER;
const auto &protocol = call.vprotocol().c_phoneCallProtocol();
TgVoipConfig config;
config.dataSaving = TgVoipDataSaving::Never;
config.enableAEC = !Platform::IsMac10_7OrGreater();
config.enableNS = true;
config.enableAGC = true;
config.enableVolumeControl = true;
config.initTimeout = Global::CallConnectTimeoutMs() / 1000;
config.recvTimeout = Global::CallPacketTimeoutMs() / 1000;
config.initializationTimeout = Global::CallConnectTimeoutMs() / 1000.;
config.receiveTimeout = Global::CallPacketTimeoutMs() / 1000.;
config.enableP2P = call.is_p2p_allowed();
config.maxApiLayer = protocol.vmax_layer().v;
if (Logs::DebugEnabled()) {
auto callLogFolder = cWorkingDir() + qsl("DebugLogs");
auto callLogPath = callLogFolder + qsl("/last_call_log.txt");
auto callLogNative = QDir::toNativeSeparators(callLogPath);
#ifdef Q_OS_WIN
config.logFilePath = callLogNative.toStdWString();
config.logPath = callLogNative.toStdWString();
#else // Q_OS_WIN
const auto callLogUtf = QFile::encodeName(callLogNative);
config.logFilePath.resize(callLogUtf.size());
ranges::copy(callLogUtf, config.logFilePath.begin());
config.logPath.resize(callLogUtf.size());
ranges::copy(callLogUtf, config.logPath.begin());
#endif // Q_OS_WIN
QFile(callLogPath).remove();
QDir().mkpath(callLogFolder);
}
const auto &protocol = call.vprotocol().c_phoneCallProtocol();
auto endpoints = std::vector<tgvoip::Endpoint>();
auto endpoints = std::vector<TgVoipEndpoint>();
for (const auto &connection : call.vconnections().v) {
AppendEndpoint(endpoints, connection);
}
auto callbacks = tgvoip::VoIPController::Callbacks();
callbacks.connectionStateChanged = [](
tgvoip::VoIPController *controller,
int state) {
const auto call = static_cast<Call*>(controller->implData);
call->handleControllerStateChange(controller, state);
};
callbacks.signalBarCountChanged = [](
tgvoip::VoIPController *controller,
int count) {
const auto call = static_cast<Call*>(controller->implData);
call->handleControllerBarCountChange(controller, count);
};
_controller.create();
if (_mute) {
_controller->SetMicMute(_mute);
}
_controller->implData = static_cast<void*>(this);
_controller->SetRemoteEndpoints(
endpoints,
call.is_p2p_allowed(),
protocol.vmax_layer().v);
_controller->SetConfig(config);
_controller->SetCurrentAudioOutput(Global::CallOutputDeviceID().toStdString());
_controller->SetCurrentAudioInput(Global::CallInputDeviceID().toStdString());
_controller->SetOutputVolume(Global::CallOutputVolume()/100.0f);
_controller->SetInputVolume(Global::CallInputVolume()/100.0f);
#ifdef Q_OS_MAC
_controller->SetAudioOutputDuckingEnabled(Global::CallAudioDuckingEnabled());
#endif
_controller->SetEncryptionKey(reinterpret_cast<char*>(_authKey.data()), (_type == Type::Outgoing));
_controller->SetCallbacks(callbacks);
auto proxy = TgVoipProxy();
if (Global::UseProxyForCalls()
&& (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) {
const auto &proxy = Global::SelectedProxy();
if (proxy.supportsCalls()) {
Assert(proxy.type == MTP::ProxyData::Type::Socks5);
_controller->SetProxy(
tgvoip::PROXY_SOCKS5,
proxy.host.toStdString(),
proxy.port,
proxy.user.toStdString(),
proxy.password.toStdString());
const auto &selected = Global::SelectedProxy();
if (selected.supportsCalls()) {
Assert(selected.type == MTP::ProxyData::Type::Socks5);
proxy.host = selected.host.toStdString();
proxy.port = selected.port;
proxy.login = selected.user.toStdString();
proxy.password = selected.password.toStdString();
}
}
_controller->Start();
_controller->Connect();
auto encryptionKey = TgVoipEncryptionKey();
encryptionKey.isOutgoing = (_type == Type::Outgoing);
encryptionKey.value = ranges::view::all(
_authKey
) | ranges::view::transform([](bytes::type byte) {
return static_cast<uint8_t>(byte);
}) | ranges::to_vector;
_controller = MakeController(
"2.4.4",
config,
TgVoipPersistentState(),
endpoints,
proxy.host.empty() ? nullptr : &proxy,
TgVoipNetworkType::Unknown,
encryptionKey);
const auto raw = _controller.get();
raw->setOnStateUpdated([=](TgVoipState state) {
handleControllerStateChange(raw, state);
});
raw->setOnSignalBarsUpdated([=](int count) {
handleControllerBarCountChange(count);
});
if (_mute) {
raw->setMuteMicrophone(_mute);
}
raw->setAudioOutputDevice(
Global::CallOutputDeviceID().toStdString());
raw->setAudioInputDevice(
Global::CallInputDeviceID().toStdString());
raw->setOutputVolume(Global::CallOutputVolume() / 100.0f);
raw->setInputVolume(Global::CallInputVolume() / 100.0f);
raw->setAudioOutputDuckingEnabled(Global::CallAudioDuckingEnabled());
}
void Call::handleControllerStateChange(
tgvoip::VoIPController *controller,
int state) {
not_null<Controller*> controller,
TgVoipState state) {
// NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()!
// Expects(controller == _controller.get());
Expects(controller->implData == static_cast<void*>(this));
switch (state) {
case tgvoip::STATE_WAIT_INIT: {
case TgVoipState::WaitInit: {
DEBUG_LOG(("Call Info: State changed to WaitingInit."));
setStateQueued(State::WaitingInit);
} break;
case tgvoip::STATE_WAIT_INIT_ACK: {
case TgVoipState::WaitInitAck: {
DEBUG_LOG(("Call Info: State changed to WaitingInitAck."));
setStateQueued(State::WaitingInitAck);
} break;
case tgvoip::STATE_ESTABLISHED: {
case TgVoipState::Established: {
DEBUG_LOG(("Call Info: State changed to Established."));
setStateQueued(State::Established);
} break;
case tgvoip::STATE_FAILED: {
auto error = controller->GetLastError();
case TgVoipState::Failed: {
auto error = QString::fromStdString(controller->getLastError());
LOG(("Call Info: State changed to Failed, error: %1.").arg(error));
setFailedQueued(error);
} break;
default: LOG(("Call Error: Unexpected state in handleStateChange: %1").arg(state));
default: LOG(("Call Error: Unexpected state in handleStateChange: %1"
).arg(int(state)));
}
}
void Call::handleControllerBarCountChange(
tgvoip::VoIPController *controller,
int count) {
void Call::handleControllerBarCountChange(int count) {
// NB! Can be called from an arbitrary thread!
// This can be called from ~VoIPController()!
// Expects(controller == _controller.get());
Expects(controller->implData == static_cast<void*>(this));
crl::on_main(this, [=] {
setSignalBarCount(count);
@@ -790,32 +754,30 @@ void Call::setState(State state) {
}
}
void Call::setCurrentAudioDevice(bool input, std::string deviceID){
void Call::setCurrentAudioDevice(bool input, std::string deviceID) {
if (_controller) {
if (input) {
_controller->SetCurrentAudioInput(deviceID);
_controller->setAudioInputDevice(deviceID);
} else {
_controller->SetCurrentAudioOutput(deviceID);
_controller->setAudioOutputDevice(deviceID);
}
}
}
void Call::setAudioVolume(bool input, float level){
void Call::setAudioVolume(bool input, float level) {
if (_controller) {
if(input) {
_controller->SetInputVolume(level);
if (input) {
_controller->setInputVolume(level);
} else {
_controller->SetOutputVolume(level);
_controller->setOutputVolume(level);
}
}
}
void Call::setAudioDuckingEnabled(bool enabled){
#ifdef Q_OS_MAC
void Call::setAudioDuckingEnabled(bool enabled) {
if (_controller) {
_controller->SetAudioOutputDuckingEnabled(enabled);
_controller->setAudioOutputDuckingEnabled(enabled);
}
#endif
}
void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
@@ -844,7 +806,7 @@ void Call::finish(FinishType type, const MTPPhoneCallDiscardReason &reason) {
setState(hangupState);
auto duration = getDurationMs() / 1000;
auto connectionId = _controller ? _controller->GetPreferredRelayID() : 0;
auto connectionId = _controller ? _controller->getPreferredRelayId() : 0;
_finishByTimeoutTimer.call(kHangupTimeoutMs, [this, finalState] { setState(finalState); });
_api.request(MTPphone_DiscardCall(
MTP_flags(0),
@@ -870,7 +832,7 @@ void Call::setStateQueued(State state) {
});
}
void Call::setFailedQueued(int error) {
void Call::setFailedQueued(const QString &error) {
crl::on_main(this, [=] {
handleControllerError(error);
});
@@ -887,13 +849,13 @@ void Call::handleRequestError(const RPCError &error) {
finish(FinishType::Failed);
}
void Call::handleControllerError(int error) {
if (error == tgvoip::ERROR_INCOMPATIBLE) {
void Call::handleControllerError(const QString &error) {
if (error == u"ERROR_INCOMPATIBLE"_q) {
Ui::show(Box<InformBox>(
Lang::Hard::CallErrorIncompatible().replace(
"{user}",
_user->name)));
} else if (error == tgvoip::ERROR_AUDIO_IO) {
} else if (error == u"ERROR_AUDIO_IO"_q) {
Ui::show(Box<InformBox>(tr::lng_call_error_audio_io(tr::now)));
}
finish(FinishType::Failed);
@@ -912,8 +874,8 @@ Call::~Call() {
destroyController();
}
void UpdateConfig(const std::string& data) {
tgvoip::ServerConfig::GetSharedInstance()->Update(data);
void UpdateConfig(const std::string &data) {
TgVoip::setGlobalServerConfig(data);
}
} // namespace Calls

View File

@@ -19,12 +19,12 @@ class Track;
} // namespace Audio
} // namespace Media
namespace tgvoip {
class VoIPController;
} // namespace tgvoip
enum class TgVoipState;
namespace Calls {
class Controller;
struct DhConfig {
int32 version = 0;
int32 g = 0;
@@ -129,30 +129,13 @@ public:
~Call();
private:
class ControllerPointer {
public:
void create();
void reset();
bool empty() const;
bool operator==(std::nullptr_t) const;
explicit operator bool() const;
tgvoip::VoIPController *operator->() const;
tgvoip::VoIPController &operator*() const;
~ControllerPointer();
private:
std::unique_ptr<tgvoip::VoIPController> _data;
};
enum class FinishType {
None,
Ended,
Failed,
};
void handleRequestError(const RPCError &error);
void handleControllerError(int error);
void handleControllerError(const QString &error);
void finish(FinishType type, const MTPPhoneCallDiscardReason &reason = MTP_phoneCallDiscardReasonDisconnect());
void startOutgoing();
void startIncoming();
@@ -160,11 +143,9 @@ private:
void generateModExpFirst(bytes::const_span randomSeed);
void handleControllerStateChange(
tgvoip::VoIPController *controller,
int state);
void handleControllerBarCountChange(
tgvoip::VoIPController *controller,
int count);
not_null<Controller*> controller,
TgVoipState state);
void handleControllerBarCountChange(int count);
void createAndStartController(const MTPDphoneCall &call);
template <typename T>
@@ -177,7 +158,7 @@ private:
void startConfirmedCall(const MTPDphoneCall &call);
void setState(State state);
void setStateQueued(State state);
void setFailedQueued(int error);
void setFailedQueued(const QString &error);
void setSignalBarCount(int count);
void destroyController();
@@ -210,12 +191,12 @@ private:
uint64 _accessHash = 0;
uint64 _keyFingerprint = 0;
ControllerPointer _controller;
std::unique_ptr<Controller> _controller;
std::unique_ptr<Media::Audio::Track> _waitingTrack;
};
void UpdateConfig(const std::string& data);
void UpdateConfig(const std::string &data);
} // namespace Calls

View File

@@ -0,0 +1,31 @@
/*
This file is part of Telegram Desktop,
the official desktop application for the Telegram messaging service.
For license and copyright information please follow this link:
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_controller.h"
#include "calls/calls_controller_tgvoip.h"
namespace Calls {
[[nodiscard]] std::unique_ptr<Controller> MakeController(
const std::string &version,
const TgVoipConfig &config,
const TgVoipPersistentState &persistentState,
const std::vector<TgVoipEndpoint> &endpoints,
const TgVoipProxy *proxy,
TgVoipNetworkType initialNetworkType,
const TgVoipEncryptionKey &encryptionKey) {
return std::make_unique<TgVoipController>(
config,
persistentState,
endpoints,
proxy,
initialNetworkType,
encryptionKey);
}
} // namespace Calls

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