Compare commits

...

490 Commits

Author SHA1 Message Date
John Preston
f09b91ebb5 Beta version 2.8.5: Fix build on non-Windows. 2021-07-02 04:45:58 +03:00
John Preston
57b147e0c8 Beta version 2.8.5.
- Use ANGLE for OpenGL over DirectX 9 / DirectX 11 (Windows).
- Use GTK from a child process (Linux).
2021-07-02 00:59:51 +03:00
Ilya Fedin
551ea7d879 Move GTK integration out of process with D-Bus 2021-07-02 00:59:36 +03:00
John Preston
d3c9bb0bc6 Try disabling native child OpenGL workaround. 2021-07-02 00:37:27 +03:00
John Preston
c711b1f1df Fix build on non-Linux systems. 2021-07-02 00:27:25 +03:00
23rd
af7ea90246 Added floating panel of playing playlist for scheduled audio files. 2021-07-01 23:53:45 +03:00
23rd
348cf4829c Added ability to scroll media in section of scheduled messages.
Fixed #8388.
2021-07-01 23:53:45 +03:00
23rd
4753a57091 Added ability to validate playlists in section of scheduled messages. 2021-07-01 23:53:45 +03:00
23rd
1a93f4fa4c Added ability to sparse id slices of scheduled media. 2021-07-01 23:53:45 +03:00
23rd
118fd187e3 Added abstract class for sparse ids slices. 2021-07-01 23:53:45 +03:00
23rd
baa47bde7f Removed unused MsgRange from SparseIdsSlice. 2021-07-01 23:53:45 +03:00
John Preston
18b48df9ce Allow to choose ANGLE backend. 2021-07-01 23:48:18 +03:00
John Preston
e71fc60d22 Use exact revision of ANGLE. 2021-07-01 23:48:16 +03:00
John Preston
148af59615 Don't check dll-s if "SetDefaultDllDirectories" is available. 2021-07-01 23:47:12 +03:00
John Preston
5b2db4112f Don't allow any .dll-s near Telegram.exe 2021-07-01 23:47:12 +03:00
John Preston
7cedc1f7a5 Add dynamic DirectX loading helper. 2021-07-01 23:47:08 +03:00
John Preston
6cea7d4a52 Fix YUV->RGB on D3D9 ANGLE backend. 2021-07-01 23:46:52 +03:00
John Preston
bd93aed393 Test build with statically linked ANGLE. 2021-07-01 23:46:52 +03:00
John Preston
348666de6d Use media viewer size hack only when required. 2021-07-01 23:46:52 +03:00
Ilya Fedin
47e32bebe4 Remove not really needed gtk scale factor query 2021-07-01 22:13:50 +03:00
Ilya Fedin
0b21c04489 Remove the copy of gtk file dialog 2021-07-01 22:13:50 +03:00
Ilya Fedin
85f013ebdb Revert "Avoid removing portal platformtheme plugin in snap"
This reverts commit 12db51fe75.
2021-07-01 22:13:50 +03:00
Ilya Fedin
832cc6ac69 Build Qt with gtk integration 2021-07-01 22:13:50 +03:00
Ilya Fedin
30ce049f51 Update submodules 2021-07-01 22:13:20 +03:00
Ilya Fedin
d42fb6d1b9 Switch from mallocng to jemalloc
Now it's known how to make it free the memory in an expected manner and it's better maintained
2021-07-01 22:13:20 +03:00
John Preston
cade53aa0a Version 2.8.4.
- Crash fixes in WebView on Windows.
2021-07-01 11:05:21 +03:00
GitHub Action
2fdcda7536 Update User-Agent for DNS to Chrome 91.0.4472.114. 2021-07-01 10:48:17 +03:00
Ilya Fedin
7e6439e4f8 Fix counting screen bottom point when restoring geometry 2021-06-30 00:27:39 +03:00
Ilya Fedin
f07ee7f590 Update lib_base and cmake_helpers 2021-06-29 17:35:39 +03:00
Ilya Fedin
02db4e01fa Get rid of qt5ct 2021-06-29 17:35:39 +03:00
Ilya Fedin
8d75078a42 Use Glib::MainLoop instead of QEventLoop in glib code 2021-06-29 15:10:08 +03:00
John Preston
0e25ef7524 Handle WinRT exceptions in WebView. 2021-06-29 14:08:50 +03:00
John Preston
8608d8aa4d Crash Fix: Destroy WebView before the container. 2021-06-29 11:07:47 +03:00
sammiee5311
c1a7332a5e Shorten if statement
Shorten if statement
2021-06-29 10:38:35 +03:00
Ilya Fedin
c3fb392906 Clean dbus-specific code in main_window_linux.h 2021-06-29 10:30:48 +03:00
Ilya Fedin
a59bfdb2f8 Fix handleNativeSurfaceChanged when dbus integration is disabled 2021-06-29 10:30:48 +03:00
Ilya Fedin
79f96480c2 Use QMenuBar instead of own global menu implementation on Linux 2021-06-29 10:30:48 +03:00
John Preston
60cbd96d91 Version 2.8.3.
- Fix crashes in OpenSSL on macOS.
2021-06-28 13:51:06 +03:00
John Preston
ee0400f1ac Version 2.8.2.
- Attempt to fix random crashes on macOS.

Fixes #16504.
2021-06-28 08:57:40 +03:00
John Preston
b8a3746558 Version 2.8.1: Fix NuGet WinRT header generation. 2021-06-26 13:26:39 +03:00
John Preston
14f25fc997 Version 2.8.1.
- Fix crash in audio player volume slider.
2021-06-26 13:03:40 +03:00
John Preston
27da6ee9eb Update patches revision in instructions. 2021-06-26 13:00:16 +03:00
John Preston
48d482006a Fix crash fix. 2021-06-26 12:33:18 +03:00
John Preston
9afee2620a Fix crash in vertical sliders.
Regression was introduced in 90ff8ecd0f.
2021-06-26 08:20:37 +03:00
John Preston
baca3047d4 Version 2.8: Fix build on Windows x64. 2021-06-24 18:39:41 +04:00
John Preston
43a5265e0c Version 2.8.
- Start video conferences from Voice Chats in any group.
- Share your screen or video from your camera
with up to 30 participants (limit to be increased soon).
- Talk without video with an unlimited number of participants.
- Create voice chats from the info page
of any group where you are an admin.
- Group video calls are supported natively on all devices,
including iPads and laptops.
2021-06-24 17:57:09 +04:00
John Preston
5519bb3523 Allow reporting private groups as well.
Fixes #7451.
2021-06-24 17:44:55 +04:00
John Preston
ff213d1386 Enable /LARGEADDRESSAWARE for 32 bit Windows build. 2021-06-24 17:44:55 +04:00
John Preston
55b3f99653 Fix new formatting mixing with emoji. 2021-06-24 17:44:55 +04:00
John Preston
8a6ff3f414 Add separator above volume control in voice chats. 2021-06-24 17:44:55 +04:00
John Preston
feb8624d05 Don't use private Hunspell headers. 2021-06-24 17:44:55 +04:00
John Preston
a2c33545d4 Improve some paddings. 2021-06-24 17:44:28 +04:00
23rd
7decf68122 Fixed possible crash in OverlayWidget when video continues from PiP. 2021-06-24 17:44:28 +04:00
John Preston
6b62ec97c6 Fix possible crash in export panel management. 2021-06-24 11:57:27 +04:00
Ilya Fedin
ea3dab4a06 Update lib_base 2021-06-24 11:26:24 +04:00
Ilya Fedin
5c8f08fc92 Move preview support from QGtkDialog to GtkFileDialog 2021-06-24 11:26:24 +04:00
Ilya Fedin
00a0b2c8b6 Get rid of GTK cast templates 2021-06-24 11:26:24 +04:00
Ilya Fedin
007218cc13 Use C++ wrappers in GtkOpenWithDialog 2021-06-24 11:26:24 +04:00
Ilya Fedin
8afe495a4f Avoid using g_unix_fd_list_new_from_array 2021-06-24 11:26:24 +04:00
Ilya Fedin
257f2086d1 Get rid of gtk2 header compatibility 2021-06-24 11:26:24 +04:00
Ilya Fedin
f011c84ce8 Make Linux file dialog API better 2021-06-24 11:26:24 +04:00
Ilya Fedin
8b839f46b2 Fix crash report window scale 2021-06-24 11:26:08 +04:00
23rd
c1067d8fe1 Fixed possible crash in notifications manager. 2021-06-24 11:25:36 +04:00
23rd
bb76818cc8 Split adaptive changed rpl::producer into two. 2021-06-24 11:25:35 +04:00
John Preston
5dcc219f1c For large video tile always request full quality. 2021-06-24 10:57:23 +04:00
John Preston
4ff9e90153 Add some assertions and logging for a crash debugging. 2021-06-24 10:49:01 +04:00
John Preston
28fe98af80 Add some assertions for a strange crash debugging. 2021-06-24 10:24:52 +04:00
John Preston
5eba65aaa0 Remove unused legacy protocol code. 2021-06-24 09:55:57 +04:00
John Preston
d1e3e7d240 Don't show pinned tooltips if only one video. 2021-06-23 20:14:49 +04:00
John Preston
90ff8ecd0f Fix volume slider in voice chats. 2021-06-23 20:14:22 +04:00
John Preston
468e75a572 Update submodules. 2021-06-23 20:13:19 +04:00
John Preston
ae3e5487d7 Fix editing messages with monospace parts. 2021-06-23 15:55:29 +04:00
John Preston
03147a5426 Fix possible crash in case of API error. 2021-06-23 14:29:38 +04:00
John Preston
14a2b10989 Show error if camera could not be enabled. 2021-06-23 12:04:05 +04:00
John Preston
b29f8aa1e6 Remove background over highlight in volume change item. 2021-06-23 11:07:23 +04:00
John Preston
f9bb932cd8 Fix voice chat window expanding near the screen edges. 2021-06-23 10:52:04 +04:00
John Preston
a38cbbf7e8 Fix disappearing icons after popup menu display. 2021-06-23 10:43:51 +04:00
John Preston
d5bb1717e0 Beta version 2.7.10: Fix link on macOS. 2021-06-22 23:07:33 +04:00
John Preston
520ff8f2ce Beta version 2.7.10: Fix build with Xcode. 2021-06-22 21:25:03 +04:00
John Preston
b3848f6a84 Beta version 2.7.10: Fix screencasts. 2021-06-22 21:23:01 +04:00
John Preston
518f387e0c Beta version 2.7.10: Update version. 2021-06-22 20:00:35 +04:00
John Preston
635f76a312 Beta version 2.7.10.
- Added ability to mix together bold, italic and other formatting.
- Fix voice chats and video calls OpenGL with some drivers on Windows.
- Several bug fixes.
2021-06-22 19:59:22 +04:00
John Preston
ff14ac68ee Always show tooltip about the muted microphone. 2021-06-22 19:50:26 +04:00
John Preston
948c5d50cb Add C++/WinRT library helper to lib_base. 2021-06-22 19:47:02 +04:00
John Preston
6b520ecc05 Add overlapping markup support. 2021-06-22 19:05:27 +04:00
John Preston
bb474686eb Use NuGet package for WinRT headers generation. 2021-06-22 09:53:20 +04:00
John Preston
659ddae9a8 Use native child window in video calls on Windows. 2021-06-21 11:29:29 +04:00
John Preston
b70276912e Use native child window in group calls on Windows. 2021-06-21 09:23:10 +04:00
23rd
858c575782 Fixed Hunspell license. 2021-06-21 09:23:10 +04:00
23rd
62fe14d592 Fixed lock icon display when switching layers in one column mode. 2021-06-21 09:23:10 +04:00
Ilya Fedin
6ad037e556 Update lib_waylandshells and cmake_helpers 2021-06-20 10:39:42 +04:00
Ilya Fedin
a55b41faa1 Provide a list of shell integrations in QT_WAYLAND_SHELL_INTEGRATION 2021-06-20 10:39:42 +04:00
Ilya Fedin
a26d769304 Set QT_WAYLAND_SHELL_INTEGRATION to custom value 2021-06-19 08:16:38 +04:00
John Preston
e1120d1cb5 Optimize out most of LastUserInputTime() calls.
Fixes #16118.
2021-06-18 19:22:36 +04:00
John Preston
8897f9e46a Limit requested qualities to 4 Full / 16 Medium. 2021-06-18 18:43:13 +04:00
John Preston
7a588be54f Add a hint to unmute your microphone. 2021-06-18 17:47:07 +04:00
John Preston
1cb1f1cbc1 Add a hint to turn on the camera. 2021-06-18 16:11:32 +04:00
John Preston
5827d6ffdb Update lib_ui submodule. 2021-06-18 12:15:01 +04:00
Ilya Fedin
766bc90921 Adapt for Ui::DisableCustomScaling changes 2021-06-18 12:15:01 +04:00
23rd
eb228eb744 Removed unused methods from file click handler. 2021-06-18 09:48:39 +03:00
23rd
7c02d67665 Moved cancelUploadLayer from MainWidget to SessionController. 2021-06-18 09:39:10 +03:00
23rd
23c54896e5 Removed App::main() from file click handlers. 2021-06-18 09:20:49 +03:00
23rd
460baa54d8 Fixed switching between PiP and OverlayWidget. 2021-06-18 07:30:54 +03:00
23rd
6c56fad180 Fixed updating of parent id for file click handlers.
Fixed #16447.
2021-06-18 07:30:54 +03:00
23rd
3fd772ce17 Moved file click handlers to separated file. 2021-06-18 07:30:54 +03:00
John Preston
8834ec8bf2 Disable audio device tracking on macOS. 2021-06-17 17:15:13 +04:00
John Preston
003fb52fb9 Make 100% volume value more sticky. 2021-06-17 16:42:50 +04:00
John Preston
ec234cdc43 Improve volume slider design in group calls. 2021-06-17 16:22:51 +04:00
John Preston
55e494f55a Beta version 2.7.9.
- Added "Enable noise suppression" option to group calls Settings.
- Fix media viewer with Retina + Non-Retina dual monitor setup on macOS.
- Several bug and crash fixes.
2021-06-17 12:11:08 +04:00
John Preston
0b4605a656 Don't pass Quality::Medium for screencast to tgcalls. 2021-06-17 12:03:26 +04:00
John Preston
18a86e500b Update tgcalls and tg_owt. 2021-06-17 11:55:10 +04:00
John Preston
e19af1257c Improve video in voice chats controls layout. 2021-06-17 11:52:53 +04:00
John Preston
e0159e15b2 Close StickerSetBox on error. 2021-06-17 11:06:17 +04:00
23rd
b6e77537e2 Fixed logo size in box of invite link QR code generation. 2021-06-17 10:57:46 +04:00
23rd
beaa4190eb Removed Q_OBJECT from GroupMembersWidget.
Removed unused onlineCountUpdated since d93c1ccbaa.
2021-06-17 10:57:46 +04:00
23rd
7924979dfb Removed Ui::showPeerHistoryAtItem from facades. 2021-06-17 10:57:46 +04:00
23rd
570ed5691d Added Window::Controller pointer to data of intro widget. 2021-06-17 10:57:45 +04:00
23rd
c25779b844 Removed showDocument and showPhoto from Media::View::OverlayWidget. 2021-06-17 10:57:45 +04:00
23rd
7304f2b695 Removed Application::showTheme. 2021-06-17 10:57:45 +04:00
23rd
b4bff939b1 Removed showDocument and showPhoto from Application. 2021-06-17 10:57:45 +04:00
23rd
1f816c249b Replaced DocumentOpenClickHandler. 2021-06-17 10:57:45 +04:00
23rd
8591d58798 Added ability to show content from Controller for Shared Media. 2021-06-17 10:57:45 +04:00
23rd
9290cd3a16 Added SessionController pointer to Media::View::OverlayWidget. 2021-06-17 10:57:45 +04:00
23rd
dc0aaec4a4 Added ability to show document from Controller for sections. 2021-06-17 10:57:45 +04:00
23rd
eefa7263b5 Added ability to show photo from Controller for sections. 2021-06-17 10:57:45 +04:00
23rd
7885be4a94 Added ability to show content from Controller for inline results. 2021-06-17 10:57:45 +04:00
23rd
583c3d3429 Moved static functions from DocumentData to separated file. 2021-06-17 10:57:45 +04:00
23rd
6d0d399250 Added initial ability to show documents in OverlayWidget from Controller. 2021-06-17 10:57:45 +04:00
23rd
0e89c93993 Added initial ability to show content in OverlayWidget from Controller. 2021-06-17 10:57:45 +04:00
23rd
b422ec025e Removed Ui::show from classes that have pointer to Controller. 2021-06-17 10:57:45 +04:00
John Preston
c8535acad8 Fix crash in hunspell initialization. 2021-06-17 10:11:08 +04:00
John Preston
e2a97e2ae9 Fix possible crash in media viewer. 2021-06-17 10:09:22 +04:00
John Preston
77a019325d Show information about unsupported gradient backgrounds. 2021-06-16 11:30:33 +04:00
23rd
115dc460ac Removed unused variables from LastCrashedWindow. 2021-06-16 09:31:32 +03:00
23rd
3df1a73cf5 Removed Q_OBJECT from LastCrashedWindow. 2021-06-16 09:31:32 +03:00
23rd
5cf69366d1 Removed Q_OBJECT from NetworkSettingsWindow. 2021-06-16 09:31:32 +03:00
23rd
8c2b1168af Fixed background color of input fields in crash reports with dark theme. 2021-06-16 09:31:32 +03:00
23rd
a425024f21 Fixed userpic updating of pinned peers in touchbar. 2021-06-16 09:31:32 +03:00
23rd
e85026ec46 Removed observable in Intro::details::Step. 2021-06-16 09:31:32 +03:00
23rd
1c6e2eae04 Removed unused enum from local legacy storage settings scheme. 2021-06-16 09:31:32 +03:00
23rd
4db5624beb Completely removed Global namespace. 2021-06-16 09:31:32 +03:00
23rd
6d08542afa Moved proxy global variables from facades to core settings. 2021-06-16 09:31:32 +03:00
23rd
707b36dc12 Moved DBIWorkMode to Core::Settings. 2021-06-16 09:31:32 +03:00
23rd
da3e140069 Moved DBINotifyView to Core::Settings. 2021-06-16 09:31:32 +03:00
23rd
5334372671 Moved WorkMode global variable from facades to core settings. 2021-06-16 09:31:32 +03:00
23rd
16db8468fa Moved ScreenIsLocked variable from facades to application. 2021-06-16 09:31:32 +03:00
23rd
2ed3543b53 Renamed class back from AdaptiveModern to Adaptive. 2021-06-16 09:31:32 +03:00
23rd
5b4d442799 Removed Adaptive namespace and related global variables from facades. 2021-06-16 09:31:32 +03:00
23rd
9669a8a44a Moved Core::Settings:chatWide to Window::Adaptive. 2021-06-16 09:31:32 +03:00
23rd
80fe2f57e9 Removed Adaptive namespace from Window::Controller and MainWidget. 2021-06-16 09:31:32 +03:00
23rd
824fbc21e8 Removed Adaptive namespace from peer context menu. 2021-06-16 09:31:32 +03:00
23rd
bf7f117323 Removed Adaptive namespace from Window::HistoryHider. 2021-06-16 09:31:32 +03:00
23rd
9b488f03a1 Removed Adaptive namespace from Settings::Chat. 2021-06-16 09:31:32 +03:00
23rd
295a863d69 Removed Adaptive namespace from Profile::BackButton. 2021-06-16 09:31:32 +03:00
23rd
0d814066d6 Removed Adaptive namespace from top bar widgets. 2021-06-16 09:31:32 +03:00
23rd
1af8e89eb9 Removed Adaptive namespace from HistoryWidget. 2021-06-16 09:31:32 +03:00
23rd
7cf79e1f8a Removed Adaptive namespace from sections. 2021-06-16 09:31:32 +03:00
23rd
019fd83c8a Removed Adaptive namespace from Dialogs::Widget. 2021-06-16 09:31:32 +03:00
23rd
65779ec37e Removed Adaptive namespace from FieldAutocomplete. 2021-06-16 09:31:32 +03:00
23rd
2d90a06078 Added new Adaptive class to replace legacy Adaptive namespace.
Temporarily named class as AdaptiveModern.
2021-06-16 09:31:32 +03:00
23rd
d2c8780c0f Removed NotificationsDemoIsShown global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
54dd63d61a Removed LocalPasscode global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
7852c82eab Simplified updating of autolock time in Settings::PrivacySecurity. 2021-06-16 09:31:32 +03:00
23rd
77c8bf8176 Removed PeerChooseCancel global variable from facades. 2021-06-16 09:31:32 +03:00
23rd
daa14466e5 Replaced observable in Lang::CloudManager with rpl. 2021-06-16 09:31:32 +03:00
23rd
aad38c2809 Replaced observable in Window::Notifications::System with rpl. 2021-06-16 09:31:32 +03:00
23rd
2c50d3d87b Replaced observable in Intro::details::Data with rpl. 2021-06-16 09:31:32 +03:00
23rd
0fe7c07007 Replaced observable with rpl in FixedBar of admin log. 2021-06-16 09:31:32 +03:00
23rd
c22d200c17 Removed unused observable trackFinished from Media::Audio::Instance. 2021-06-16 09:31:32 +03:00
23rd
9e6afa0d4e Removed observable dragFinished from MainWindow. 2021-06-16 09:31:32 +03:00
23rd
3340b2dc03 Replaced observable in Dialogs::InnerWidget with rpl. 2021-06-16 09:31:32 +03:00
23rd
386fae952b Replaced observable in SessionController with rpl. 2021-06-16 09:31:32 +03:00
23rd
a164cb9480 Removed unused observable passcodedChanged from Application. 2021-06-16 09:31:32 +03:00
23rd
bc9b288617 Replaced observable in StickersBox with rpl. 2021-06-16 09:31:32 +03:00
23rd
5c7229f875 Replaced observable in EditColorBox with rpl. 2021-06-16 09:31:31 +03:00
John Preston
658d5a1322 Fix move between Retina / Non-Retina. 2021-06-16 10:30:08 +04:00
John Preston
52e841ec29 Select correct quality for incoming screencast. 2021-06-16 08:59:15 +04:00
John Preston
df28da4d97 Show "Video is paused" in wide panel mode. 2021-06-15 16:49:53 +04:00
John Preston
8dac6896d6 Set Send/Receive buffer size for download TCP sockets. 2021-06-15 16:45:48 +04:00
John Preston
f18e157e46 Add video placeholder if can't receive it. 2021-06-15 14:30:51 +04:00
John Preston
b2bf8244dd Add "Enable noise suppression" setting to group calls. 2021-06-15 12:33:02 +04:00
John Preston
4e0355d09f Fix semi-transparent .webp in media viewer. 2021-06-14 15:28:39 +04:00
John Preston
7059336ff0 Show red mute icon for force-muted. 2021-06-14 15:15:33 +04:00
John Preston
94f10ce72e Fix dropping self level around mute button. 2021-06-14 14:57:25 +04:00
John Preston
68be54288c Fix working using OpenGLES / ANGLE. 2021-06-14 12:16:00 +04:00
John Preston
10636d931f Validate video speed before applying. 2021-06-14 11:22:57 +04:00
John Preston
3b1aa55d21 Don't send OpenGL initialization crash reports. 2021-06-14 11:22:39 +04:00
mid-kid
37f59095f4 Fix building with LINK_TO_GTK 2021-06-12 15:08:11 +04:00
John Preston
f85d1b8a29 Beta version 2.7.8: Update lib_waylandshells. 2021-06-12 00:27:56 +04:00
John Preston
ece491eee7 Beta version 2.7.8.
- Crash fixes.
2021-06-11 23:15:53 +04:00
John Preston
750c13e5fe Add OpenGL init crash checker. 2021-06-11 23:01:07 +04:00
John Preston
0fde35f59e Increase limit for full video request. 2021-06-11 22:52:59 +04:00
John Preston
5ab8a7d9c5 Fix controls in PiP video player. 2021-06-11 20:29:34 +04:00
John Preston
b1fad4f7e0 Fix possible crash in DBus SettingWatcher. 2021-06-11 19:41:58 +04:00
John Preston
4f0f815201 Fix crash in saving document from media viewer. 2021-06-11 19:36:27 +04:00
John Preston
f2286fdffd Fix possible crash in emoji suggestions. 2021-06-11 19:31:16 +04:00
John Preston
46dfde881a Fix crash in screencast error handling. 2021-06-11 19:19:50 +04:00
John Preston
95f7704d14 Fix crash in voice chat camera enabling. 2021-06-11 19:12:14 +04:00
John Preston
64a6838764 Fix crash in account switching. 2021-06-11 19:11:58 +04:00
John Preston
a0c2318919 Beta version 2.7.7.
- Optimized video playback in media viewer and Picture-in-Picture mode.
- Added integration with System Media Transport Controls on Windows 10.
- Added "Now Playing" integration for music playback on macOS.
- Added "Archive Sticker" into the "..." menu of the Sticker Set Box.
- Fixed memory not being freed on Linux.
- Several crash fixes.
2021-06-11 17:37:49 +04:00
John Preston
8d8fffd306 Fix OpenGL renderers on macOS. 2021-06-11 17:35:16 +04:00
John Preston
ecb53e3e0b Display Puny-encoded domains in proxy confirmation. 2021-06-11 14:20:00 +04:00
John Preston
468d43c4c7 Don't send by Enter elements, chosen by mouse. 2021-06-11 14:20:00 +04:00
John Preston
425a632965 Accept DD / EE as proxy type tag.
Fixes #16218.
2021-06-11 14:20:00 +04:00
John Preston
bf581a1ba4 Fix build with DESKTOP_APP_DISABLE_DBUS_INTEGRATION. 2021-06-11 14:20:00 +04:00
John Preston
7a0ba58ffd Don't construct Webrtc::VideoTrack only for state tracking. 2021-06-11 14:20:00 +04:00
John Preston
4543656aa3 Implement screencast pause in TDesktop. 2021-06-11 14:20:00 +04:00
23rd
8d72026cbd Fixed build for Linux. 2021-06-10 23:00:56 +03:00
23rd
32e47c24b4 Moved Linux MPRIS support to lib_base. 2021-06-10 23:00:56 +03:00
23rd
69eaecc218 Moved SystemMediaControlsManagerto Media namespace. 2021-06-10 23:00:56 +03:00
23rd
3ffbb94fdb Removed SPMediaKeyTap solution for macOS media keys.
Related commit: fd6a312abc.
2021-06-10 23:00:55 +03:00
23rd
4f8bab6a5f Fixed auto-seeking by system for non-fully loaded audio files in SMC. 2021-06-10 23:00:55 +03:00
23rd
2f0fd398d5 Fixed update of availability of next and previous tracks in SMC. 2021-06-10 23:00:55 +03:00
23rd
c6fde48936 Optimized updating of position in SMC. 2021-06-10 23:00:55 +03:00
23rd
8356bac6d7 Added new event of seeking to media player. 2021-06-10 23:00:55 +03:00
23rd
b553520a48 Fixed track change notification in media player. 2021-06-10 23:00:55 +03:00
23rd
3c86da78af Added volume support to SMC class. 2021-06-10 23:00:55 +03:00
23rd
fdbf63229d Added ability to specify application name for Linux MPRIS. 2021-06-10 23:00:55 +03:00
23rd
d22601461a Added new commands to Quit and Raise for Linux MPRIS. 2021-06-10 23:00:55 +03:00
23rd
13c70a9ce9 Added initial support of seeking to SMC class. 2021-06-10 23:00:55 +03:00
23rd
1cfbf24635 Moved Windows SMTC as part of cross-platform media controls solution. 2021-06-10 23:00:55 +03:00
Ilya Fedin
f90f1c02c3 Add extra-cmake-modules as telegram dependency in snapcraft.yaml 2021-06-11 00:00:16 +04:00
Ilya Fedin
8d0f5bb828 Use custom xdg-shell fork for shadows on Wayland 2021-06-10 23:49:10 +04:00
John Preston
2f986660ff Optimize background painting in OpenGL renderers. 2021-06-10 23:37:09 +04:00
John Preston
f9f98975a1 Implement OpenGL renderer for one-on-one calls. 2021-06-10 17:16:17 +04:00
John Preston
e0e2b973f1 Remove shadow debugging image saving. 2021-06-10 15:38:19 +04:00
John Preston
aeb994dd40 Fix radial loading and seek frame in PiP. 2021-06-10 14:05:15 +04:00
John Preston
112c597556 Fix video rotation apply in PiP player. 2021-06-10 11:44:31 +04:00
John Preston
fc94045f41 Fix PiP cursor after drag/resize finished. 2021-06-10 10:39:09 +04:00
John Preston
2a8055c513 Fix action invocation after dragging PiP window.
Regression was introduced in d752aa3481.
2021-06-10 10:31:47 +04:00
John Preston
fba116f0d5 Implement custom OpenGL renderer for PiP. 2021-06-10 10:12:37 +04:00
John Preston
b38f89d69e Fix 2x and 3x volume off icon in media viewer. 2021-06-10 10:12:23 +04:00
John Preston
84f6a5f957 Handle "video_joined" flag in self participant. 2021-06-09 09:19:29 +04:00
John Preston
054223efe0 Request screen recording permissions on macOS. 2021-06-09 09:19:29 +04:00
John Preston
de3ea30d69 Don't show messages to support as always-read. 2021-06-09 09:19:29 +04:00
John Preston
c5a46d9d1b For surface with parent backend should be fixed. 2021-06-09 09:19:29 +04:00
John Preston
e41fb0d8fd Fix ARGB32 frame rendering. 2021-06-09 09:19:28 +04:00
John Preston
5970f3de9e Show video paused icon. 2021-06-09 09:19:28 +04:00
John Preston
7878552e7d Fix hiding rows with video in narrow column. 2021-06-09 09:19:28 +04:00
John Preston
b3648d0147 Use QOpenGLShaderProgram::bind. 2021-06-09 09:19:28 +04:00
John Preston
dd79b3c0d5 Add noise to blur to remove color banding. 2021-06-09 09:19:28 +04:00
John Preston
3d76e6de55 Improve level meter design in group call settings. 2021-06-09 09:19:28 +04:00
John Preston
ef61443342 Fix tg://settings/devices link. 2021-06-09 09:19:28 +04:00
John Preston
4f8989fad7 Fix large video being removed animation. 2021-06-09 09:19:28 +04:00
John Preston
945411274f Close large video tile by click anywhere. 2021-06-09 09:19:28 +04:00
John Preston
f1f7330bf6 Hide "Remove" context action for participants-groups. 2021-06-09 09:19:28 +04:00
John Preston
a1957fe5c0 Stop connecting sound when group call leave starts. 2021-06-09 09:19:28 +04:00
John Preston
9a21d55de7 Show last blurred frame or userpic for paused videos. 2021-06-09 09:19:28 +04:00
John Preston
303ad02c61 Always call raise() before activateWindow(). 2021-06-09 09:19:28 +04:00
John Preston
1886a5c4ed Fix build on macOS. 2021-06-09 09:19:28 +04:00
John Preston
71ddfacfaa Fix showing static content in OpenGL media viewer. 2021-06-09 09:19:28 +04:00
John Preston
23c2bce1bb Animated zoom+rotate in OpenGL media viewer. 2021-06-09 09:19:28 +04:00
John Preston
5324a626be Animated zoom in OpenGL media viewer. 2021-06-09 09:19:28 +04:00
John Preston
4c5421916a Closed alpha version 2.7.6.2. 2021-06-09 09:19:28 +04:00
John Preston
2801bd99b8 Render media viewer icons in RendererGL. 2021-06-09 09:19:28 +04:00
John Preston
38a0eb3b52 Fix color conversions on GPU. 2021-06-09 09:19:28 +04:00
John Preston
607263b8be Fix seek / cancel of video playback in media viewer. 2021-06-09 09:19:28 +04:00
John Preston
42b62e90ca Fix video in non-group calls. 2021-06-09 09:19:28 +04:00
John Preston
f6f0b02333 Render YUV420 video in media viewer. 2021-06-09 09:19:28 +04:00
John Preston
1858e7e8ac Fix many video tiles in voice chats. 2021-06-09 09:19:28 +04:00
John Preston
482ad74c57 Stop camera/screen video when muted by admin. 2021-06-09 09:19:27 +04:00
John Preston
68ae40ee56 Draw all except controls in OpenGL media viewer. 2021-06-09 09:19:27 +04:00
John Preston
24f8a88625 Start OpenGL media viewer renderer. 2021-06-09 09:19:27 +04:00
23rd
fc78769e9c Added floating date header to Shared Files and Shared Links. 2021-06-09 09:19:27 +04:00
23rd
5c54d3690c Added floating date badge to Shared Photos and Shared Videos. 2021-06-09 09:19:27 +04:00
23rd
2cd8b00610 Added ability to override foreground color for date service messages. 2021-06-09 09:19:27 +04:00
23rd
7ee35bc80c Added ability to override background color for service messages. 2021-06-09 09:19:27 +04:00
23rd
cfbbce26c4 Added suitable name for floating badge colors. 2021-06-09 09:19:27 +04:00
John Preston
dfb26cabfc Closed alpha version 2.7.6.1. 2021-06-09 09:19:27 +04:00
John Preston
70f0cce340 Update API scheme. 2021-06-09 09:19:27 +04:00
Alexander Bushnev
3af0c37c6b Fix video player volume level changing
Bug:
Sometimes changing of the volume level or mute/unmute has no effect.
It happens because Fader::onTimer get a current volume level from the Mixer,
but it gets an event about the volume modification from the settings.
Bug appear when the method onTimer calling between updating
of the settings and the Mixer volume.

Solution:
Updating the Mixer volume before the settings.
(maybe will be better to get the volume level
from the settings in place of the Mixer,
but I am not sure about other side effects of this)
2021-06-09 08:18:49 +03:00
Anthony Axenov
b1906a778e Actual link to Vazir Fonts license in README 2021-06-09 08:17:53 +03:00
Alexander Bushnev
d752aa3481 Add volume controls to the PiP window
Add volume toggle and volume level controls to the PiP window.
2021-06-09 08:17:32 +03:00
John Preston
afc5191644 Update mallocng. 2021-06-07 16:21:55 +04:00
John Preston
254b02ad6b Fix Release build on Windows. 2021-06-07 16:21:55 +04:00
23rd
885365a1c2 Fixed Github CI Windows build. 2021-06-04 11:47:32 +03:00
23rd
245be4cd63 Fixed Github CI macOS build. 2021-06-04 11:47:32 +03:00
Ilya Fedin
ce413f2946 Update tg_owt in snap 2021-06-04 11:47:01 +03:00
Ilya Fedin
0d84ba406f Exclude some development files from snap 2021-06-04 11:47:01 +03:00
Ilya Fedin
9047b3c121 Prime tg_owt dependencies 2021-06-04 11:47:01 +03:00
Ilya Fedin
3ff9543106 Fix rnnoise installation path 2021-06-04 11:47:01 +03:00
Ilya Fedin
46b4a5fc5a Fix snap build 2021-06-02 14:00:43 +03:00
Ilya Fedin
bd456568ed Set -DTG_OWT_BUILD_AUDIO_BACKENDS=OFF in snapcraft.yaml 2021-06-01 19:33:43 +03:00
Ilya Fedin
93fa0e1df5 Add rnnoise to snapcraft.yaml 2021-06-01 19:33:43 +03:00
Ilya Fedin
fe4c5155eb Fix some warnings from GCC 11 2021-06-01 19:33:19 +03:00
John Preston
24c435bb5f Improve hide media viewer workaround on Windows. 2021-06-01 16:56:38 +04:00
John Preston
e6977b2c33 Start sharing without source choosing in case of PipeWire. 2021-06-01 14:58:30 +04:00
John Preston
28f83f2af4 Show participants Bio when not speaking. 2021-06-01 14:16:55 +04:00
John Preston
5a6e8a0a8c Improve style of desktop capture source choosing. 2021-06-01 13:58:15 +04:00
John Preston
003da28699 Beta version 2.7.6: Update submodules. 2021-05-31 23:54:09 +04:00
John Preston
e8dd969e78 Fix paint-image vertex shader on macOS. 2021-05-31 23:53:41 +04:00
John Preston
acce2a217d Beta version 2.7.6: Fix build on macOS. 2021-05-31 21:51:47 +04:00
Ilya Fedin
b964c681f8 Get system dark mode state asynchronously on Linux 2021-05-31 20:31:24 +03:00
Ilya Fedin
c6dcc57c5e Set _KDE_NET_WM_DESKTOP_FILE on X11 2021-05-31 20:30:51 +03:00
John Preston
cf8e1cfd0f Beta version 2.7.6.
- Optimized video playback in media viewer and Picture-in-Picture
on Windows and Linux.
- Added integration with System Media Transport Controls
on Windows 10.
- Added "Archive Sticker" into the "..." menu of the Sticker Set Box.
- Fixed memory not being freed on Linux.
- Several crash fixes.
2021-05-31 21:30:21 +04:00
John Preston
78b40a1f66 Revert test code in 'tgcalls'. 2021-05-31 21:27:14 +04:00
John Preston
2fe75f8296 Add large / small video animation. 2021-05-31 21:25:15 +04:00
John Preston
b22363224f Track tiles visibility separately from geometry. 2021-05-31 18:40:53 +04:00
John Preston
b3c92ed3f4 Rejoin if the call started accepting video. 2021-05-31 18:00:41 +04:00
John Preston
464b0a0f30 Use old media viewer hide workaround on macOS. 2021-05-31 17:39:15 +04:00
John Preston
dfcc13c7e6 Warn user about pinning of his screencast. 2021-05-31 17:35:41 +04:00
John Preston
ba6cee6f81 Add video/screencast pinned/unpinned toasts. 2021-05-31 17:10:30 +04:00
John Preston
bcdfd2150d Auto-pin new screencasts. 2021-05-31 15:53:15 +04:00
John Preston
d19d6bbcd9 Group call owner chat/channel is always admin. 2021-05-31 15:52:51 +04:00
John Preston
4080fa9bdc Allow mute for me even force-muted participants. 2021-05-31 15:46:15 +04:00
John Preston
ce091b0b63 Fix second click in media viewer double-click. 2021-05-31 14:54:56 +04:00
John Preston
136e930362 Paint outline in raster mode. 2021-05-31 08:54:23 +04:00
23rd
78dfe940ef Added Windows SMTC support.
System Media Transport Controls.
2021-05-31 08:54:23 +04:00
23rd
690fbe83fd Unified and moved to single place generating of song name from SongData. 2021-05-31 08:54:22 +04:00
23rd
f98e8f3e04 Fixed stuck of forward bar when using -sendpath argument.
Regression was introduced in b3d1602354.
2021-05-31 08:54:22 +04:00
23rd
63febef3ed Added Dock menu for macOS. 2021-05-30 23:39:55 +03:00
23rd
2599ae45d6 Fixed handle of last message on Up arrow in sections with key modifiers. 2021-05-30 23:39:55 +03:00
23rd
bfb03621c2 Fixed GIFs in EditCaptionBox on Retina screens. 2021-05-30 23:39:55 +03:00
23rd
be53bd5293 Added ability to start recording voice chat without title. 2021-05-30 23:39:55 +03:00
23rd
a429500b57 Fixed first animation of album thumbs in SendFilesBox on Retina screens. 2021-05-30 23:39:55 +03:00
John Preston
ec9fa00f46 Bring second large peer video to the top. 2021-05-31 00:07:11 +04:00
John Preston
6a001f2e6c Auto-switch large video by speaking participant. 2021-05-30 23:52:01 +04:00
John Preston
8bde53cd0f Add Back button to large video tiles. 2021-05-30 21:08:54 +04:00
John Preston
090d7d7112 Show video large on click. 2021-05-30 19:14:08 +04:00
John Preston
97c7c0742c Rename LargeVideo to Video in voice chats. 2021-05-30 18:46:51 +04:00
John Preston
90efbf1210 Remove some experimental code. 2021-05-30 18:21:11 +04:00
John Preston
38506d27a1 Hide member rows with active small videos. 2021-05-30 18:09:59 +04:00
John Preston
8a693bc932 Move 'Invite members' button to the bottom. 2021-05-30 14:56:54 +04:00
John Preston
0e49bf5dee Add video tiles in narrow members column. 2021-05-29 23:57:21 +04:00
John Preston
6a967948de Optimize uploading of textures. 2021-05-29 23:27:12 +04:00
John Preston
0771fc14db Use unique_id for tiles instead of PeerData*. 2021-05-29 22:58:11 +04:00
John Preston
e1614a280f Add blur effect for video tile background. 2021-05-29 17:00:09 +04:00
John Preston
ddf81c949b Add green outline to speaking video tiles. 2021-05-28 21:05:28 +04:00
John Preston
b906b2f625 Closed alpha version 2.7.5.7. 2021-05-28 19:11:07 +04:00
John Preston
3f2b473287 Add tooltips for wide mode controls. 2021-05-28 19:08:11 +04:00
John Preston
9a9430b5e1 Move some logging to DEBUG_LOG instead of LOG. 2021-05-28 15:21:15 +04:00
John Preston
d659200a42 Show unmute button tooltip about space bar. 2021-05-28 14:47:41 +04:00
John Preston
cb630c69f0 Fix tooltip colors in default dark green theme. 2021-05-28 13:39:38 +04:00
John Preston
9a812090a2 Add some error tooltips in group calls. 2021-05-28 13:23:24 +04:00
John Preston
5b0278847d Add context menu to video tile right click. 2021-05-27 23:20:16 +04:00
John Preston
9d07bb2946 Remove 'Share Screen' menu item in scheduled chats. 2021-05-27 22:47:18 +04:00
John Preston
b27d314fa7 Skip deleted users in voice chat invites. 2021-05-27 22:46:20 +04:00
John Preston
df666ff724 Implement more robust reconnect management. 2021-05-27 17:09:36 +04:00
John Preston
3709714339 Make '[un]registerLeaveSubscription' work in all windows. 2021-05-27 09:34:33 +04:00
John Preston
deecf80f20 Add OpenGL media viewer glitches workaround. 2021-05-27 08:39:01 +04:00
John Preston
6ea66bc527 Fix joining broadcasted streams in voice chats. 2021-05-27 00:37:05 +04:00
John Preston
513c8d1a65 Fix PiP drag pausing the video. 2021-05-26 23:49:33 +04:00
John Preston
49f71f4e1e Use av_packet_alloc instead of av_init_packet. 2021-05-26 22:53:54 +04:00
John Preston
0c5258b43a Closed alpha version 2.7.5.6. 2021-05-26 18:35:35 +04:00
John Preston
a0506f009a Update tg_owt revision. 2021-05-26 18:35:25 +04:00
John Preston
9f93dae6f9 Update FFmpeg to 4.4. 2021-05-26 18:22:30 +04:00
John Preston
45cca35724 Implement menu in wide video mode. 2021-05-26 18:21:50 +04:00
John Preston
1c42513e44 Fix pinning video from narrow mode. 2021-05-26 15:29:26 +04:00
John Preston
f3e6f5e772 Cancel outgoing video when muted by admin. 2021-05-26 15:12:00 +04:00
John Preston
c6f44e7928 Hide video button if the call doesn't support video. 2021-05-26 14:27:48 +04:00
John Preston
7b6b32db74 Fix name display in group call video tiles. 2021-05-26 13:35:01 +04:00
John Preston
e39f9bef1f Fix voice message recording with FFmpeg 4.2. 2021-05-26 09:59:25 +04:00
John Preston
479b604c0e Closed alpha version 2.7.5.5. 2021-05-25 23:34:55 +04:00
John Preston
e7ef3c4b6d Fix crash in GL_RED textures uploading. 2021-05-25 23:34:55 +04:00
John Preston
87cae1c3a7 Fix build on macOS. 2021-05-25 23:34:55 +04:00
John Preston
562fc74481 Closed alpha version 2.7.5.4. 2021-05-25 22:11:11 +04:00
John Preston
51d8e9c43d Skip empty rects in painting. 2021-05-25 17:23:50 +04:00
John Preston
e50a7a2e42 Toggle wide mode only when videos with frames. 2021-05-25 16:55:01 +04:00
John Preston
aaad250a77 Show names in OpenGL renderer. 2021-05-25 16:26:41 +04:00
John Preston
699730b7f4 Show mute icon in OpenGL renderer. 2021-05-25 14:56:26 +04:00
John Preston
302cffba1c Display pin button in OpenGL renderer. 2021-05-25 12:08:06 +04:00
John Preston
e299aa032d Update tg_owt to webrtc m91. 2021-05-25 12:07:49 +04:00
John Preston
ca6f70746c Closed alpha version 2.7.5.3. 2021-05-24 22:45:16 +04:00
John Preston
2af1d95650 Fix scheduled voice chat creation. 2021-05-24 22:45:16 +04:00
John Preston
df6f5d83d6 Make shaders work on OpenGL 2.1. 2021-05-24 22:45:16 +04:00
John Preston
42baa3e1bc Convert YUV420 -> ARGB32 in fragment shader. 2021-05-24 22:45:16 +04:00
John Preston
5f393babd6 Fix video wrap geometry in narrow column. 2021-05-24 22:45:16 +04:00
John Preston
b864563f47 Support mode switching in single widget Viewport. 2021-05-24 22:45:16 +04:00
John Preston
3edb2d08ba Optimize frame shader, apply rotation. 2021-05-24 22:45:16 +04:00
John Preston
d44f923277 OpenGL render of frames in single widget. 2021-05-24 22:45:16 +04:00
John Preston
ec468431b4 Raster render of wide mode in single widget. 2021-05-24 22:45:16 +04:00
John Preston
4774f438a9 Update API scheme. 2021-05-24 22:45:16 +04:00
John Preston
f40659a7b4 Round corners of LargeVideo. 2021-05-24 22:45:16 +04:00
John Preston
047989abcf Fill solid background in OpenGL renderer. 2021-05-24 22:45:16 +04:00
John Preston
3e79b67032 Start OpenGL renderer for group calls. 2021-05-24 22:45:16 +04:00
John Preston
ca4b1e6ae0 Fix build for macOS. 2021-05-24 22:45:16 +04:00
John Preston
b56749426b Fix build on Clang/GCC. 2021-05-24 22:45:16 +04:00
John Preston
cbe6e1caad Closed alpha version 2.7.5.2. 2021-05-24 22:45:16 +04:00
John Preston
748eb9ff12 Remove labels from wide mode buttons. 2021-05-24 22:45:16 +04:00
John Preston
385b98ff3d Nice three-button narrow mode with gradient fading. 2021-05-24 22:45:16 +04:00
John Preston
c12a50544e Allow force-disabling OpenGL. 2021-05-24 22:45:15 +04:00
John Preston
c64e953174 Choose OpenGL / Raster in media viewer. 2021-05-24 22:45:15 +04:00
John Preston
ccc599c83e Fix PiP window first show. 2021-05-24 22:45:15 +04:00
John Preston
a45064257a Choose OpenGL / Raster surface at runtime. 2021-05-24 22:45:15 +04:00
John Preston
9510ba07f7 Drop old sticker set cover locations. 2021-05-24 22:45:15 +04:00
John Preston
8e3dc76dd7 Disable tg_owt audio backends explicitly. 2021-05-24 22:45:15 +04:00
John Preston
451332b2e7 Closed alpha version 2.7.5.1. 2021-05-24 22:45:15 +04:00
John Preston
445c798bbc Improve pin video button design and controls hiding. 2021-05-24 22:45:15 +04:00
John Preston
c48c4d4283 Use QOpenGLWidget on all systems. 2021-05-24 22:45:15 +04:00
John Preston
b421d0c5cc Build Qt with dynamic OpenGL on Windows. 2021-05-24 22:45:15 +04:00
John Preston
f7454a4284 Fix crash on quit in idle state. 2021-05-24 22:45:15 +04:00
John Preston
9144f4ea7b Fix streaming frames prepare. 2021-05-24 22:45:15 +04:00
John Preston
aaea367fba Hide controls when mouse is out of video area. 2021-05-24 22:45:15 +04:00
John Preston
e0e878cbb1 Update tg_owt to webrtc m90. 2021-05-24 22:45:15 +04:00
John Preston
b905a18161 Destroy all tgcalls instances before quit. 2021-05-24 22:45:15 +04:00
John Preston
f4ae7ecbe7 Remove tracking of video ssrc-s. 2021-05-24 22:45:15 +04:00
John Preston
9a8812d00b Move participants list to the right of the window. 2021-05-24 22:45:15 +04:00
John Preston
13b3de683a Improve narrow participants column design. 2021-05-24 22:45:15 +04:00
John Preston
64243d1437 Fix crash in joining active video chat. 2021-05-24 22:45:15 +04:00
John Preston
a730c88491 Add icons and improve narrow participants column. 2021-05-24 22:45:15 +04:00
John Preston
bd90cc4134 Fix closing of pre-launch windows. 2021-05-24 22:45:15 +04:00
John Preston
316f0537c4 Implement video pin / controls hiding in video tiles. 2021-05-24 22:45:15 +04:00
John Preston
7f739065e8 First version of tiled layout. 2021-05-24 22:45:15 +04:00
John Preston
bd83ed8130 Add 'pin screencast' context menu item. 2021-05-24 22:45:15 +04:00
John Preston
e39ffbc83c Update tgcalls, request required video channels. 2021-05-24 22:45:15 +04:00
John Preston
1471e9b8e2 Destroy group call instances async. 2021-05-24 22:45:15 +04:00
John Preston
4c23d51be5 Fix volume icon over video. 2021-05-24 22:45:15 +04:00
John Preston
412cfb24d2 Stop video when rejoining-as, handle errors. 2021-05-24 22:45:15 +04:00
John Preston
2a5977e97f Support enlarge / minimize of video. 2021-05-24 22:45:15 +04:00
John Preston
64c34b7029 Hide controls in wide video mode. 2021-05-24 22:45:15 +04:00
John Preston
0db0abe608 Use LargeVideo in the default mode. 2021-05-24 22:45:15 +04:00
John Preston
5f4903a279 Show controls in the middle of wide video. 2021-05-24 22:45:14 +04:00
John Preston
20ff79abf4 Fix camera / screen self track activation. 2021-05-24 22:45:14 +04:00
John Preston
3a321d64f6 Switch between videos by left click. 2021-05-24 22:45:14 +04:00
John Preston
7e8d1f7974 Toggle video pin from LargeVideo. 2021-05-24 22:45:14 +04:00
John Preston
9f41461209 Load .dll symbols in a similar way. 2021-05-24 22:45:14 +04:00
John Preston
6b10045b7b Enable screen sharing on Linux. 2021-05-24 22:45:14 +04:00
John Preston
9ca6d0d893 Build tg_owt with desktop_capture support. 2021-05-24 22:45:14 +04:00
John Preston
2830049a53 Add support for DirectX desktop capturer backend. 2021-05-24 22:45:14 +04:00
John Preston
50558de591 Show name and information on wide large video. 2021-05-24 22:45:14 +04:00
John Preston
80e3e8a01e Extract MembersRow from calls_group_members module. 2021-05-24 22:45:14 +04:00
John Preston
d38780c94d Add shadow under name over video. 2021-05-24 22:45:14 +04:00
John Preston
801435e57c Show participant names in narrow column. 2021-05-24 22:45:14 +04:00
John Preston
8001efe6ab Track peer together with video endpoint. 2021-05-24 22:45:14 +04:00
John Preston
909a3cef9b Create a new Instance for each screencast. 2021-05-24 22:45:14 +04:00
John Preston
9ac510a1ad Fix title of wide mode video chat. 2021-05-24 22:45:14 +04:00
John Preston
00ce302b38 Improve narrow participants column design. 2021-05-24 22:45:14 +04:00
John Preston
0dcc7a05f7 Fix crash in pinned video switching. 2021-05-24 22:45:14 +04:00
John Preston
54c2769d8a Improve voice /video chat members management. 2021-05-24 22:45:14 +04:00
John Preston
2e400d88d3 Fix creating group calls. 2021-05-24 22:45:14 +04:00
John Preston
d9aa660253 Handle members slice loaded. 2021-05-24 22:45:14 +04:00
John Preston
ba1dade4b0 New API/tgcalls with two outgoing videos. 2021-05-24 22:45:14 +04:00
John Preston
a48649987e Improve screencast source choosing design. 2021-05-24 22:45:14 +04:00
John Preston
022c0a1327 Update tgcalls library. 2021-05-24 22:45:14 +04:00
John Preston
69ceed5bbc Update API scheme to layer 129. 2021-05-24 22:45:14 +04:00
John Preston
b3fcb4ef36 Allow 'mute for me' of muted by admin participants. 2021-05-24 22:45:14 +04:00
John Preston
8342b2d275 Fix bug with video_muted flag. 2021-05-24 22:45:14 +04:00
John Preston
36888f844f Disable (crashing) capturer on Linux. 2021-05-24 22:45:14 +04:00
John Preston
75f220c3d9 Fix build for Linux. 2021-05-24 22:45:14 +04:00
John Preston
1a784fc678 Track video_muted from API. 2021-05-24 22:45:14 +04:00
John Preston
dac9017df1 Improve video chat controls layout. 2021-05-24 22:45:14 +04:00
John Preston
7b3b5a1463 Use 'Screencast' video content type. 2021-05-24 22:45:14 +04:00
John Preston
b7fc3f67d7 Add toggle video and screen sharing buttons. 2021-05-24 22:45:13 +04:00
John Preston
e0bfaad3a2 Make style of mute button customizable. 2021-05-24 22:45:13 +04:00
John Preston
24c77a8956 Fix build on macOS. 2021-05-24 22:45:13 +04:00
John Preston
380a0d1f86 Improve wide video layout. 2021-05-24 22:45:13 +04:00
John Preston
b7f6fc9a2d Update API scheme. 2021-05-24 22:45:13 +04:00
John Preston
e12fe974b2 Add pinned video in wide mode. 2021-05-24 22:45:13 +04:00
John Preston
b15623d435 Allow pinning video to top of members list. 2021-05-24 22:45:13 +04:00
John Preston
eb8f709943 Show members list in PanelMode::Wide. 2021-05-24 22:45:13 +04:00
John Preston
c93ddf6aac Separate Call/GroupCall delegates and Instance. 2021-05-24 22:45:13 +04:00
John Preston
6e34360f7e Move some group call modules. 2021-05-24 22:45:13 +04:00
John Preston
c9d07cd0f8 Proof-of-concept desktop capture source picker. 2021-05-24 22:45:13 +04:00
John Preston
9ff6b57b94 Use common desktop_capturer code on Windows. 2021-05-24 22:45:13 +04:00
John Preston
fb49b0ca27 Add proof-of-concept screen sharing on macOS. 2021-05-24 22:45:13 +04:00
John Preston
fef1f80570 Disable video preview in Settings when in group call. 2021-05-24 22:45:13 +04:00
John Preston
38cb1b195d Add proof-of-concept screen sharing on Windows. 2021-05-24 22:45:13 +04:00
John Preston
ebdbe4a8d6 Show video instead of userpics in members list. 2021-05-24 22:45:13 +04:00
John Preston
ba02a5c46a Resolve video chat participants by unknown ssrcs. 2021-05-24 22:45:13 +04:00
John Preston
a6f379a17a Parse and serialize video parameters. 2021-05-24 22:45:13 +04:00
John Preston
a41b7b62ac Build and link rnnoise on Windows. 2021-05-24 22:45:13 +04:00
Ilya Fedin
5010c9033b Specify buildtype for meson 2021-05-22 17:31:26 +03:00
23rd
93e4161d5e Fixed NuGet link in instructions for Windows build. 2021-05-19 14:39:22 +03:00
Ilya Fedin
e0d6faf45b Fix build with LTO 2021-05-19 12:26:07 +03:00
John Preston
fbe4e3f0ec Fix build with mallocng. 2021-05-17 13:38:28 +04:00
John Preston
8e02c50f7d Fix build on Linux. 2021-05-17 13:07:39 +04:00
Ilya Fedin
837485974a Use mallocng on Linux 2021-05-17 10:35:18 +03:00
Ilya Fedin
3cf739eca9 Use event filter to get surface expose event 2021-05-17 10:00:01 +03:00
Ilya Fedin
cfee688feb Replace call_delayed with InvokeQueued in MainWindow::handleVisibleChanged 2021-05-17 10:00:01 +03:00
Ilya Fedin
30d8894c30 Use nodiscard in WaylandIntegration 2021-05-17 10:00:01 +03:00
Ilya Fedin
0b86feeeb5 Implement appmenu on Wayland with org_kde_kwin_appmenu protocol 2021-05-17 10:00:01 +03:00
Ilya Fedin
434ef34378 Implement taskbar icon hidding on Wayland with org_kde_plasma_shell protocol 2021-05-17 10:00:01 +03:00
Ilya Fedin
166c28c215 Get rid of default_delete 2021-05-17 10:00:01 +03:00
Ilya Fedin
17c514e851 Use surface as XdgExporter parent 2021-05-17 10:00:01 +03:00
Ilya Fedin
f7489592d6 Fix BIO_new_mem_buf leaks 2021-05-17 09:53:02 +03:00
Ilya Fedin
3cb9312805 NEON support for ARMv7 is fixed in tg_owt 2021-05-16 11:28:11 +03:00
Ilya Fedin
3722486b19 Add new tg_owt dependencies to snap 2021-05-16 11:28:11 +03:00
John Preston
57b3982346 Update tg_owt in Snap build. 2021-05-14 15:22:39 +04:00
John Preston
a8807bc915 Fix voice recoding with FFmpeg 4.4.
Fixes #16217.
2021-05-13 15:36:27 +04:00
John Preston
71deaa48af Don't crash on voice recording error.
Fixes #16217.
2021-05-13 15:36:24 +04:00
John Preston
e7ca35a276 Fix possible deadlock in debug logs. 2021-05-13 15:36:08 +04:00
John Preston
2d8f43bd8c Fix text color for crash report window. 2021-05-13 15:35:36 +04:00
John Preston
383acf0ffc Fix crash in native notifications on Linux. 2021-05-12 12:10:55 +04:00
c0re100
ee156fc6a8 Add "Archive Sticker" into Sticker Box 3dots menu 2021-05-11 10:54:25 +03:00
Ilya Fedin
680a9a7ca7 Implement parent setting for portal and gtk dialogs on Wayland via xdg-foreign-v2 2021-05-11 10:53:32 +03:00
Ilya Fedin
7de8d6f9ac Fix resetting of available geometry fix in some cases 2021-05-11 10:43:04 +03:00
John Preston
d79fab8b3c Build ffmpeg with 'CONFIG_SAFE_BITSTREAM_READER' on macOS. 2021-05-10 16:45:21 +04:00
John Preston
0cb32181c5 Handle small SLOWMODE_WAIT as FLOOD_WAIT. 2021-05-10 16:44:28 +04:00
John Preston
dba3c39726 Skip 'enhancement' issues by stale bot. 2021-05-10 13:53:54 +04:00
Ilya Fedin
95b4435396 Resubscribe to signal when running with old xdg-desktop-portal 2021-05-07 18:32:02 +03:00
466 changed files with 27746 additions and 13365 deletions

2
.github/stale.yml vendored
View File

@@ -3,7 +3,7 @@ daysUntilStale: 180
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 30
# Issues with these labels will never be considered stale
exemptLabels: []
exemptLabels: [ "enhancement" ]
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable

View File

@@ -93,6 +93,9 @@ jobs:
DEFINE=""
if [ -n "${{ matrix.defines }}" ]; then
DEFINE="-D ${{ matrix.defines }}=ON"
if [ "${{ matrix.defines }}" == "DESKTOP_APP_DISABLE_DBUS_INTEGRATION" ]; then
DEFINE="$DEFINE -D DESKTOP_APP_DISABLE_GTK_INTEGRATION=ON"
fi
echo Define from matrix: $DEFINE
echo "ARTIFACT_NAME=Telegram_${{ matrix.defines }}" >> $GITHUB_ENV
else

View File

@@ -205,6 +205,16 @@ jobs:
cd $LibrariesPath
sudo cp -R opus-cache/. /
- name: Rnnoise.
run: |
cd $LibrariesPath
git clone $GIT/desktop-app/rnnoise.git
mkdir -p rnnoise/out/Debug
cd rnnoise/out/Debug
cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug ../..
ninja
- name: Libiconv cache.
id: cache-libiconv
uses: actions/cache@v2
@@ -240,7 +250,7 @@ jobs:
git clone $GIT/FFmpeg/FFmpeg.git ffmpeg
cd ffmpeg
git checkout release/4.2
git checkout release/4.4
CFLAGS=`freetype-config --cflags`
LDFLAGS=`freetype-config --libs`
PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig:/usr/lib/pkgconfig:/usr/X11/lib/pkgconfig
@@ -317,7 +327,6 @@ jobs:
--enable-decoder=pcm_u32be \
--enable-decoder=pcm_u32le \
--enable-decoder=pcm_u8 \
--enable-decoder=pcm_zork \
--enable-decoder=vorbis \
--enable-decoder=wavpack \
--enable-decoder=wmalossless \
@@ -490,6 +499,7 @@ jobs:
cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Debug \
-DTG_OWT_SPECIAL_TARGET=mac \
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF \
-DTG_OWT_LIBJPEG_INCLUDE_PATH=$PREFIX/include \
-DTG_OWT_OPENSSL_INCLUDE_PATH=`pwd`/../../../openssl_$OPENSSL_VER/include \
-DTG_OWT_OPUS_INCLUDE_PATH=$PREFIX/include/opus \

View File

@@ -284,9 +284,16 @@ jobs:
msbuild -m opus.sln /property:Configuration=Debug /property:Platform="Win32"
msbuild -m opus.sln /property:Configuration=Release /property:Platform="Win32"
echo "Workaround for FFmpeg."
copy Win32\Release\m.lib Win32\Release\ssp.lib
copy Win32\Release\m.lib Win32\Debug\ssp.lib
- name: Rnnoise.
shell: cmd
run: |
%VC%
git clone %GIT%/desktop-app/rnnoise.git
mkdir rnnoise\out
cd rnnoise\out
cmake -A Win32 ..
cmake --build . --config Debug
- name: FFmpeg cache.
id: cache-ffmpeg
@@ -302,7 +309,7 @@ jobs:
git clone %GIT%/FFmpeg/FFmpeg.git ffmpeg
cd ffmpeg
git checkout release/4.2
git checkout release/4.4
set CHERE_INVOKING=enabled_from_arguments
set MSYS2_PATH_TYPE=inherit
call c:\tools\msys64\usr\bin\bash --login ../patches/build_ffmpeg_win.sh
@@ -341,7 +348,7 @@ jobs:
-confirm-license ^
-static ^
-static-runtime -I "%SSL%\include" ^
-no-opengl ^
-opengl dynamic ^
-openssl-linked ^
OPENSSL_LIBS_DEBUG="%SSL%\out32.dbg\libssl.lib %SSL%\out32.dbg\%LIBS%" ^
OPENSSL_LIBS_RELEASE="%SSL%\out32\libssl.lib %SSL%\out32\%LIBS%" ^
@@ -381,6 +388,7 @@ jobs:
cmake -G Ninja ^
-DCMAKE_BUILD_TYPE=Debug ^
-DTG_OWT_SPECIAL_TARGET=win ^
-DTG_OWT_BUILD_AUDIO_BACKENDS=OFF ^
-DTG_OWT_LIBJPEG_INCLUDE_PATH=%cd%/../../../mozjpeg ^
-DTG_OWT_OPENSSL_INCLUDE_PATH=%cd%/../../../openssl_%OPENSSL_VER%/include ^
-DTG_OWT_OPUS_INCLUDE_PATH=%cd%/../../../opus/include ^
@@ -409,6 +417,9 @@ jobs:
fi
echo "TDESKTOP_BUILD_DEFINE=$DEFINE" >> $GITHUB_ENV
- name: Free up some disk space.
run: del /S *.pdb
- name: Telegram Desktop build.
if: env.ONLY_CACHE == 'false'
run: |

6
.gitmodules vendored
View File

@@ -76,9 +76,6 @@
[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/fcitx5-qt"]
path = Telegram/ThirdParty/fcitx5-qt
url = https://github.com/fcitx/fcitx5-qt.git
@@ -91,3 +88,6 @@
[submodule "Telegram/lib_webview"]
path = Telegram/lib_webview
url = https://github.com/desktop-app/lib_webview.git
[submodule "Telegram/lib_waylandshells"]
path = Telegram/lib_waylandshells
url = https://github.com/desktop-app/lib_waylandshells.git

View File

@@ -31,6 +31,7 @@ include(cmake/target_link_static_libraries.cmake)
include(cmake/target_link_frameworks.cmake)
include(cmake/init_target.cmake)
include(cmake/generate_target.cmake)
include(cmake/nuget.cmake)
include(cmake/options.cmake)

View File

@@ -53,13 +53,13 @@ Version **1.8.15** was the last that supports older systems
* Guideline Support Library ([MIT License](https://github.com/Microsoft/GSL/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))
* Vazir font ([SIL Open Font License 1.1](https://github.com/rastikerdar/vazir-font/blob/master/OFL.txt))
* 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))
* QR Code generator ([MIT License](https://github.com/nayuki/QR-Code-generator#license))
* CMake ([New BSD License](https://github.com/Kitware/CMake/blob/master/Copyright.txt))
* Hunspell ([GPL](https://github.com/hunspell/hunspell/blob/master/COPYING))
* Hunspell ([LGPL](https://github.com/hunspell/hunspell/blob/master/COPYING.LESSER))
## Build instructions

View File

@@ -18,6 +18,9 @@ endif()
add_subdirectory(lib_storage)
add_subdirectory(lib_lottie)
add_subdirectory(lib_qr)
if (LINUX AND NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
add_subdirectory(lib_waylandshells)
endif()
add_subdirectory(lib_webrtc)
add_subdirectory(lib_webview)
add_subdirectory(codegen)
@@ -79,12 +82,7 @@ PRIVATE
desktop-app::external_xxhash
)
if (WIN32)
target_link_libraries(Telegram
PRIVATE
desktop-app::lib_webview_winrt
)
elseif (LINUX)
if (LINUX)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_glibmm
@@ -95,7 +93,6 @@ elseif (LINUX)
target_link_libraries(Telegram
PRIVATE
desktop-app::external_statusnotifieritem
desktop-app::external_dbusmenu_qt
)
endif()
@@ -109,11 +106,13 @@ elseif (LINUX)
if (NOT DESKTOP_APP_DISABLE_WAYLAND_INTEGRATION)
target_link_libraries(Telegram
PRIVATE
desktop-app::lib_waylandshells
desktop-app::external_kwayland
)
endif()
if (NOT DESKTOP_APP_DISABLE_GTK_INTEGRATION)
target_link_libraries(Telegram PRIVATE rt)
find_package(PkgConfig REQUIRED)
if (DESKTOP_APP_USE_PACKAGED AND NOT DESKTOP_APP_USE_PACKAGED_LAZY)
@@ -125,7 +124,7 @@ elseif (LINUX)
target_link_libraries(Telegram PRIVATE PkgConfig::X11)
endif()
else()
pkg_search_module(GTK REQUIRED gtk+-3.0 gtk+-2.0)
pkg_check_modules(GTK REQUIRED gtk+-3.0)
target_include_directories(Telegram PRIVATE ${GTK_INCLUDE_DIRS})
if (NOT DESKTOP_APP_DISABLE_X11_INTEGRATION)
@@ -271,23 +270,39 @@ PRIVATE
boxes/url_auth_box.h
boxes/username_box.cpp
boxes/username_box.h
calls/group/calls_choose_join_as.cpp
calls/group/calls_choose_join_as.h
calls/group/calls_group_call.cpp
calls/group/calls_group_call.h
calls/group/calls_group_common.h
calls/group/calls_group_invite_controller.cpp
calls/group/calls_group_invite_controller.h
calls/group/calls_group_members.cpp
calls/group/calls_group_members.h
calls/group/calls_group_members_row.cpp
calls/group/calls_group_members_row.h
calls/group/calls_group_menu.cpp
calls/group/calls_group_menu.h
calls/group/calls_group_panel.cpp
calls/group/calls_group_panel.h
calls/group/calls_group_settings.cpp
calls/group/calls_group_settings.h
calls/group/calls_group_toasts.cpp
calls/group/calls_group_toasts.h
calls/group/calls_group_viewport.cpp
calls/group/calls_group_viewport.h
calls/group/calls_group_viewport_opengl.cpp
calls/group/calls_group_viewport_opengl.h
calls/group/calls_group_viewport_raster.cpp
calls/group/calls_group_viewport_raster.h
calls/group/calls_group_viewport_tile.cpp
calls/group/calls_group_viewport_tile.h
calls/group/calls_volume_item.cpp
calls/group/calls_volume_item.h
calls/calls_box_controller.cpp
calls/calls_box_controller.h
calls/calls_call.cpp
calls/calls_call.h
calls/calls_choose_join_as.cpp
calls/calls_choose_join_as.h
calls/calls_group_call.cpp
calls/calls_group_call.h
calls/calls_group_common.h
calls/calls_group_members.cpp
calls/calls_group_members.h
calls/calls_group_menu.cpp
calls/calls_group_menu.h
calls/calls_group_panel.cpp
calls/calls_group_panel.h
calls/calls_group_settings.cpp
calls/calls_group_settings.h
calls/calls_emoji_fingerprint.cpp
calls/calls_emoji_fingerprint.h
calls/calls_instance.cpp
@@ -302,8 +317,8 @@ PRIVATE
calls/calls_userpic.h
calls/calls_video_bubble.cpp
calls/calls_video_bubble.h
calls/calls_volume_item.cpp
calls/calls_volume_item.h
calls/calls_video_incoming.cpp
calls/calls_video_incoming.h
chat_helpers/bot_keyboard.cpp
chat_helpers/bot_keyboard.h
chat_helpers/emoji_keywords.cpp
@@ -352,6 +367,8 @@ PRIVATE
core/core_cloud_password.h
core/core_settings.cpp
core/core_settings.h
core/core_settings_proxy.cpp
core/core_settings_proxy.h
core/crash_report_window.cpp
core/crash_report_window.h
core/crash_reports.cpp
@@ -377,6 +394,7 @@ PRIVATE
data/stickers/data_stickers_set.h
data/stickers/data_stickers.cpp
data/stickers/data_stickers.h
data/data_abstract_sparse_ids.h
data/data_abstract_structure.cpp
data/data_abstract_structure.h
data/data_auto_download.cpp
@@ -399,10 +417,14 @@ PRIVATE
data/data_document.h
data/data_document_media.cpp
data/data_document_media.h
data/data_document_resolver.cpp
data/data_document_resolver.h
data/data_drafts.cpp
data/data_drafts.h
data/data_folder.cpp
data/data_folder.h
data/data_file_click_handler.cpp
data/data_file_click_handler.h
data/data_file_origin.cpp
data/data_file_origin.h
data/data_flags.h
@@ -708,6 +730,8 @@ PRIVATE
main/main_session.h
main/main_session_settings.cpp
main/main_session_settings.h
media/system_media_controls_manager.h
media/system_media_controls_manager.cpp
media/audio/media_audio.cpp
media/audio/media_audio.h
media/audio/media_audio_capture.cpp
@@ -762,14 +786,25 @@ PRIVATE
media/streaming/media_streaming_video_track.h
media/view/media_view_group_thumbs.cpp
media/view/media_view_group_thumbs.h
media/view/media_view_overlay_opengl.cpp
media/view/media_view_overlay_opengl.h
media/view/media_view_overlay_raster.cpp
media/view/media_view_overlay_raster.h
media/view/media_view_overlay_renderer.h
media/view/media_view_overlay_widget.cpp
media/view/media_view_overlay_widget.h
media/view/media_view_pip.cpp
media/view/media_view_pip.h
media/view/media_view_pip_opengl.cpp
media/view/media_view_pip_opengl.h
media/view/media_view_pip_raster.cpp
media/view/media_view_pip_raster.h
media/view/media_view_pip_renderer.h
media/view/media_view_playback_controls.cpp
media/view/media_view_playback_controls.h
media/view/media_view_playback_progress.cpp
media/view/media_view_playback_progress.h
media/view/media_view_open_common.h
mtproto/config_loader.cpp
mtproto/config_loader.h
mtproto/connection_abstract.cpp
@@ -828,16 +863,12 @@ PRIVATE
platform/linux/linux_gdk_helper.h
platform/linux/linux_gsd_media_keys.cpp
platform/linux/linux_gsd_media_keys.h
platform/linux/linux_gtk_file_dialog.cpp
platform/linux/linux_gtk_file_dialog.h
platform/linux/linux_gtk_integration_dummy.cpp
platform/linux/linux_gtk_integration_p.h
platform/linux/linux_gtk_integration.cpp
platform/linux/linux_gtk_integration.h
platform/linux/linux_gtk_open_with_dialog.cpp
platform/linux/linux_gtk_open_with_dialog.h
platform/linux/linux_mpris_support.cpp
platform/linux/linux_mpris_support.h
platform/linux/linux_notification_service_watcher.cpp
platform/linux/linux_notification_service_watcher.h
platform/linux/linux_wayland_integration_dummy.cpp
@@ -1040,6 +1071,8 @@ PRIVATE
ui/search_field_controller.h
ui/special_buttons.cpp
ui/special_buttons.h
ui/text/format_song_document_name.cpp
ui/text/format_song_document_name.h
ui/unread_badge.cpp
ui/unread_badge.h
window/main_window.cpp
@@ -1053,6 +1086,8 @@ PRIVATE
window/section_memento.h
window/section_widget.cpp
window/section_widget.h
window/window_adaptive.cpp
window/window_adaptive.h
window/window_connecting_widget.cpp
window/window_connecting_widget.h
window/window_controller.cpp
@@ -1159,8 +1194,6 @@ if (DESKTOP_APP_DISABLE_GTK_INTEGRATION)
remove_target_sources(Telegram ${src_loc}
platform/linux/linux_gdk_helper.cpp
platform/linux/linux_gdk_helper.h
platform/linux/linux_gtk_file_dialog.cpp
platform/linux/linux_gtk_file_dialog.h
platform/linux/linux_gtk_integration_p.h
platform/linux/linux_gtk_integration.cpp
platform/linux/linux_gtk_open_with_dialog.cpp
@@ -1211,8 +1244,6 @@ if (WIN32)
# $<IF:${release},"Appending compatibility manifest.","Finalizing build.">
# )
elseif (APPLE)
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()
@@ -1327,6 +1358,32 @@ endif()
set_target_properties(Telegram PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${output_folder})
if (WIN32)
target_link_options(Telegram
PRIVATE
/DELAYLOAD:secur32.dll
/DELAYLOAD:winmm.dll
/DELAYLOAD:ws2_32.dll
/DELAYLOAD:user32.dll
/DELAYLOAD:gdi32.dll
/DELAYLOAD:advapi32.dll
/DELAYLOAD:shell32.dll
/DELAYLOAD:ole32.dll
/DELAYLOAD:oleaut32.dll
/DELAYLOAD:shlwapi.dll
/DELAYLOAD:iphlpapi.dll
/DELAYLOAD:gdiplus.dll
/DELAYLOAD:version.dll
/DELAYLOAD:dwmapi.dll
/DELAYLOAD:crypt32.dll
/DELAYLOAD:bcrypt.dll
/DELAYLOAD:imm32.dll
/DELAYLOAD:netapi32.dll
/DELAYLOAD:userenv.dll
/DELAYLOAD:wtsapi32.dll
)
endif()
if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT build_winstore)
add_executable(Updater WIN32)
init_target(Updater)
@@ -1343,8 +1400,26 @@ if ((NOT DESKTOP_APP_DISABLE_AUTOUPDATE OR APPLE) AND NOT build_macstore AND NOT
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)
if (WIN32)
get_filename_component(lib_base_loc lib_base REALPATH)
nice_target_sources(Updater ${lib_base_loc}
PRIVATE
base/platform/win/base_windows_safe_library.cpp
base/platform/win/base_windows_safe_library.h
)
target_include_directories(Updater PRIVATE ${lib_base_loc})
if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
target_link_options(Updater
PRIVATE
/DELAYLOAD:user32.dll
/DELAYLOAD:advapi32.dll
/DELAYLOAD:shell32.dll
/DELAYLOAD:ole32.dll
/DELAYLOAD:shlwapi.dll
)
else()
target_link_options(Updater PRIVATE -municode)
endif()
endif()
if (LINUX)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 991 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 756 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 532 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 560 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 965 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 413 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 622 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 854 B

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -451,6 +451,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_settings_system_integration" = "System integration";
"lng_settings_performance" = "Performance";
"lng_settings_enable_animations" = "Enable animations";
"lng_settings_enable_opengl" = "Enable OpenGL rendering for media";
"lng_settings_angle_backend" = "ANGLE graphics backend";
"lng_settings_angle_backend_auto" = "Auto";
"lng_settings_angle_backend_d3d9" = "Direct3D 9";
"lng_settings_angle_backend_d3d11" = "Direct3D 11";
"lng_settings_angle_backend_d3d11on12" = "D3D11on12";
"lng_settings_angle_backend_opengl" = "OpenGL";
"lng_settings_angle_backend_disabled" = "Disabled";
"lng_settings_sensitive_title" = "Sensitive content";
"lng_settings_sensitive_disable_filtering" = "Disable filtering";
"lng_settings_sensitive_about" = "Display sensitive media in public channels on all your Telegram devices.";
@@ -496,6 +504,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_background_text1" = "Ah, you kids today with techno music! You should enjoy the classics, like Hasselhoff!";
"lng_background_text2" = "I can't even take you seriously right now.";
"lng_background_bad_link" = "This background link appears to be invalid.";
"lng_background_gradient_unsupported" = "Telegram Desktop doesn't support gradient backgrounds yet.";
"lng_background_apply" = "Apply";
"lng_background_share" = "Share";
"lng_background_link_copied" = "Link copied to clipboard";
@@ -1005,6 +1014,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_report_group_title" = "Report group";
"lng_report_bot_title" = "Report bot";
"lng_report_message_title" = "Report message";
"lng_report_please_select_messages" = "Please select messages to report.";
"lng_report_select_messages" = "Select messages";
"lng_report_messages_none" = "Select Messages";
"lng_report_messages_count#one" = "Report {count} Message";
@@ -1401,6 +1411,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_stickers_search_sets" = "Search sticker sets";
"lng_stickers_nothing_found" = "No stickers found";
"lng_stickers_remove_pack_confirm" = "Remove";
"lng_stickers_archive_pack" = "Archive Stickers";
"lng_stickers_has_been_archived" = "Sticker pack has been archived.";
"lng_in_dlg_photo" = "Photo";
"lng_in_dlg_album" = "Album";
@@ -1996,8 +2008,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_raised_hand_status" = "wants to speak";
"lng_group_call_settings" = "Settings";
"lng_group_call_share_button" = "Share";
"lng_group_call_video" = "Video";
"lng_group_call_screen_share_start" = "Share Screen";
"lng_group_call_screen_share_stop" = "Stop Sharing";
"lng_group_call_screen_title" = "Screen {index}";
"lng_group_call_unmute_small" = "Unmute";
"lng_group_call_more" = "More";
"lng_group_call_unmute" = "Unmute";
"lng_group_call_unmute_sub" = "or hold spacebar to talk";
"lng_group_call_unmute_sub" = "Hold space bar to temporarily unmute.";
"lng_group_call_you_are_live" = "You are Live";
"lng_group_call_force_muted" = "Muted by admin";
"lng_group_call_force_muted_sub" = "You are in Listen Only mode";
@@ -2015,6 +2033,18 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_create_sure" = "Do you really want to start a voice chat in this group?";
"lng_group_call_create_sure_channel" = "Are you sure you want to start a voice chat in this channel as your personal account?";
"lng_group_call_join_sure_personal" = "Are you sure you want to join this voice chat as your personal account?";
"lng_group_call_muted_no_camera" = "You can't turn on video while you're muted by admin.";
"lng_group_call_muted_no_screen" = "You can't share your screen while you're muted by admin.";
"lng_group_call_chat_no_camera" = "You can't turn on video in this chat.";
"lng_group_call_chat_no_screen" = "You can't share your screen in this chat.";
"lng_group_call_failed_screen" = "An error occured. Screencast has stopped.";
"lng_group_call_failed_camera" = "Could not enable camera. Perhaps another app is using the camera already. Try closing other apps.";
"lng_group_call_tooltip_screen" = "Share screen";
"lng_group_call_tooltip_camera" = "Your camera is off. Click here to enable camera.";
"lng_group_call_tooltip_microphone" = "You are on mute. Click here to speak.";
"lng_group_call_tooltip_camera_off" = "Disable camera";
"lng_group_call_tooltip_force_muted" = "Muted by admin. Click if you want to speak.";
"lng_group_call_tooltip_raised_hand" = "You asked to speak. We let the speakers know.";
"lng_group_call_also_end" = "End voice chat";
"lng_group_call_settings_title" = "Settings";
"lng_group_call_invite" = "Invite Member";
@@ -2037,6 +2067,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_ptt_delay_s" = "{amount}s";
"lng_group_call_ptt_delay" = "Push to Talk release delay: {delay}";
"lng_group_call_share" = "Share Invite Link";
"lng_group_call_noise_suppression" = "Enable Noise Suppression";
"lng_group_call_limit#one" = "Video is only available\nfor the first {count} member";
"lng_group_call_limit#other" = "Video is only available\nfor the first {count} members";
"lng_group_call_video_paused" = "Video is paused";
"lng_group_call_share_speaker" = "Users with this link can speak";
"lng_group_call_copy_speaker_link" = "Copy Speaker Link";
"lng_group_call_copy_listener_link" = "Copy Listener Link";
@@ -2057,6 +2091,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_context_remove_hand" = "Cancel request to speak";
"lng_group_call_context_mute_for_me" = "Mute for me";
"lng_group_call_context_unmute_for_me" = "Unmute for me";
"lng_group_call_context_pin_camera" = "Pin video";
"lng_group_call_context_unpin_camera" = "Unpin video";
"lng_group_call_context_pin_screen" = "Pin screencast";
"lng_group_call_context_unpin_screen" = "Unpin screencast";
"lng_group_call_context_remove" = "Remove";
"lng_group_call_remove_channel" = "Remove {channel} from the voice chat?";
"lng_group_call_duration_days#one" = "{count} day";
@@ -2070,6 +2108,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_mac_access" = "Telegram Desktop does not have access to system wide keyboard input required for Push to Talk.";
"lng_group_call_mac_input" = "Please allow **Input Monitoring** for Telegram in Privacy Settings.";
"lng_group_call_mac_accessibility" = "Please allow **Accessibility** for Telegram in Privacy Settings.\n\nApp restart may be required.";
"lng_group_call_mac_screencast_access" = "Telegram Desktop does not have access to screen recording required for Screen Sharing.";
"lng_group_call_mac_recording" = "Please allow **Screen Recording** for Telegram in Privacy Settings.";
"lng_group_call_mac_settings" = "Open Settings";
"lng_group_call_start_as_header" = "Start Voice Chat as...";
@@ -2106,6 +2146,15 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_group_call_recording_started" = "Voice chat recording started.";
"lng_group_call_recording_stopped" = "Voice chat recording stopped.";
"lng_group_call_recording_saved" = "Audio saved to Saved Messages.";
"lng_group_call_pinned_camera_me" = "Your video is pinned.";
"lng_group_call_pinned_screen_me" = "Your screencast is pinned.";
"lng_group_call_pinned_camera" = "{user}'s video is pinned.";
"lng_group_call_pinned_screen" = "{user}'s screencast is pinned.";
"lng_group_call_unpinned_camera_me" = "Your video is unpinned.";
"lng_group_call_unpinned_screen_me" = "Your screencast is unpinned.";
"lng_group_call_unpinned_camera" = "{user}'s video is unpinned.";
"lng_group_call_unpinned_screen" = "{user}'s screencast is unpinned.";
"lng_group_call_sure_screencast" = "{user} is screensharing. This action will make your screencast pinned for all participants.";
"lng_group_call_recording_start_sure" = "Do you want to start recording this chat and save the result into an audio file?\n\nOther members will see the chat is being recorded.";
"lng_group_call_recording_stop_sure" = "Do you want to stop recording this chat?";
"lng_group_call_recording_start_field" = "Recording Title";
@@ -2772,6 +2821,12 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
"lng_mac_menu_show" = "Show Telegram";
"lng_mac_menu_emoji_and_symbols" = "Emoji & Symbols";
"lng_mac_menu_player_pause" = "Pause";
"lng_mac_menu_player_resume" = "Resume";
"lng_mac_menu_player_next" = "Next";
"lng_mac_menu_player_previous" = "Previous";
"lng_mac_menu_player_stop" = "Stop";
"lng_mac_touchbar_favorite_stickers" = "Favorite stickers";
// Keys finished

View File

@@ -68,7 +68,7 @@ inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string pro
inputMediaPhotoExternal#e5bbfe1a flags:# url:string ttl_seconds:flags.0?int = InputMedia;
inputMediaDocumentExternal#fb52dc99 flags:# url:string ttl_seconds:flags.0?int = InputMedia;
inputMediaGame#d33f43f3 id:InputGame = InputMedia;
inputMediaInvoice#f4e096c3 flags:# multiple_allowed:flags.1?true can_forward:flags.2?true title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string = InputMedia;
inputMediaInvoice#d9799874 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:flags.1?string = InputMedia;
inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = 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;
@@ -223,7 +223,7 @@ peerNotifySettings#af509d20 flags:# show_previews:flags.0?Bool silent:flags.1?Bo
peerSettings#733f2961 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true geo_distance:flags.6?int = PeerSettings;
wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper;
wallPaperNoFile#8af40b25 flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;
wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper;
inputReportReasonSpam#58dbcab8 = ReportReason;
inputReportReasonViolence#1e22c78d = ReportReason;
@@ -356,7 +356,7 @@ updateDeleteScheduledMessages#90866cee peer:Peer messages:Vector<int> = Update;
updateTheme#8216fba3 theme:Theme = Update;
updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update;
updateLoginToken#564fe691 = Update;
updateMessagePollVote#42f88f2c poll_id:long user_id:int options:Vector<bytes> = Update;
updateMessagePollVote#37f69f0b poll_id:long user_id:int options:Vector<bytes> qts:int = Update;
updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update;
updateDialogFilterOrder#a5d72105 order:Vector<int> = Update;
updateDialogFilters#3504914f = Update;
@@ -375,6 +375,7 @@ updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update;
updateChatParticipant#f3b3781f flags:# chat_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateChannelParticipant#7fecb1ec flags:# channel_id:int date:int actor_id:int user_id:int prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update;
updateBotStopped#7f9488a user_id:int date:int stopped:Bool qts:int = Update;
updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update;
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
@@ -405,7 +406,7 @@ config#330b4067 flags:# phonecalls_enabled:flags.1?true default_p2p_contacts:fla
nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc;
help.appUpdate#1da7158f flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string = help.AppUpdate;
help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector<MessageEntity> document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate;
help.noAppUpdate#c45a6536 = help.AppUpdate;
help.inviteText#18cb9f78 message:string = help.InviteText;
@@ -649,7 +650,7 @@ inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:f
inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaInvoice#d5348d85 flags:# multiple_allowed:flags.1?true can_forward:flags.3?true title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON start_param:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage;
inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult;
inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult;
@@ -1069,14 +1070,14 @@ chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags
inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper;
inputWallPaperSlug#72091c80 slug:string = InputWallPaper;
inputWallPaperNoFile#8427bbac = InputWallPaper;
inputWallPaperNoFile#967a462e id:long = InputWallPaper;
account.wallPapersNotModified#1c199183 = account.WallPapers;
account.wallPapers#702b65a9 hash:int wallpapers:Vector<WallPaper> = account.WallPapers;
codeSettings#debebe83 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true = CodeSettings;
wallPaperSettings#5086cf8 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
wallPaperSettings#1dc1bca4 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int = WallPaperSettings;
autoDownloadSettings#e04232f3 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true photo_size_max:int video_size_max:int file_size_max:int video_upload_maxbitrate:int = AutoDownloadSettings;
@@ -1204,11 +1205,11 @@ peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked;
stats.messageStats#8999f295 views_graph:StatsGraph = stats.MessageStats;
groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall;
groupCall#c95c6654 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true id:long access_hash:long participants_count:int params:flags.0?DataJSON title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int version:int = GroupCall;
groupCall#653dbaad flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int version:int = GroupCall;
inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall;
groupCallParticipant#b96b25ee flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long params:flags.6?DataJSON = GroupCallParticipant;
groupCallParticipant#eba636fe flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo = GroupCallParticipant;
phone.groupCall#9e727aad call:GroupCall participants:Vector<GroupCallParticipant> participants_next_offset:string chats:Vector<Chat> users:Vector<User> = phone.GroupCall;
@@ -1245,6 +1246,10 @@ phone.joinAsPeers#afe5623f peers:Vector<Peer> chats:Vector<Chat> users:Vector<Us
phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite;
groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector<int> = GroupCallParticipantVideoSourceGroup;
groupCallParticipantVideo#78e41663 flags:# paused:flags.0?true endpoint:string source_groups:Vector<GroupCallParticipantVideoSourceGroup> = GroupCallParticipantVideo;
---functions---
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
@@ -1617,22 +1622,24 @@ phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhon
phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool;
phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool;
phone.createGroupCall#48cdc6d8 flags:# peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates;
phone.joinGroupCall#b132ff7b flags:# muted:flags.0?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string params:DataJSON = Updates;
phone.joinGroupCall#b132ff7b flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string params:DataJSON = Updates;
phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates;
phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector<InputUser> = Updates;
phone.discardGroupCall#7a777135 call:InputGroupCall = Updates;
phone.toggleGroupCallSettings#74bbb43d flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool = Updates;
phone.getGroupCall#c7cb017 call:InputGroupCall = phone.GroupCall;
phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector<InputPeer> sources:Vector<int> offset:string limit:int = phone.GroupParticipants;
phone.checkGroupCall#b74a7bea call:InputGroupCall source:int = Bool;
phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector<int> = Vector<int>;
phone.toggleGroupCallRecord#c02a66d7 flags:# start:flags.0?true call:InputGroupCall title:flags.1?string = Updates;
phone.editGroupCallParticipant#d975eb80 flags:# muted:flags.0?true call:InputGroupCall participant:InputPeer volume:flags.1?int raise_hand:flags.2?Bool = Updates;
phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates;
phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates;
phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers;
phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite;
phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates;
phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates;
phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool;
phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates;
phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates;
langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference;
langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector<string> = Vector<LangPackString>;
@@ -1649,4 +1656,4 @@ stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel
stats.getMessagePublicForwards#5630281b channel:InputChannel msg_id:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages;
stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats;
// LAYER 128
// LAYER 129

View File

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

View File

@@ -44,8 +44,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,5,0
PRODUCTVERSION 2,7,5,0
FILEVERSION 2,8,5,0
PRODUCTVERSION 2,8,5,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -62,10 +62,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop"
VALUE "FileVersion", "2.7.5.0"
VALUE "FileVersion", "2.8.5.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.7.5.0"
VALUE "ProductVersion", "2.8.5.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -35,8 +35,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,5,0
PRODUCTVERSION 2,7,5,0
FILEVERSION 2,8,5,0
PRODUCTVERSION 2,8,5,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -53,10 +53,10 @@ BEGIN
BEGIN
VALUE "CompanyName", "Telegram FZ-LLC"
VALUE "FileDescription", "Telegram Desktop Updater"
VALUE "FileVersion", "2.7.5.0"
VALUE "FileVersion", "2.8.5.0"
VALUE "LegalCopyright", "Copyright (C) 2014-2021"
VALUE "ProductName", "Telegram Desktop"
VALUE "ProductVersion", "2.7.5.0"
VALUE "ProductVersion", "2.8.5.0"
END
END
BLOCK "VarFileInfo"

View File

@@ -47,6 +47,18 @@ typedef signed int int32;
namespace{
struct BIODeleter {
void operator()(BIO *value) {
BIO_free(value);
}
};
inline auto makeBIO(const void *buf, int len) {
return std::unique_ptr<BIO, BIODeleter>{
BIO_new_mem_buf(buf, len),
};
}
inline uint32 sha1Shift(uint32 v, uint32 shift) {
return ((v << shift) | (v >> (32 - shift)));
}
@@ -430,7 +442,15 @@ int main(int argc, char *argv[])
uint32 siglen = 0;
cout << "Signing..\n";
RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>((BetaChannel || AlphaVersion) ? PrivateBetaKey : PrivateKey), -1), 0, 0, 0);
RSA *prKey = [] {
const auto bio = makeBIO(
const_cast<char*>(
(BetaChannel || AlphaVersion)
? PrivateBetaKey
: PrivateKey),
-1);
return PEM_read_bio_RSAPrivateKey(bio.get(), 0, 0, 0);
}();
if (!prKey) {
cout << "Could not read RSA private key!\n";
return -1;
@@ -453,7 +473,15 @@ int main(int argc, char *argv[])
}
cout << "Checking signature..\n";
RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>((BetaChannel || AlphaVersion) ? PublicBetaKey : PublicKey), -1), 0, 0, 0);
RSA *pbKey = [] {
const auto bio = makeBIO(
const_cast<char*>(
(BetaChannel || AlphaVersion)
? PublicBetaKey
: PublicKey),
-1);
return PEM_read_bio_RSAPublicKey(bio.get(), 0, 0, 0);
}();
if (!pbKey) {
cout << "Could not read RSA public key!\n";
return -1;
@@ -510,7 +538,12 @@ QString countAlphaVersionSignature(quint64 version) { // duplicated in autoupdat
uint32 siglen = 0;
RSA *prKey = PEM_read_bio_RSAPrivateKey(BIO_new_mem_buf(const_cast<char*>(cAlphaPrivateKey.constData()), -1), 0, 0, 0);
RSA *prKey = [&] {
const auto bio = makeBIO(
const_cast<char*>(cAlphaPrivateKey.constData()),
-1);
return PEM_read_bio_RSAPrivateKey(bio.get(), 0, 0, 0);
}();
if (!prKey) {
cout << "Error: Could not read alpha private key!\n";
return QString();

View File

@@ -7,6 +7,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "updater.h"
#include "base/platform/win/base_windows_safe_library.h"
bool _debug = false;
wstring updaterName, updaterDir, updateTo, exeName, customWorkingDir, customKeyFile;
@@ -329,6 +331,8 @@ void updateRegistry() {
}
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR cmdParamarg, int cmdShow) {
base::Platform::InitDynamicLibraries();
openLog();
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);

View File

@@ -36,10 +36,12 @@ void AttachedStickers::request(
return;
}
if (result.v.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
return;
} else if (result.v.size() > 1) {
Ui::show(Box<StickersBox>(strongController, result));
strongController->show(
Box<StickersBox>(strongController, result));
return;
}
// Single attached sticker pack.
@@ -52,12 +54,15 @@ void AttachedStickers::request(
const auto setId = (setData->vid().v && setData->vaccess_hash().v)
? MTP_inputStickerSetID(setData->vid(), setData->vaccess_hash())
: MTP_inputStickerSetShortName(setData->vshort_name());
Ui::show(
strongController->show(
Box<StickerSetBox>(strongController, setId),
Ui::LayerOption::KeepOther);
}).fail([=](const MTP::Error &error) {
_requestId = 0;
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
if (const auto strongController = weak.get()) {
strongController->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
}
}).send();
}

View File

@@ -34,7 +34,11 @@ void CheckChatInvite(
session->api().checkChatInvite(hash, [=](const MTPChatInvite &result) {
Core::App().hideMediaView();
result.match([=](const MTPDchatInvite &data) {
const auto box = Ui::show(Box<ConfirmInviteBox>(
const auto strongController = weak.get();
if (!strongController) {
return;
}
const auto box = strongController->show(Box<ConfirmInviteBox>(
session,
data,
invitePeekChannel,
@@ -80,7 +84,10 @@ void CheckChatInvite(
return;
}
Core::App().hideMediaView();
Ui::show(Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
if (const auto strong = weak.get()) {
strong->show(
Box<InformBox>(tr::lng_group_invite_bad_link(tr::now)));
}
});
}

View File

@@ -862,26 +862,35 @@ int32 Updates::pts() const {
return _ptsWaiter.current();
}
void Updates::updateOnline() {
updateOnline(false);
void Updates::updateOnline(crl::time lastNonIdleTime) {
updateOnline(lastNonIdleTime, false);
}
bool Updates::isIdle() const {
return _isIdle;
return _isIdle.current();
}
void Updates::updateOnline(bool gotOtherOffline) {
crl::on_main(&session(), [] { Core::App().checkAutoLock(); });
rpl::producer<bool> Updates::isIdleValue() const {
return _isIdle.value();
}
void Updates::updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline) {
if (!lastNonIdleTime) {
lastNonIdleTime = Core::App().lastNonIdleTime();
}
crl::on_main(&session(), [=] {
Core::App().checkAutoLock(lastNonIdleTime);
});
const auto &config = _session->serverConfig();
bool isOnline = Core::App().hasActiveWindow(&session());
int updateIn = config.onlineUpdatePeriod;
Assert(updateIn >= 0);
if (isOnline) {
const auto idle = crl::now() - Core::App().lastNonIdleTime();
const auto idle = crl::now() - lastNonIdleTime;
if (idle >= config.offlineIdleTimeout) {
isOnline = false;
if (!_isIdle) {
if (!isIdle()) {
_isIdle = true;
_idleFinishTimer.callOnce(900);
}
@@ -929,13 +938,15 @@ void Updates::updateOnline(bool gotOtherOffline) {
_onlineTimer.callOnce(updateIn);
}
void Updates::checkIdleFinish() {
if (crl::now() - Core::App().lastNonIdleTime()
void Updates::checkIdleFinish(crl::time lastNonIdleTime) {
if (!lastNonIdleTime) {
lastNonIdleTime = Core::App().lastNonIdleTime();
}
if (crl::now() - lastNonIdleTime
< _session->serverConfig().offlineIdleTimeout) {
updateOnline(lastNonIdleTime);
_idleFinishTimer.cancel();
_isIdle = false;
updateOnline();
App::wnd()->checkHistoryActivation();
} else {
_idleFinishTimer.callOnce(900);
}
@@ -954,9 +965,10 @@ bool Updates::isQuitPrevent() {
return false;
}
LOG(("Api::Updates prevents quit, sending offline status..."));
updateOnline();
updateOnline(crl::now());
return true;
}
void Updates::handleSendActionUpdate(
PeerId peerId,
MsgId rootId,
@@ -1747,7 +1759,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
if (UserId(d.vuser_id()) == session().userId()) {
if (d.vstatus().type() == mtpc_userStatusOffline
|| d.vstatus().type() == mtpc_userStatusEmpty) {
updateOnline(true);
updateOnline(Core::App().lastNonIdleTime(), true);
if (d.vstatus().type() == mtpc_userStatusOffline) {
cSetOtherOnline(
d.vstatus().c_userStatusOffline().vwas_online().v);
@@ -1878,6 +1890,7 @@ void Updates::feedUpdate(const MTPUpdate &update) {
case mtpc_updatePhoneCall:
case mtpc_updatePhoneCallSignalingData:
case mtpc_updateGroupCallParticipants:
case mtpc_updateGroupCallConnection:
case mtpc_updateGroupCall: {
Core::App().calls().handleUpdate(&session(), update);
} break;

View File

@@ -38,9 +38,10 @@ public:
[[nodiscard]] int32 pts() const;
void updateOnline();
void updateOnline(crl::time lastNonIdleTime = 0);
[[nodiscard]] bool isIdle() const;
void checkIdleFinish();
[[nodiscard]] rpl::producer<bool> isIdleValue() const;
void checkIdleFinish(crl::time lastNonIdleTime = 0);
bool lastWasOnline() const;
crl::time lastSetOnline() const;
bool isQuitPrevent();
@@ -86,7 +87,7 @@ private:
MsgRange range,
const MTPupdates_ChannelDifference &result);
void updateOnline(bool gotOtherOffline);
void updateOnline(crl::time lastNonIdleTime, bool gotOtherOffline);
void sendPing();
void getDifferenceByPts();
void getDifferenceAfterFail();
@@ -185,7 +186,7 @@ private:
base::Timer _idleFinishTimer;
crl::time _lastSetOnline = 0;
bool _lastWasOnline = false;
bool _isIdle = false;
rpl::variable<bool> _isIdle = false;
rpl::lifetime _lifetime;

View File

@@ -212,6 +212,11 @@ ApiWrap::ApiWrap(not_null<Main::Session*> session)
}, _session->lifetime());
setupSupportMode();
Core::App().settings().proxy().connectionTypeValue(
) | rpl::start_with_next([=] {
refreshTopPromotion();
}, _session->lifetime());
});
}
@@ -261,10 +266,10 @@ void ApiWrap::refreshTopPromotion() {
return;
}
const auto key = [&]() -> std::pair<QString, uint32> {
if (Global::ProxySettings() != MTP::ProxyData::Settings::Enabled) {
if (!Core::App().settings().proxy().isEnabled()) {
return {};
}
const auto &proxy = Global::SelectedProxy();
const auto &proxy = Core::App().settings().proxy().selected();
if (proxy.type != MTP::ProxyData::Type::Mtproto) {
return {};
}

View File

@@ -12,7 +12,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "core/application.h"
#include "mainwindow.h"
#include "ui/widgets/checkbox.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
@@ -45,8 +44,7 @@ void AutoLockBox::prepare() {
void AutoLockBox::durationChanged(int seconds) {
Core::App().settings().setAutoLock(seconds);
Core::App().saveSettingsDelayed();
Global::RefLocalPasscodeChanged().notify();
Core::App().checkAutoLock();
Core::App().checkAutoLock(crl::now());
closeBox();
}

View File

@@ -151,7 +151,7 @@ void BackgroundBox::prepare() {
_inner->chooseEvents(
) | rpl::start_with_next([=](const Data::WallPaper &paper) {
Ui::show(
_controller->show(
Box<BackgroundPreviewBox>(_controller, paper),
Ui::LayerOption::KeepOther);
}, _inner->lifetime());
@@ -176,7 +176,7 @@ void BackgroundBox::removePaper(const Data::WallPaper &paper) {
paper.mtpSettings()
)).send();
};
Ui::show(
_controller->show(
Box<ConfirmBox>(
tr::lng_background_sure_delete(tr::now),
tr::lng_selected_delete(tr::now),

View File

@@ -23,6 +23,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_user.h"
#include "data/data_document.h"
#include "data/data_document_media.h"
#include "data/data_document_resolver.h"
#include "data/data_file_origin.h"
#include "base/unixtime.h"
#include "boxes/confirm_box.h"
@@ -769,23 +770,25 @@ bool BackgroundPreviewBox::Start(
const QString &slug,
const QMap<QString, QString> &params) {
if (const auto paper = Data::WallPaper::FromColorSlug(slug)) {
Ui::show(Box<BackgroundPreviewBox>(
controller->show(Box<BackgroundPreviewBox>(
controller,
paper->withUrlParams(params)));
return true;
}
if (!IsValidWallPaperSlug(slug)) {
Ui::show(Box<InformBox>(tr::lng_background_bad_link(tr::now)));
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
return false;
}
controller->session().api().requestWallPaper(slug, crl::guard(controller, [=](
const Data::WallPaper &result) {
Ui::show(Box<BackgroundPreviewBox>(
controller->show(Box<BackgroundPreviewBox>(
controller,
result.withUrlParams(params)));
}), [](const MTP::Error &error) {
Ui::show(Box<InformBox>(tr::lng_background_bad_link(tr::now)));
});
}), crl::guard(controller, [=](const MTP::Error &error) {
controller->show(
Box<InformBox>(tr::lng_background_bad_link(tr::now)));
}));
return true;
}

View File

@@ -433,7 +433,7 @@ editMediaButtonFileSkipRight: 1px;
editMediaButtonFileSkipTop: 7px;
editMediaButtonIconFile: icon {{ "settings_edit", menuIconFg }};
editMediaButtonIconPhoto: icon {{ "settings_edit", msgServiceFg }};
editMediaButtonIconPhoto: icon {{ "settings_edit", roundedFg }};
editMediaButton: IconButton {
width: editMediaButtonSize;
height: editMediaButtonSize;
@@ -464,8 +464,8 @@ sendBoxAlbumGroupButtonFile: IconButton(editMediaButton) {
sendBoxAlbumGroupEditButtonIconFile: editMediaButtonIconFile;
sendBoxAlbumGroupDeleteButtonIconFile: icon {{ "history_file_cancel", menuIconFg, point(6px, 6px) }};
sendBoxAlbumGroupButtonMediaEdit: icon {{ "settings_edit", msgServiceFg, point(3px, -2px) }};
sendBoxAlbumGroupButtonMediaDelete: icon {{ "history_file_cancel", msgServiceFg, point(2px, 5px) }};
sendBoxAlbumGroupButtonMediaEdit: icon {{ "settings_edit", roundedFg, point(3px, -2px) }};
sendBoxAlbumGroupButtonMediaDelete: icon {{ "history_file_cancel", roundedFg, point(2px, 5px) }};
sendBoxAlbumGroupButtonMedia: IconButton {
width: sendBoxAlbumGroupHeight;
height: sendBoxAlbumGroupHeight;
@@ -729,10 +729,6 @@ termsAgePadding: margins(22px, 16px, 16px, 0px);
themesSmallSkip: 10px;
themesBackgroundSize: 120px;
themesScroll: ScrollArea(defaultScrollArea) {
bottomsh: 0px;
topsh: 0px;
}
themesMenuToggle: IconButton(defaultIconButton) {
width: 44px;
height: 44px;

View File

@@ -13,6 +13,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/qthelp_url.h"
#include "base/call_delayed.h"
#include "core/application.h"
#include "core/core_settings.h"
#include "main/main_account.h"
#include "mtproto/facade.h"
#include "ui/widgets/checkbox.h"
@@ -26,7 +27,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/effects/animations.h"
#include "ui/effects/radial_animation.h"
#include "ui/text/text_options.h"
#include "facades.h"
#include "ui/basic_click_handlers.h"
#include "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_chat_helpers.h"
@@ -185,7 +186,10 @@ class ProxiesBox : public Ui::BoxContent {
public:
using View = ProxiesBoxController::ItemView;
ProxiesBox(QWidget*, not_null<ProxiesBoxController*> controller);
ProxiesBox(
QWidget*,
not_null<ProxiesBoxController*> controller,
Core::SettingsProxy &settings);
protected:
void prepare() override;
@@ -200,6 +204,7 @@ private:
void refreshProxyForCalls();
not_null<ProxiesBoxController*> _controller;
Core::SettingsProxy &_settings;
QPointer<Ui::Checkbox> _tryIPv6;
std::shared_ptr<Ui::RadioenumGroup<ProxyData::Settings>> _proxySettings;
QPointer<Ui::SlideWrap<Ui::Checkbox>> _proxyForCalls;
@@ -565,8 +570,10 @@ void ProxyRow::showMenu() {
ProxiesBox::ProxiesBox(
QWidget*,
not_null<ProxiesBoxController*> controller)
not_null<ProxiesBoxController*> controller,
Core::SettingsProxy &settings)
: _controller(controller)
, _settings(settings)
, _initialWrap(this) {
_controller->views(
) | rpl::start_with_next([=](View &&view) {
@@ -590,11 +597,11 @@ void ProxiesBox::setupContent() {
object_ptr<Ui::Checkbox>(
inner,
tr::lng_connection_try_ipv6(tr::now),
Global::TryIPv6()),
_settings.tryIPv6()),
st::proxyTryIPv6Padding);
_proxySettings
= std::make_shared<Ui::RadioenumGroup<ProxyData::Settings>>(
Global::ProxySettings());
_settings.settings());
inner->add(
object_ptr<Ui::Radioenum<ProxyData::Settings>>(
inner,
@@ -622,7 +629,7 @@ void ProxiesBox::setupContent() {
object_ptr<Ui::Checkbox>(
inner,
tr::lng_proxy_use_for_calls(tr::now),
Global::UseProxyForCalls()),
_settings.useProxyForCalls()),
style::margins(
0,
st::proxyUsePadding.top(),
@@ -651,7 +658,7 @@ void ProxiesBox::setupContent() {
_proxySettings->setChangedCallback([=](ProxyData::Settings value) {
if (!_controller->setProxySettings(value)) {
_proxySettings->setValue(Global::ProxySettings());
_proxySettings->setValue(_settings.settings());
addNewProxy();
}
refreshProxyForCalls();
@@ -1050,20 +1057,22 @@ void ProxyBox::addLabel(
ProxiesBoxController::ProxiesBoxController(not_null<Main::Account*> account)
: _account(account)
, _settings(Core::App().settings().proxy())
, _saveTimer([] { Local::writeSettings(); }) {
_list = ranges::views::all(
Global::ProxiesList()
_settings.list()
) | ranges::views::transform([&](const ProxyData &proxy) {
return Item{ ++_idCounter, proxy };
}) | ranges::to_vector;
subscribe(Global::RefConnectionTypeChanged(), [=] {
_proxySettingsChanges.fire_copy(Global::ProxySettings());
const auto i = findByProxy(Global::SelectedProxy());
_settings.connectionTypeChanges(
) | rpl::start_with_next([=] {
_proxySettingsChanges.fire_copy(_settings.settings());
const auto i = findByProxy(_settings.selected());
if (i != end(_list)) {
updateView(*i);
}
});
}, _lifetime);
for (auto &item : _list) {
refreshChecker(item);
@@ -1086,17 +1095,32 @@ void ProxiesBoxController::ShowApplyConfirmation(
proxy.password = fields.value(qsl("secret"));
}
if (proxy) {
const auto displayed = "https://" + server + "/";
const auto parsed = QUrl::fromUserInput(displayed);
const auto displayUrl = !UrlClickHandler::IsSuspicious(displayed)
? displayed
: parsed.isValid()
? QString::fromUtf8(parsed.toEncoded())
: UrlClickHandler::ShowEncoded(displayed);
const auto displayServer = QString(
displayUrl
).replace(
QRegularExpression(
"^https://",
QRegularExpression::CaseInsensitiveOption),
QString()
).replace(QRegularExpression("/$"), QString());
const auto text = tr::lng_sure_enable_socks(
tr::now,
lt_server,
server,
displayServer,
lt_port,
QString::number(port))
+ (proxy.type == Type::Mtproto
? "\n\n" + tr::lng_proxy_sponsor_warning(tr::now)
: QString());
auto callback = [=](Fn<void()> &&close) {
auto &proxies = Global::RefProxiesList();
auto &proxies = Core::App().settings().proxy().list();
if (!ranges::contains(proxies, proxy)) {
proxies.push_back(proxy);
}
@@ -1123,7 +1147,7 @@ void ProxiesBoxController::ShowApplyConfirmation(
auto ProxiesBoxController::proxySettingsValue() const
-> rpl::producer<ProxyData::Settings> {
return _proxySettingsChanges.events_starting_with_copy(
Global::ProxySettings()
_settings.settings()
) | rpl::distinct_until_changed();
}
@@ -1134,6 +1158,7 @@ void ProxiesBoxController::refreshChecker(Item &item) {
: Variants::Tcp;
const auto mtproto = &_account->mtp();
const auto dcId = mtproto->mainDcId();
const auto forFiles = false;
item.state = ItemState::Checking;
const auto setup = [&](Checker &checker, const bytes::vector &secret) {
@@ -1152,7 +1177,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
item.data.host,
item.data.port,
secret,
dcId);
dcId,
forFiles);
item.checkerv6 = nullptr;
} else {
const auto options = mtproto->dcOptions().lookup(
@@ -1164,7 +1190,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
Variants::Address address) {
const auto &list = options.data[address][type];
if (list.empty()
|| (address == Variants::IPv6 && !Global::TryIPv6())) {
|| ((address == Variants::IPv6)
&& !Core::App().settings().proxy().tryIPv6())) {
checker = nullptr;
return;
}
@@ -1174,7 +1201,8 @@ void ProxiesBoxController::refreshChecker(Item &item) {
QString::fromStdString(endpoint.ip),
endpoint.port,
endpoint.secret,
dcId);
dcId,
forFiles);
};
connect(item.checker, Variants::IPv4);
connect(item.checkerv6, Variants::IPv6);
@@ -1225,7 +1253,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::CreateOwningBox(
}
object_ptr<Ui::BoxContent> ProxiesBoxController::create() {
auto result = Box<ProxiesBox>(this);
auto result = Box<ProxiesBox>(this, _settings);
for (const auto &item : _list) {
updateView(item);
}
@@ -1263,14 +1291,13 @@ void ProxiesBoxController::shareItem(int id) {
void ProxiesBoxController::applyItem(int id) {
auto item = findById(id);
if ((Global::ProxySettings() == ProxyData::Settings::Enabled)
&& Global::SelectedProxy() == item->data) {
if (_settings.isEnabled() && (_settings.selected() == item->data)) {
return;
} else if (item->deleted) {
return;
}
auto j = findByProxy(Global::SelectedProxy());
auto j = findByProxy(_settings.selected());
Core::App().setCurrentProxy(
item->data,
@@ -1288,12 +1315,13 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
item->deleted = deleted;
if (deleted) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.erase(ranges::remove(proxies, item->data), end(proxies));
if (item->data == Global::SelectedProxy()) {
_lastSelectedProxy = base::take(Global::RefSelectedProxy());
if (Global::ProxySettings() == ProxyData::Settings::Enabled) {
if (item->data == _settings.selected()) {
_lastSelectedProxy = _settings.selected();
_settings.setSelected(MTP::ProxyData());
if (_settings.isEnabled()) {
_lastSelectedProxyUsed = true;
Core::App().setCurrentProxy(
ProxyData(),
@@ -1304,7 +1332,7 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
}
}
} else {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
if (ranges::find(proxies, item->data) == end(proxies)) {
auto insertBefore = item + 1;
while (insertBefore != end(_list) && insertBefore->deleted) {
@@ -1316,15 +1344,15 @@ void ProxiesBoxController::setDeleted(int id, bool deleted) {
proxies.insert(insertBeforeIt, item->data);
}
if (!Global::SelectedProxy() && _lastSelectedProxy == item->data) {
Assert(Global::ProxySettings() != ProxyData::Settings::Enabled);
if (!_settings.selected() && _lastSelectedProxy == item->data) {
Assert(!_settings.isEnabled());
if (base::take(_lastSelectedProxyUsed)) {
Core::App().setCurrentProxy(
base::take(_lastSelectedProxy),
ProxyData::Settings::Enabled);
} else {
Global::SetSelectedProxy(base::take(_lastSelectedProxy));
_settings.setSelected(base::take(_lastSelectedProxy));
}
}
}
@@ -1352,7 +1380,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::editItemBox(int id) {
void ProxiesBoxController::replaceItemWith(
std::vector<Item>::iterator which,
std::vector<Item>::iterator with) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.erase(ranges::remove(proxies, which->data), end(proxies));
_views.fire({ which->id });
@@ -1372,7 +1400,7 @@ void ProxiesBoxController::replaceItemValue(
restoreItem(which->id);
}
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
const auto i = ranges::find(proxies, which->data);
Assert(i != end(proxies));
*i = proxy;
@@ -1403,7 +1431,7 @@ object_ptr<Ui::BoxContent> ProxiesBoxController::addNewItemBox() {
}
void ProxiesBoxController::addNewItem(const ProxyData &proxy) {
auto &proxies = Global::RefProxiesList();
auto &proxies = _settings.list();
proxies.push_back(proxy);
_list.push_back({ ++_idCounter, proxy });
@@ -1412,43 +1440,42 @@ void ProxiesBoxController::addNewItem(const ProxyData &proxy) {
}
bool ProxiesBoxController::setProxySettings(ProxyData::Settings value) {
if (Global::ProxySettings() == value) {
if (_settings.settings() == value) {
return true;
} else if (value == ProxyData::Settings::Enabled) {
if (Global::ProxiesList().empty()) {
if (_settings.list().empty()) {
return false;
} else if (!Global::SelectedProxy()) {
Global::SetSelectedProxy(Global::ProxiesList().back());
auto j = findByProxy(Global::SelectedProxy());
} else if (!_settings.selected()) {
_settings.setSelected(_settings.list().back());
auto j = findByProxy(_settings.selected());
if (j != end(_list)) {
updateView(*j);
}
}
}
Core::App().setCurrentProxy(Global::SelectedProxy(), value);
Core::App().setCurrentProxy(_settings.selected(), value);
saveDelayed();
return true;
}
void ProxiesBoxController::setProxyForCalls(bool enabled) {
if (Global::UseProxyForCalls() == enabled) {
if (_settings.useProxyForCalls() == enabled) {
return;
}
Global::SetUseProxyForCalls(enabled);
if ((Global::ProxySettings() == ProxyData::Settings::Enabled)
&& Global::SelectedProxy().supportsCalls()) {
Global::RefConnectionTypeChanged().notify();
_settings.setUseProxyForCalls(enabled);
if (_settings.isEnabled() && _settings.selected().supportsCalls()) {
_settings.connectionTypeChangesNotify();
}
saveDelayed();
}
void ProxiesBoxController::setTryIPv6(bool enabled) {
if (Global::TryIPv6() == enabled) {
if (Core::App().settings().proxy().tryIPv6() == enabled) {
return;
}
Global::SetTryIPv6(enabled);
Core::App().settings().proxy().setTryIPv6(enabled);
_account->mtp().restart();
Global::RefConnectionTypeChanged().notify();
_settings.connectionTypeChangesNotify();
saveDelayed();
}
@@ -1461,7 +1488,7 @@ auto ProxiesBoxController::views() const -> rpl::producer<ItemView> {
}
void ProxiesBoxController::updateView(const Item &item) {
const auto selected = (Global::SelectedProxy() == item.data);
const auto selected = (_settings.selected() == item.data);
const auto deleted = item.deleted;
const auto type = [&] {
switch (item.data.type) {
@@ -1475,8 +1502,7 @@ void ProxiesBoxController::updateView(const Item &item) {
Unexpected("Proxy type in ProxiesBoxController::updateView.");
}();
const auto state = [&] {
if (!selected
|| (Global::ProxySettings() != ProxyData::Settings::Enabled)) {
if (!selected || !_settings.isEnabled()) {
return item.state;
} else if (_account->mtp().dcstate() == MTP::ConnectedState) {
return ItemState::Online;

View File

@@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/timer.h"
#include "base/object_ptr.h"
#include "core/core_settings.h"
#include "mtproto/connection_abstract.h"
#include "mtproto/mtproto_proxy_data.h"
@@ -28,7 +29,7 @@ namespace Main {
class Account;
} // namespace Main
class ProxiesBoxController : public base::Subscriber {
class ProxiesBoxController {
public:
using ProxyData = MTP::ProxyData;
using Type = ProxyData::Type;
@@ -110,6 +111,7 @@ private:
void addNewItem(const ProxyData &proxy);
const not_null<Main::Account*> _account;
Core::SettingsProxy &_settings;
int _idCounter = 0;
std::vector<Item> _list;
rpl::event_stream<ItemView> _views;
@@ -119,4 +121,6 @@ private:
ProxyData _lastSelectedProxy;
bool _lastSelectedProxyUsed = false;
rpl::lifetime _lifetime;
};

View File

@@ -1085,7 +1085,7 @@ object_ptr<Ui::RpWidget> CreatePollBox::setupContent() {
send({ .silent = true });
};
const auto sendScheduled = [=] {
Ui::show(
_controller->show(
HistoryView::PrepareScheduleBox(
this,
SendMenu::Type::Scheduled,

View File

@@ -47,6 +47,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/input_fields.h"
#include "ui/widgets/checkbox.h"
#include "ui/widgets/checkbox.h"
#include "ui/text/format_song_document_name.h"
#include "ui/text/format_values.h"
#include "ui/text/text_options.h"
#include "ui/chat/attach/attach_prepare.h"
@@ -220,7 +221,7 @@ EditCaptionBox::EditCaptionBox(
const auto document = _documentMedia->owner();
const auto nameString = document->isVoiceMessage()
? tr::lng_media_audio(tr::now)
: document->composeNameString();
: Ui::Text::FormatSongNameFor(document).string();
setName(nameString, document->size);
_isImage = document->isImage();
_isAudio = document->isVoiceMessage()
@@ -486,13 +487,13 @@ void EditCaptionBox::handleStreamingError(Error &&error) {
}
void EditCaptionBox::streamingReady(Information &&info) {
const auto calculateGifDimensions = [&]() {
const auto calculateGifDimensions = [&] {
const auto scaled = QSize(
info.video.size.width(),
info.video.size.height()
).scaled(
st::sendMediaPreviewSize * cIntRetinaFactor(),
st::confirmMaxHeight * cIntRetinaFactor(),
st::sendMediaPreviewSize,
st::confirmMaxHeight,
Qt::KeepAspectRatio);
_thumbw = _gifw = scaled.width();
_thumbh = _gifh = scaled.height();
@@ -549,10 +550,10 @@ void EditCaptionBox::updateEditPreview() {
if (shouldAsDoc) {
auto nameString = filename;
if (const auto song = std::get_if<Info::Song>(fileMedia)) {
nameString = Ui::ComposeNameString(
nameString = Ui::Text::FormatSongName(
filename,
song->title,
song->performer);
song->performer).string();
_isAudio = true;
if (auto cover = song->cover; !cover.isNull()) {
@@ -620,7 +621,7 @@ void EditCaptionBox::updateEditMediaButton() {
const auto icon = _doc
? &st::editMediaButtonIconFile
: &st::editMediaButtonIconPhoto;
const auto color = _doc ? &st::windowBgRipple : &st::callFingerprintBg;
const auto color = _doc ? &st::windowBgRipple : &st::roundedBg;
_editMedia->setIconOverride(icon);
_editMedia->setRippleColorOverride(color);
_editMedia->setForceRippled(!_doc, anim::type::instant);

View File

@@ -27,8 +27,8 @@ public:
return _y;
}
base::Observable<void> &changed() {
return _changed;
rpl::producer<> changed() const {
return _changed.events();
}
void setHSB(HSB hsb);
void setRGB(int red, int green, int blue);
@@ -61,7 +61,7 @@ private:
float64 _y = 0.;
bool _choosing = false;
base::Observable<void> _changed;
rpl::event_stream<> _changed;
};
@@ -234,7 +234,7 @@ void EditColorBox::Picker::updateCurrentPoint(QPoint localPosition) {
_x = x;
_y = y;
update();
_changed.notify();
_changed.fire({});
}
}
@@ -284,8 +284,8 @@ public:
};
Slider(QWidget *parent, Direction direction, Type type, QColor color);
base::Observable<void> &changed() {
return _changed;
rpl::producer<> changed() const {
return _changed.events();
}
float64 value() const {
return _value;
@@ -335,7 +335,7 @@ private:
QBrush _transparent;
bool _choosing = false;
base::Observable<void> _changed;
rpl::event_stream<> _changed;
};
@@ -349,7 +349,9 @@ EditColorBox::Slider::Slider(
, _type(type)
, _color(color.red(), color.green(), color.blue())
, _value(valueFromColor(color))
, _transparent((_type == Type::Opacity) ? style::transparentPlaceholderBrush() : QBrush()) {
, _transparent((_type == Type::Opacity)
? style::TransparentPlaceholder()
: QBrush()) {
prepareMinSize();
}
@@ -538,7 +540,7 @@ void EditColorBox::Slider::updateCurrentPoint(QPoint localPosition) {
if (_value != value) {
_value = value;
update();
_changed.notify();
_changed.fire({});
}
}
@@ -758,7 +760,7 @@ EditColorBox::EditColorBox(
, _greenField(this, st::colorValueInput, "G", 255)
, _blueField(this, st::colorValueInput, "B", 255)
, _result(this, st::colorResultInput)
, _transparent(style::transparentPlaceholderBrush())
, _transparent(style::TransparentPlaceholder())
, _current(current)
, _new(current) {
if (_mode == Mode::RGBA) {
@@ -824,16 +826,14 @@ void EditColorBox::prepare() {
auto height = st::colorEditSkip + st::colorPickerSize + st::colorEditSkip + st::colorSliderWidth + st::colorEditSkip;
setDimensions(st::colorEditWidth, height);
subscribe(_picker->changed(), [=] { updateFromControls(); });
if (_hueSlider) {
subscribe(_hueSlider->changed(), [=] { updateFromControls(); });
}
if (_opacitySlider) {
subscribe(_opacitySlider->changed(), [=] { updateFromControls(); });
}
if (_lightnessSlider) {
subscribe(_lightnessSlider->changed(), [=] { updateFromControls(); });
}
rpl::merge(
_picker->changed(),
(_hueSlider ? _hueSlider->changed() : rpl::never<>()),
(_opacitySlider ? _opacitySlider->changed() : rpl::never<>()),
(_lightnessSlider ? _lightnessSlider->changed() : rpl::never<>())
) | rpl::start_with_next([=] {
updateFromControls();
}, lifetime());
boxClosing() | rpl::start_with_next([=] {
if (_cancelCallback) {

View File

@@ -9,7 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "boxes/abstract_box.h"
class EditColorBox : public Ui::BoxContent, private base::Subscriber {
class EditColorBox : public Ui::BoxContent {
public:
enum class Mode {
RGBA,

View File

@@ -165,7 +165,7 @@ void EditPrivacyBox::editExceptions(
}));
box->addButton(tr::lng_cancel(), [=] { box->closeBox(); });
};
Ui::show(
_window->show(
Box<PeerListBox>(std::move(controller), std::move(initBox)),
Ui::LayerOption::KeepOther);
}

View File

@@ -1166,15 +1166,19 @@ base::binary_guard LanguageBox::Show() {
if (manager.languageList().empty()) {
auto guard = std::make_shared<base::binary_guard>(
result.make_guard());
auto alive = std::make_shared<std::unique_ptr<base::Subscription>>(
std::make_unique<base::Subscription>());
**alive = manager.languageListChanged().add_subscription([=] {
auto lifetime = std::make_shared<rpl::lifetime>();
manager.languageListChanged(
) | rpl::take(
1
) | rpl::start_with_next([=]() mutable {
const auto show = guard->alive();
*alive = nullptr;
if (lifetime) {
base::take(lifetime)->destroy();
}
if (show) {
Ui::show(Box<LanguageBox>());
}
});
}, *lifetime);
} else {
Ui::show(Box<LanguageBox>());
}

View File

@@ -27,7 +27,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "passport/passport_encryption.h"
#include "passport/passport_panel_edit_contact.h"
#include "settings/settings_privacy_security.h"
#include "facades.h"
#include "styles/style_layers.h"
#include "styles/style_passport.h"
#include "styles/style_boxes.h"
@@ -119,7 +118,12 @@ PasscodeBox::PasscodeBox(
, _turningOff(turningOff)
, _about(st::boxWidth - st::boxPadding.left() * 1.5)
, _oldPasscode(this, st::defaultInputField, tr::lng_passcode_enter_old())
, _newPasscode(this, st::defaultInputField, Global::LocalPasscode() ? tr::lng_passcode_enter_new() : tr::lng_passcode_enter_first())
, _newPasscode(
this,
st::defaultInputField,
session->domain().local().hasLocalPasscode()
? tr::lng_passcode_enter_new()
: tr::lng_passcode_enter_first())
, _reenterPasscode(this, st::defaultInputField, tr::lng_passcode_confirm_new())
, _passwordHint(this, st::defaultInputField, tr::lng_cloud_password_hint())
, _recoverEmail(this, st::defaultInputField, tr::lng_cloud_password_email())
@@ -164,7 +168,9 @@ rpl::producer<> PasscodeBox::clearUnconfirmedPassword() const {
}
bool PasscodeBox::currentlyHave() const {
return _cloudPwd ? (!!_cloudFields.curRequest) : Global::LocalPasscode();
return _cloudPwd
? (!!_cloudFields.curRequest)
: _session->domain().local().hasLocalPasscode();
}
bool PasscodeBox::onlyCheckCurrent() const {
@@ -520,7 +526,7 @@ void PasscodeBox::save(bool force) {
return;
}
if (Core::App().domain().local().checkPasscode(old.toUtf8())) {
if (_session->domain().local().checkPasscode(old.toUtf8())) {
cSetPasscodeBadTries(0);
if (_turningOff) pwd = conf = QString();
} else {
@@ -588,7 +594,7 @@ void PasscodeBox::save(bool force) {
closeReplacedBy();
const auto weak = Ui::MakeWeak(this);
cSetPasscodeBadTries(0);
Core::App().domain().local().setPasscode(pwd.toUtf8());
_session->domain().local().setPasscode(pwd.toUtf8());
Core::App().localPasscodeChanged();
if (weak) {
closeBox();

View File

@@ -434,6 +434,7 @@ PeerListRow::PeerListRow(not_null<PeerData*> peer)
PeerListRow::PeerListRow(not_null<PeerData*> peer, PeerListRowId id)
: _id(id)
, _peer(peer)
, _hidden(false)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false)
@@ -442,6 +443,7 @@ PeerListRow::PeerListRow(not_null<PeerData*> peer, PeerListRowId id)
PeerListRow::PeerListRow(PeerListRowId id)
: _id(id)
, _hidden(false)
, _initialized(false)
, _isSearchResult(false)
, _isSavedMessagesChat(false)
@@ -529,7 +531,7 @@ QString PeerListRow::generateShortName() {
: peer()->shortName();
}
std::shared_ptr<Data::CloudImageView> PeerListRow::ensureUserpicView() {
std::shared_ptr<Data::CloudImageView> &PeerListRow::ensureUserpicView() {
if (!_userpic) {
_userpic = peer()->createUserpicView();
}
@@ -588,11 +590,14 @@ void PeerListRow::paintStatusText(
_status.drawLeftElided(p, x, y, availableWidth, outerWidth);
}
template <typename UpdateCallback>
void PeerListRow::addRipple(const style::PeerListItem &st, QSize size, QPoint point, UpdateCallback updateCallback) {
template <typename MaskGenerator, typename UpdateCallback>
void PeerListRow::addRipple(const style::PeerListItem &st, MaskGenerator &&maskGenerator, QPoint point, UpdateCallback &&updateCallback) {
if (!_ripple) {
auto mask = Ui::RippleAnimation::rectMask(size);
_ripple = std::make_unique<Ui::RippleAnimation>(st.button.ripple, std::move(mask), std::move(updateCallback));
auto mask = maskGenerator();
if (mask.isNull()) {
return;
}
_ripple = std::make_unique<Ui::RippleAnimation>(st.button.ripple, std::move(mask), std::forward<UpdateCallback>(updateCallback));
}
_ripple->add(point);
}
@@ -741,12 +746,42 @@ PeerListContent::PeerListContent(
_repaintByStatus.setCallback([this] { update(); });
}
void PeerListContent::setMode(Mode mode) {
if (mode == Mode::Default && _mode == Mode::Default) {
return;
}
_mode = mode;
switch (_mode) {
case Mode::Default:
_rowHeight = _st.item.height;
break;
case Mode::Custom:
_rowHeight = _controller->customRowHeight();
break;
}
const auto wasMouseSelection = _mouseSelection;
const auto wasLastMousePosition = _lastMousePosition;
_contextMenu = nullptr;
if (wasMouseSelection) {
setSelected(Selected());
}
setPressed(Selected());
refreshRows();
if (wasMouseSelection && wasLastMousePosition) {
selectByMouse(*wasLastMousePosition);
}
}
void PeerListContent::appendRow(std::unique_ptr<PeerListRow> row) {
Expects(row != nullptr);
if (_rowsById.find(row->id()) == _rowsById.cend()) {
row->setAbsoluteIndex(_rows.size());
addRowEntry(row.get());
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.push_back(row.get());
}
_rows.push_back(std::move(row));
}
}
@@ -784,6 +819,17 @@ void PeerListContent::changeCheckState(
[=] { updateRow(row); });
}
void PeerListContent::setRowHidden(not_null<PeerListRow*> row, bool hidden) {
Expects(!row->isSearchResult());
row->setHidden(hidden);
if (hidden) {
_hiddenRows.emplace(row);
} else {
_hiddenRows.remove(row);
}
}
void PeerListContent::addRowEntry(not_null<PeerListRow*> row) {
if (_controller->respectSavedMessagesChat() && !row->special()) {
if (row->peer()->isSelf()) {
@@ -850,6 +896,10 @@ void PeerListContent::prependRow(std::unique_ptr<PeerListRow> row) {
if (_rowsById.find(row->id()) == _rowsById.cend()) {
addRowEntry(row.get());
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.insert(_filterResults.begin(), row.get());
}
_rows.insert(_rows.begin(), std::move(row));
refreshIndices();
}
@@ -865,6 +915,10 @@ void PeerListContent::prependRowFromSearchResult(not_null<PeerListRow*> row) {
Assert(_searchRows[index].get() == row);
row->setIsSearchResult(false);
if (!_hiddenRows.empty()) {
Assert(!row->hidden());
_filterResults.insert(_filterResults.begin(), row);
}
_rows.insert(_rows.begin(), std::move(_searchRows[index]));
refreshIndices();
removeRowAtIndex(_searchRows, index);
@@ -918,6 +972,7 @@ void PeerListContent::removeRow(not_null<PeerListRow*> row) {
_filterResults.erase(
ranges::remove(_filterResults, row),
end(_filterResults));
_hiddenRows.remove(row);
removeRowAtIndex(eraseFrom, index);
restoreSelection();
@@ -955,7 +1010,9 @@ void PeerListContent::convertRowToSearchResult(not_null<PeerListRow*> row) {
removeFromSearchIndex(row);
row->setIsSearchResult(true);
row->setHidden(false);
row->setAbsoluteIndex(_searchRows.size());
_hiddenRows.remove(row);
_searchRows.push_back(std::move(_rows[index]));
removeRowAtIndex(_rows, index);
}
@@ -1040,6 +1097,14 @@ int PeerListContent::labelHeight() const {
}
void PeerListContent::refreshRows() {
if (!_hiddenRows.empty()) {
_filterResults.clear();
for (const auto &row : _rows) {
if (!row->hidden()) {
_filterResults.push_back(row.get());
}
}
}
resizeToWidth(width());
if (_visibleBottom > 0) {
checkScrollForPreload();
@@ -1053,7 +1118,7 @@ void PeerListContent::refreshRows() {
void PeerListContent::setSearchMode(PeerListSearchMode mode) {
if (_searchMode != mode) {
if (!addingToSearchIndex()) {
for_const (auto &row, _rows) {
for (const auto &row : _rows) {
addToSearchIndex(row.get());
}
}
@@ -1080,25 +1145,27 @@ void PeerListContent::clearSearchRows() {
void PeerListContent::paintEvent(QPaintEvent *e) {
Painter p(this);
auto clip = e->rect();
p.fillRect(clip, _st.item.button.textBg);
const auto clip = e->rect();
if (_mode != Mode::Custom) {
p.fillRect(clip, _st.item.button.textBg);
}
auto repaintByStatusAfter = _repaintByStatus.remainingTime();
const auto repaintByStatusAfter = _repaintByStatus.remainingTime();
auto repaintAfterMin = repaintByStatusAfter;
auto rowsTopCached = rowsTop();
auto ms = crl::now();
auto yFrom = clip.y() - rowsTopCached;
auto yTo = clip.y() + clip.height() - rowsTopCached;
const auto rowsTopCached = rowsTop();
const auto now = crl::now();
const auto yFrom = clip.y() - rowsTopCached;
const auto yTo = clip.y() + clip.height() - rowsTopCached;
p.translate(0, rowsTopCached);
auto count = shownRowsCount();
const auto count = shownRowsCount();
if (count > 0) {
auto from = floorclamp(yFrom, _rowHeight, 0, count);
auto to = ceilclamp(yTo, _rowHeight, 0, count);
const auto from = floorclamp(yFrom, _rowHeight, 0, count);
const auto to = ceilclamp(yTo, _rowHeight, 0, count);
p.translate(0, from * _rowHeight);
for (auto index = from; index != to; ++index) {
auto repaintAfter = paintRow(p, ms, RowIndex(index));
if (repaintAfter >= 0
const auto repaintAfter = paintRow(p, now, RowIndex(index));
if (repaintAfter > 0
&& (repaintAfterMin < 0
|| repaintAfterMin > repaintAfter)) {
repaintAfterMin = repaintAfter;
@@ -1213,9 +1280,16 @@ void PeerListContent::mousePressEvent(QMouseEvent *e) {
row->addActionRipple(point, std::move(updateCallback));
}
} else {
auto size = QSize(width(), _rowHeight);
auto point = mapFromGlobal(QCursor::pos()) - QPoint(0, getRowTop(_selected.index));
row->addRipple(_st.item, size, point, std::move(updateCallback));
if (_mode == Mode::Custom) {
row->addRipple(_st.item, _controller->customRowRippleMaskGenerator(), point, std::move(updateCallback));
} else {
const auto maskGenerator = [&] {
return Ui::RippleAnimation::rectMask(
QSize(width(), _rowHeight));
};
row->addRipple(_st.item, maskGenerator, point, std::move(updateCallback));
}
}
}
if (anim::Disabled()) {
@@ -1246,13 +1320,22 @@ void PeerListContent::mousePressReleased(Qt::MouseButton button) {
void PeerListContent::showRowMenu(
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed) {
showRowMenu(findRowIndex(row), QCursor::pos(), std::move(destroyed));
const auto index = findRowIndex(row);
showRowMenu(
index,
row,
QCursor::pos(),
highlightRow,
std::move(destroyed));
}
bool PeerListContent::showRowMenu(
RowIndex index,
PeerListRow *row,
QPoint globalPos,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed) {
if (_contextMenu) {
_contextMenu->setDestroyedCallback(nullptr);
@@ -1263,7 +1346,9 @@ bool PeerListContent::showRowMenu(
mousePressReleased(_pressButton);
}
const auto row = getRow(index);
if (highlightRow) {
row = getRow(index);
}
if (!row) {
return false;
}
@@ -1274,11 +1359,15 @@ bool PeerListContent::showRowMenu(
return false;
}
setContexted({ index, false });
if (highlightRow) {
setContexted({ index, false });
}
raw->setDestroyedCallback(crl::guard(
this,
[=] {
setContexted(Selected());
if (highlightRow) {
setContexted(Selected());
}
handleMouseMove(QCursor::pos());
if (destroyed) {
destroyed(raw);
@@ -1292,7 +1381,7 @@ void PeerListContent::contextMenuEvent(QContextMenuEvent *e) {
if (e->reason() == QContextMenuEvent::Mouse) {
handleMouseMove(e->globalPos());
}
if (showRowMenu(_selected.index, e->globalPos())) {
if (showRowMenu(_selected.index, nullptr, e->globalPos(), true)) {
e->accept();
}
}
@@ -1307,7 +1396,7 @@ void PeerListContent::setPressed(Selected pressed) {
crl::time PeerListContent::paintRow(
Painter &p,
crl::time ms,
crl::time now,
RowIndex index) {
const auto row = getRow(index);
Assert(row != nullptr);
@@ -1315,13 +1404,15 @@ crl::time PeerListContent::paintRow(
row->lazyInitialize(_st.item);
auto refreshStatusAt = row->refreshStatusTime();
if (refreshStatusAt >= 0 && ms >= refreshStatusAt) {
if (refreshStatusAt > 0 && now >= refreshStatusAt) {
row->refreshStatus();
refreshStatusAt = row->refreshStatusTime();
}
const auto refreshStatusIn = (refreshStatusAt > 0)
? std::max(refreshStatusAt - now, crl::time(1))
: 0;
const auto peer = row->special() ? nullptr : row->peer().get();
const auto user = peer ? peer->asUser() : nullptr;
const auto active = (_contexted.index.value >= 0)
? _contexted
: (_pressed.index.value >= 0)
@@ -1330,6 +1421,11 @@ crl::time PeerListContent::paintRow(
const auto selected = (active.index == index);
const auto actionSelected = (selected && active.action);
if (_mode == Mode::Custom) {
_controller->customRowPaint(p, now, row, selected);
return refreshStatusIn;
}
const auto &bg = selected
? _st.item.button.textBgOver
: _st.item.button.textBg;
@@ -1412,7 +1508,7 @@ crl::time PeerListContent::paintRow(
} else {
row->paintStatusText(p, _st.item, _st.item.statusPosition.x(), _st.item.statusPosition.y(), statusw, width(), selected);
}
return (refreshStatusAt - ms);
return refreshStatusIn;
}
PeerListContent::SkipResult PeerListContent::selectSkip(int direction) {
@@ -1562,6 +1658,8 @@ void PeerListContent::searchQueryChanged(QString query) {
if (_normalizedSearchQuery != normalizedQuery) {
setSearchQuery(query, normalizedQuery);
if (_controller->searchInLocal() && !searchWordsList.isEmpty()) {
Assert(_hiddenRows.empty());
auto minimalList = (const std::vector<not_null<PeerListRow*>>*)nullptr;
for (const auto &searchWord : searchWordsList) {
auto searchWordStart = searchWord[0].toLower();
@@ -1611,15 +1709,17 @@ void PeerListContent::searchQueryChanged(QString query) {
}
std::unique_ptr<PeerListState> PeerListContent::saveState() const {
Expects(_hiddenRows.empty());
auto result = std::make_unique<PeerListState>();
result->controllerState
= std::make_unique<PeerListController::SavedStateBase>();
result->list.reserve(_rows.size());
for (auto &row : _rows) {
for (const auto &row : _rows) {
result->list.push_back(row->peer());
}
result->filterResults.reserve(_filterResults.size());
for (auto &row : _filterResults) {
for (const auto &row : _filterResults) {
result->filterResults.push_back(row->peer());
}
result->searchQuery = _searchQuery;
@@ -1740,15 +1840,25 @@ void PeerListContent::selectByMouse(QPoint globalPosition) {
_mouseSelection = true;
_lastMousePosition = globalPosition;
const auto point = mapFromGlobal(globalPosition);
const auto customMode = (_mode == Mode::Custom);
auto in = parentWidget()->rect().contains(parentWidget()->mapFromGlobal(globalPosition));
auto selected = Selected();
auto rowsPointY = point.y() - rowsTop();
selected.index.value = (in && rowsPointY >= 0 && rowsPointY < shownRowsCount() * _rowHeight) ? (rowsPointY / _rowHeight) : -1;
selected.index.value = (in
&& rowsPointY >= 0
&& rowsPointY < shownRowsCount() * _rowHeight)
? (rowsPointY / _rowHeight)
: -1;
if (selected.index.value >= 0) {
auto row = getRow(selected.index);
if (row->disabled()) {
const auto row = getRow(selected.index);
if (row->disabled()
|| (customMode
&& !_controller->customRowSelectionPoint(
row,
point.x(),
rowsPointY - (selected.index.value * _rowHeight)))) {
selected = Selected();
} else {
} else if (!customMode) {
if (getActiveActionRect(row, selected.index).contains(point)) {
selected.action = true;
}
@@ -1789,8 +1899,7 @@ void PeerListContent::updateRow(RowIndex index) {
if (index.value < 0) {
return;
}
auto row = getRow(index);
if (row->disabled()) {
if (const auto row = getRow(index); row && row->disabled()) {
if (index == _selected.index) {
setSelected(Selected());
}
@@ -1885,3 +1994,10 @@ PeerListContent::~PeerListContent() {
_contextMenu->setDestroyedCallback(nullptr);
}
}
void PeerListContentDelegate::peerListShowRowMenu(
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu *>)> destroyed) {
_content->showRowMenu(row, highlightRow, std::move(destroyed));
}

View File

@@ -82,7 +82,7 @@ public:
return _id;
}
[[nodiscard]] std::shared_ptr<Data::CloudImageView> ensureUserpicView();
[[nodiscard]] std::shared_ptr<Data::CloudImageView> &ensureUserpicView();
[[nodiscard]] virtual QString generateName();
[[nodiscard]] virtual QString generateShortName();
@@ -122,7 +122,7 @@ public:
bool actionSelected) {
}
void refreshName(const style::PeerListItem &st);
virtual void refreshName(const style::PeerListItem &st);
const Ui::Text::String &name() const {
return _name;
}
@@ -161,7 +161,7 @@ public:
template <typename UpdateCallback>
void setChecked(
bool checked,
const style::RoundImageCheckbox &st,
const style::RoundImageCheckbox &st,
anim::type animated,
UpdateCallback callback) {
if (checked && !_checkbox) {
@@ -169,15 +169,21 @@ public:
}
setCheckedInternal(checked, animated);
}
void setHidden(bool hidden) {
_hidden = hidden;
}
[[nodiscard]] bool hidden() const {
return _hidden;
}
void finishCheckedAnimation();
void invalidatePixmapsCache();
template <typename UpdateCallback>
template <typename MaskGenerator, typename UpdateCallback>
void addRipple(
const style::PeerListItem &st,
QSize size,
MaskGenerator &&maskGenerator,
QPoint point,
UpdateCallback updateCallback);
UpdateCallback &&updateCallback);
void stopLastRipple();
void paintRipple(Painter &p, int x, int y, int outerWidth);
void paintUserpic(
@@ -237,6 +243,7 @@ private:
base::flat_set<QChar> _nameFirstLetters;
int _absoluteIndex = -1;
State _disabledState = State::Active;
bool _hidden : 1;
bool _initialized : 1;
bool _isSearchResult : 1;
bool _isSavedMessagesChat : 1;
@@ -274,6 +281,7 @@ public:
virtual void peerListConvertRowToSearchResult(not_null<PeerListRow*> row) = 0;
virtual bool peerListIsRowChecked(not_null<PeerListRow*> row) = 0;
virtual void peerListSetRowChecked(not_null<PeerListRow*> row, bool checked) = 0;
virtual void peerListSetRowHidden(not_null<PeerListRow*> row, bool hidden) = 0;
virtual void peerListSetForeignRowChecked(
not_null<PeerListRow*> row,
bool checked,
@@ -304,6 +312,7 @@ public:
virtual void peerListShowRowMenu(
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) = 0;
virtual int peerListSelectedRowsCount() = 0;
virtual std::unique_ptr<PeerListState> peerListSaveState() const = 0;
@@ -450,6 +459,25 @@ public:
[[nodiscard]] virtual bool respectSavedMessagesChat() const {
return false;
}
[[nodiscard]] virtual int customRowHeight() {
Unexpected("PeerListController::customRowHeight.");
}
virtual void customRowPaint(
Painter &p,
crl::time now,
not_null<PeerListRow*> row,
bool selected) {
Unexpected("PeerListController::customRowPaint.");
}
[[nodiscard]] virtual bool customRowSelectionPoint(
not_null<PeerListRow*> row,
int x,
int y) {
Unexpected("PeerListController::customRowSelectionPoint.");
}
[[nodiscard]] virtual Fn<QImage()> customRowRippleMaskGenerator() {
Unexpected("PeerListController::customRowRippleMaskGenerator.");
}
[[nodiscard]] virtual rpl::producer<int> onlineCountValue() const;
@@ -514,6 +542,12 @@ public:
SkipResult selectSkip(int direction);
void selectSkipPage(int height, int direction);
enum class Mode {
Default,
Custom,
};
void setMode(Mode mode);
[[nodiscard]] rpl::producer<int> selectedIndexValue() const;
[[nodiscard]] bool hasSelection() const;
[[nodiscard]] bool hasPressed() const;
@@ -552,6 +586,9 @@ public:
not_null<PeerListRow*> row,
bool checked,
anim::type animated);
void setRowHidden(
not_null<PeerListRow*> row,
bool hidden);
template <typename ReorderCallback>
void reorderRows(ReorderCallback &&callback) {
@@ -560,6 +597,9 @@ public:
callback(searchEntity.second.begin(), searchEntity.second.end());
}
refreshIndices();
if (!_hiddenRows.empty()) {
callback(_filterResults.begin(), _filterResults.end());
}
update();
}
@@ -568,6 +608,7 @@ public:
void showRowMenu(
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed);
auto scrollToRequests() const {
@@ -655,10 +696,12 @@ private:
bool showRowMenu(
RowIndex index,
PeerListRow *row,
QPoint globalPos,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr);
crl::time paintRow(Painter &p, crl::time ms, RowIndex index);
crl::time paintRow(Painter &p, crl::time now, RowIndex index);
void addRowEntry(not_null<PeerListRow*> row);
void addToSearchIndex(not_null<PeerListRow*> row);
@@ -666,7 +709,7 @@ private:
void removeFromSearchIndex(not_null<PeerListRow*> row);
void setSearchQuery(const QString &query, const QString &normalizedQuery);
bool showingSearch() const {
return !_searchQuery.isEmpty();
return !_hiddenRows.empty() || !_searchQuery.isEmpty();
}
int shownRowsCount() const {
return showingSearch() ? _filterResults.size() : _rows.size();
@@ -688,6 +731,7 @@ private:
not_null<PeerListController*> _controller;
PeerListSearchMode _searchMode = PeerListSearchMode::Disabled;
Mode _mode = Mode::Default;
int _rowHeight = 0;
int _visibleTop = 0;
int _visibleBottom = 0;
@@ -711,6 +755,7 @@ private:
QString _normalizedSearchQuery;
QString _mentionHighlight;
std::vector<not_null<PeerListRow*>> _filterResults;
base::flat_set<not_null<PeerListRow*>> _hiddenRows;
int _aboveHeight = 0;
int _belowHeight = 0;
@@ -775,6 +820,11 @@ public:
bool checked) override {
_content->changeCheckState(row, checked, anim::type::normal);
}
void peerListSetRowHidden(
not_null<PeerListRow*> row,
bool hidden) override {
_content->setRowHidden(row, hidden);
}
void peerListSetForeignRowChecked(
not_null<PeerListRow*> row,
bool checked,
@@ -845,10 +895,9 @@ public:
_content->restoreState(std::move(state));
}
void peerListShowRowMenu(
not_null<PeerListRow*> row,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override {
_content->showRowMenu(row, std::move(destroyed));
}
not_null<PeerListRow*> row,
bool highlightRow,
Fn<void(not_null<Ui::PopupMenu*>)> destroyed = nullptr) override;
protected:
not_null<PeerListContent*> content() const {

View File

@@ -201,8 +201,10 @@ void SaveSlowmodeSeconds(
void ShowEditPermissions(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
const auto box = Ui::show(
Box<EditPeerPermissionsBox>(navigation, peer),
auto content = Box<EditPeerPermissionsBox>(navigation, peer);
const auto box = QPointer<EditPeerPermissionsBox>(content.data());
navigation->parentController()->show(
std::move(content),
Ui::LayerOption::KeepOther);
const auto saving = box->lifetime().make_state<int>(0);
const auto save = [=](
@@ -244,8 +246,10 @@ void ShowEditPermissions(
void ShowEditInviteLinks(
not_null<Window::SessionNavigation*> navigation,
not_null<PeerData*> peer) {
const auto box = Ui::show(
Box<EditPeerPermissionsBox>(navigation, peer),
auto content = Box<EditPeerPermissionsBox>(navigation, peer);
const auto box = QPointer<EditPeerPermissionsBox>(content.data());
navigation->parentController()->show(
std::move(content),
Ui::LayerOption::KeepOther);
const auto saving = box->lifetime().make_state<int>(0);
const auto save = [=](
@@ -612,7 +616,7 @@ object_ptr<Ui::RpWidget> Controller::createStickersEdit() {
tr::lng_group_stickers_add(tr::now),
st::editPeerInviteLinkButton)
)->addClickHandler([=] {
Ui::show(
_navigation->parentController()->show(
Box<StickersBox>(_navigation->parentController(), channel),
Ui::LayerOption::KeepOther);
});
@@ -649,7 +653,7 @@ void Controller::showEditPeerTypeBox(
_usernameSavedValue = publicLink;
refreshHistoryVisibility();
});
Ui::show(
_navigation->parentController()->show(
Box<EditPeerTypeBox>(
_peer,
_channelHasLocationOriginalValue,
@@ -681,7 +685,7 @@ void Controller::showEditLinkedChatBox() {
|| channel->canEditPreHistoryHidden()));
if (const auto chat = *_linkedChatSavedValue) {
*box = Ui::show(
*box = _navigation->parentController()->show(
EditLinkedChatBox(
_navigation,
channel,
@@ -709,7 +713,7 @@ void Controller::showEditLinkedChatBox() {
for (const auto &item : list) {
chats.emplace_back(_peer->owner().processChat(item));
}
*box = Ui::show(
*box = _navigation->parentController()->show(
EditLinkedChatBox(
_navigation,
channel,
@@ -858,7 +862,7 @@ void Controller::fillHistoryVisibilityButton() {
_historyVisibilitySavedValue = checked;
});
const auto buttonCallback = [=] {
Ui::show(
_navigation->parentController()->show(
Box<EditPeerHistoryVisibilityBox>(
_peer,
boxCallback,
@@ -1023,9 +1027,15 @@ void Controller::fillManageSection() {
wrap->entity(),
tr::lng_manage_peer_invite_links(),
rpl::duplicate(count) | ToPositiveNumberString(),
[=] { Ui::show(
Box(ManageInviteLinksBox, _peer, _peer->session().user(), 0, 0),
Ui::LayerOption::KeepOther);
[=] {
_navigation->parentController()->show(
Box(
ManageInviteLinksBox,
_peer,
_peer->session().user(),
0,
0),
Ui::LayerOption::KeepOther);
},
st::infoIconInviteLinks);
@@ -1520,7 +1530,7 @@ void Controller::deleteWithConfirmation() {
const auto deleteCallback = crl::guard(this, [=] {
deleteChannel();
});
Ui::show(
_navigation->parentController()->show(
Box<ConfirmBox>(
text,
tr::lng_box_delete(tr::now),

View File

@@ -133,8 +133,8 @@ QImage QrExact(const Qr::Data &data, int pixel, QColor color) {
skip,
skip,
Intro::details::TelegramLogoImage().scaled(
logoSize,
logoSize,
logoSize * cIntRetinaFactor(),
logoSize * cIntRetinaFactor(),
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation));
}

View File

@@ -533,7 +533,7 @@ void LinksController::rowClicked(not_null<PeerListRow*> row) {
}
void LinksController::rowActionClicked(not_null<PeerListRow*> row) {
delegate()->peerListShowRowMenu(row, nullptr);
delegate()->peerListShowRowMenu(row, true);
}
base::unique_qptr<Ui::PopupMenu> LinksController::rowContextMenu(

View File

@@ -1002,7 +1002,7 @@ void SendFilesBox::sendScheduled() {
? SendMenu::Type::ScheduledToUser
: _sendMenuType;
const auto callback = [=](Api::SendOptions options) { send(options); };
Ui::show(
_controller->show(
HistoryView::PrepareScheduleBox(this, type, callback),
Ui::LayerOption::KeepOther);
}

View File

@@ -63,12 +63,14 @@ public:
bool loaded() const;
bool notInstalled() const;
bool official() const;
rpl::producer<TextWithEntities> title() const;
QString shortName() const;
[[nodiscard]] rpl::producer<TextWithEntities> title() const;
[[nodiscard]] QString shortName() const;
void install();
rpl::producer<uint64> setInstalled() const;
rpl::producer<> updateControls() const;
[[nodiscard]] rpl::producer<uint64> setInstalled() const;
[[nodiscard]] rpl::producer<> updateControls() const;
[[nodiscard]] rpl::producer<Error> errors() const;
~Inner();
@@ -137,6 +139,7 @@ private:
rpl::event_stream<uint64> _setInstalled;
rpl::event_stream<> _updateControls;
rpl::event_stream<Error> _errors;
};
@@ -153,7 +156,7 @@ QPointer<Ui::BoxContent> StickerSetBox::Show(
not_null<DocumentData*> document) {
if (const auto sticker = document->sticker()) {
if (sticker->set.type() != mtpc_inputStickerSetEmpty) {
return Ui::show(
return controller->show(
Box<StickerSetBox>(controller, sticker->set),
Ui::LayerOption::KeepOther).data();
}
@@ -186,6 +189,11 @@ void StickerSetBox::prepare() {
_controller->session().api().stickerSetInstalled(setId);
closeBox();
}, lifetime());
_inner->errors(
) | rpl::start_with_next([=](Error error) {
handleError(error);
}, lifetime());
}
void StickerSetBox::addStickers() {
@@ -198,6 +206,52 @@ void StickerSetBox::copyStickersLink() {
QGuiApplication::clipboard()->setText(url);
}
void StickerSetBox::handleError(Error error) {
const auto guard = gsl::finally(crl::guard(this, [=] {
closeBox();
}));
switch (error) {
case Error::NotFound:
_controller->show(
Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
break;
default: Unexpected("Error in StickerSetBox::handleError.");
}
}
void StickerSetBox::archiveStickers() {
const auto weak = base::make_weak(_controller.get());
const auto setId = _set.c_inputStickerSetID().vid().v;
_controller->session().api().request(MTPmessages_InstallStickerSet(
_set,
MTP_boolTrue()
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
const auto controller = weak.get();
if (!controller) {
return;
}
if (result.type() == mtpc_messages_stickerSetInstallResultSuccess) {
Ui::Toast::Show(tr::lng_stickers_has_been_archived(tr::now));
const auto &session = controller->session();
auto &order = session.data().stickers().setsOrderRef();
const auto index = order.indexOf(setId);
if (index == -1) {
return;
}
order.removeAt(index);
session.local().writeInstalledStickers();
session.local().writeArchivedStickers();
session.data().stickers().notifyUpdated();
}
}).fail([](const MTP::Error &error) {
Ui::Toast::Show(Lang::Hard::ServerError());
}).send();
}
void StickerSetBox::updateTitleAndButtons() {
setTitle(_inner->title());
updateButtons();
@@ -237,6 +291,24 @@ void StickerSetBox::updateButtons() {
};
addButton(tr::lng_stickers_share_pack(), std::move(share));
addButton(tr::lng_cancel(), [=] { closeBox(); });
if (!_inner->shortName().isEmpty()) {
const auto top = addTopButton(st::infoTopBarMenu);
const auto archive = [=] {
archiveStickers();
closeBox();
};
const auto menu =
std::make_shared<base::unique_qptr<Ui::PopupMenu>>();
top->setClickedCallback([=] {
*menu = base::make_unique_q<Ui::PopupMenu>(top);
(*menu)->addAction(
tr::lng_stickers_archive_pack(tr::now),
archive);
(*menu)->popup(QCursor::pos());
return true;
});
}
}
} else {
addButton(tr::lng_cancel(), [=] { closeBox(); });
@@ -274,7 +346,7 @@ StickerSetBox::Inner::Inner(
gotSet(result);
}).fail([=](const MTP::Error &error) {
_loaded = true;
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
}).send();
_controller->session().api().updateStickers();
@@ -369,7 +441,7 @@ void StickerSetBox::Inner::gotSet(const MTPmessages_StickerSet &set) {
});
if (_pack.isEmpty()) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
return;
} else {
int32 rows = _pack.size() / kStickersPanelPerRow + ((_pack.size() % kStickersPanelPerRow) ? 1 : 0);
@@ -389,6 +461,10 @@ rpl::producer<> StickerSetBox::Inner::updateControls() const {
return _updateControls.events();
}
rpl::producer<StickerSetBox::Error> StickerSetBox::Inner::errors() const {
return _errors.events();
}
void StickerSetBox::Inner::installDone(
const MTPmessages_StickerSetInstallResult &result) {
auto &sets = _controller->session().data().stickers().setsRef();
@@ -745,7 +821,7 @@ QString StickerSetBox::Inner::shortName() const {
void StickerSetBox::Inner::install() {
if (isMasksSet()) {
Ui::show(
_controller->show(
Box<InformBox>(tr::lng_stickers_masks_pack(tr::now)),
Ui::LayerOption::KeepOther);
return;
@@ -758,7 +834,7 @@ void StickerSetBox::Inner::install() {
)).done([=](const MTPmessages_StickerSetInstallResult &result) {
installDone(result);
}).fail([=](const MTP::Error &error) {
Ui::show(Box<InformBox>(tr::lng_stickers_not_found(tr::now)));
_errors.fire(Error::NotFound);
}).send();
}

View File

@@ -38,10 +38,16 @@ protected:
void resizeEvent(QResizeEvent *e) override;
private:
enum class Error {
NotFound,
};
void updateTitleAndButtons();
void updateButtons();
void addStickers();
void copyStickersLink();
void archiveStickers();
void handleError(Error error);
const not_null<Window::SessionController*> _controller;
MTPInputStickerSet _set;

View File

@@ -68,9 +68,7 @@ private:
};
// This class is hold in header because it requires Qt preprocessing.
class StickersBox::Inner
: public Ui::RpWidget
, private base::Subscriber {
class StickersBox::Inner : public Ui::RpWidget {
public:
using Section = StickersBox::Section;
@@ -85,7 +83,9 @@ public:
[[nodiscard]] Main::Session &session() const;
base::Observable<int> scrollToY;
rpl::producer<int> scrollsToY() const {
return _scrollsToY.events();
}
void setInnerFocus();
void saveGroupSet();
@@ -276,6 +276,8 @@ private:
int _above = -1;
rpl::event_stream<int> _draggingScrollDelta;
rpl::event_stream<int> _scrollsToY;
int _minHeight = 0;
int _scrollbar = 0;
@@ -387,9 +389,10 @@ StickersBox::StickersBox(
, _section(Section::Installed)
, _installed(0, this, controller, megagroup)
, _megagroupSet(megagroup) {
subscribe(_installed.widget()->scrollToY, [=](int y) {
_installed.widget()->scrollsToY(
) | rpl::start_with_next([=](int y) {
onScrollToY(y);
});
}, lifetime());
}
StickersBox::StickersBox(
@@ -1589,7 +1592,7 @@ void StickersBox::Inner::mouseReleaseEvent(QMouseEvent *e) {
}();
const auto showSetByRow = [&](const Row &row) {
setSelected(SelectedRow());
Ui::show(
_controller->show(
Box<StickerSetBox>(_controller, row.set->mtpInput()),
Ui::LayerOption::KeepOther);
};
@@ -1898,7 +1901,7 @@ void StickersBox::Inner::rebuild() {
void StickersBox::Inner::setMegagroupSelectedSet(const MTPInputStickerSet &set) {
_megagroupSetInput = set;
rebuild();
scrollToY.notify(0, true);
_scrollsToY.fire(0);
updateSelected();
}

View File

@@ -175,6 +175,87 @@ callCameraUnmute: CallButton(callMicrophoneUnmute) {
}
callBottomShadowSize: 124px;
CallMuteButton {
active: CallButton;
muted: CallButton;
labelAdditional: pixels;
sublabel: FlatLabel;
labelsSkip: pixels;
sublabelSkip: pixels;
lottieSize: size;
lottieTop: pixels;
}
callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMembersFg;
style: TextStyle(defaultTextStyle) {
font: font(14px);
linkFont: font(14px);
linkFontOver: font(14px underline);
}
}
callMuteButtonActiveInner: IconButton {
width: 112px;
height: 138px;
}
callMuteButtonSmallActiveInner: IconButton {
width: 68px;
height: 68px;
}
callMuteButtonActive: CallButton {
button: callMuteButtonActiveInner;
bg: groupCallLive1;
bgSize: 77px;
bgPosition: point(18px, 18px);
outerRadius: 18px;
outerBg: callAnswerBgOuter;
label: callMuteButtonLabel;
}
callMuteButton: CallMuteButton {
active: callMuteButtonActive;
muted: CallButton(callMuteButtonActive) {
bg: groupCallMuted1;
label: callMuteButtonLabel;
}
labelAdditional: 5px;
sublabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMemberNotJoinedStatus;
}
labelsSkip: 8px;
sublabelSkip: 14px;
lottieSize: size(54px, 54px);
lottieTop: 31px;
}
callMuteButtonSmallActive: CallButton(callMuteButtonActive) {
button: callMuteButtonSmallActiveInner;
bgSize: 42px;
bgPosition: point(13px, 13px);
outerRadius: 13px;
label: callButtonLabel;
}
callMuteButtonSmall: CallMuteButton(callMuteButton) {
active: callMuteButtonSmallActive;
muted: CallButton(callMuteButtonSmallActive) {
bg: groupCallMuted1;
label: callButtonLabel;
}
labelsSkip: 0px;
sublabelSkip: 0px;
lottieSize: size(36px, 36px);
lottieTop: 17px;
}
callMuteMinorBlobMinRadius: 64px;
callMuteMinorBlobMaxRadius: 74px;
callMuteMajorBlobMinRadius: 67px;
callMuteMajorBlobMaxRadius: 77px;
callMuteBlobRadiusForDiameter: 100px;
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: lightButtonFg;
thickness: 4px;
}
callName: FlatLabel(defaultFlatLabel) {
minWidth: 260px;
maxHeight: 30px;
@@ -208,55 +289,6 @@ callRemoteAudioMute: FlatLabel(callStatus) {
}
callRemoteAudioMuteSkip: 12px;
callMuteMainBlobMinRadius: 57px;
callMuteMainBlobMaxRadius: 63px;
callMuteMinorBlobMinRadius: 64px;
callMuteMinorBlobMaxRadius: 74px;
callMuteMajorBlobMinRadius: 67px;
callMuteMajorBlobMaxRadius: 77px;
callMuteButtonActiveInner: IconButton {
width: 136px;
height: 165px;
}
callMuteButtonLabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMembersFg;
style: TextStyle(defaultTextStyle) {
font: font(14px);
linkFont: font(14px);
linkFontOver: font(14px underline);
}
}
callMuteButtonSublabel: FlatLabel(defaultFlatLabel) {
textFg: groupCallMemberNotJoinedStatus;
}
callMuteButtonLabelsSkip: 5px;
callMuteButtonSublabelSkip: 19px;
callMuteButtonActive: CallButton {
button: callMuteButtonActiveInner;
bg: groupCallLive1;
bgSize: 100px;
bgPosition: point(18px, 18px);
outerRadius: 18px;
outerBg: callAnswerBgOuter;
label: callMuteButtonLabel;
}
callMuteButtonMuted: CallButton(callMuteButtonActive) {
bg: groupCallMuted1;
label: callMuteButtonLabel;
}
callMuteButtonConnecting: CallButton(callMuteButtonMuted) {
bg: callIconBg;
label: callMuteButtonLabel;
}
callMuteButtonLabelAdditional: 5px;
callConnectingRadial: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) {
color: lightButtonFg;
thickness: 4px;
size: size(100px, 100px);
}
callBarHeight: 38px;
callBarMuteToggle: IconButton {
width: 41px;
@@ -433,7 +465,8 @@ callTitle: WindowTitle(defaultWindowTitle) {
closeIconActive: callTitleCloseIcon;
closeIconActiveOver: callTitleCloseIconOver;
}
callTitleShadow: icon {{ "calls/calls_shadow_controls", windowShadowFg }};
callTitleShadowRight: icon {{ "calls/calls_shadow_controls", windowShadowFg }};
callTitleShadowLeft: icon {{ "calls/calls_shadow_controls-flip_horizontal", windowShadowFg }};
callErrorToast: Toast(defaultToast) {
minWidth: 240px;
@@ -442,8 +475,6 @@ callErrorToast: Toast(defaultToast) {
groupCallWidth: 380px;
groupCallHeight: 580px;
groupCallMuteButtonIconSize: size(67px, 67px);
groupCallMuteButtonIconTop: 35px;
groupCallRipple: RippleAnimation(defaultRippleAnimation) {
color: groupCallMembersBgRipple;
}
@@ -459,6 +490,7 @@ groupCallMenu: Menu(defaultMenu) {
itemFgShortcutDisabled: groupCallMemberNotJoinedStatus;
separatorFg: groupCallMenuBgOver;
separatorPadding: margins(0px, 4px, 0px, 4px);
arrow: icon {{ "dropdown_submenu_arrow", groupCallMemberNotJoinedStatus }};
@@ -482,6 +514,16 @@ groupCallPopupMenu: PopupMenu(defaultPopupMenu) {
menu: groupCallMenu;
animation: groupCallPanelAnimation;
}
groupCallPopupMenuWithVolume: PopupMenu(groupCallPopupMenu) {
scrollPadding: margins(0px, 3px, 0px, 8px);
menu: Menu(groupCallMenu) {
widthMin: 210px;
}
}
groupCallPopupVolumeMenu: Menu(groupCallMenu) {
widthMin: 210px;
itemBgOver: groupCallMenuBg;
}
groupCallRecordingTimerPadding: margins(0px, 4px, 0px, 4px);
groupCallRecordingTimerFont: font(12px);
@@ -532,6 +574,11 @@ groupCallMembersListItem: PeerListItem(defaultPeerListItem) {
statusFgOver: groupCallMemberInactiveStatus;
statusFgActive: groupCallMemberActiveStatus;
}
groupCallNarrowMembersListItem: PeerListItem(groupCallMembersListItem) {
statusFg: groupCallMemberNotJoinedStatus;
statusFgOver: groupCallMemberNotJoinedStatus;
statusFgActive: groupCallMemberActiveStatus;
}
groupCallMembersList: PeerList(defaultPeerList) {
bg: groupCallMembersBg;
about: FlatLabel(defaultPeerListAbout) {
@@ -648,8 +695,8 @@ groupCallShareBoxList: PeerList(groupCallMembersList) {
groupCallMembersTop: 51px;
groupCallTitleTop: 8px;
groupCallSubtitleTop: 26px;
groupCallWideVideoTop: 24px;
groupCallMembersMargin: margins(16px, 16px, 16px, 28px);
groupCallAddMember: SettingsButton(defaultSettingsButton) {
textFg: groupCallMemberNotJoinedStatus;
textFgOver: groupCallMemberNotJoinedStatus;
@@ -678,7 +725,7 @@ groupCallTitleLabel: FlatLabel(groupCallSubtitleLabel) {
}
}
groupCallAddButtonPosition: point(10px, 7px);
groupCallMembersWidthMax: 360px;
groupCallMembersWidthMax: 480px;
groupCallRecordingMark: 6px;
groupCallRecordingMarkSkip: 4px;
groupCallRecordingMarkTop: 8px;
@@ -704,6 +751,7 @@ groupCallJoinAsToggle: UserpicButton(defaultUserpicButton) {
photoPosition: point(3px, 3px);
}
groupCallMenuPosition: point(-1px, 29px);
groupCallWideMenuPosition: point(-2px, 28px);
groupCallActiveButton: IconButton {
width: 36px;
@@ -736,33 +784,106 @@ groupCallMemberRaisedHand: icon {{ "calls/group_calls_raised_hand", groupCallMem
groupCallSettingsInner: IconButton(callButton) {
iconPosition: point(-1px, 22px);
icon: icon {{ "calls/call_settings", groupCallIconFg }};
icon: icon {{ "calls/calls_settings", groupCallIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: callMuteRipple;
}
}
groupCallShareInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/group_calls_share", groupCallIconFg }};
}
groupCallVideoInner: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/call_camera_muted", groupCallIconFg }};
iconPosition: point(-1px, 16px);
}
groupCallHangupInner: IconButton(callButton) {
icon: icon {{ "calls/call_discard", groupCallIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: groupCallLeaveBgRipple;
}
}
groupCallSettings: CallButton(callMicrophoneMute) {
button: groupCallSettingsInner;
}
groupCallShare: CallButton(groupCallSettings) {
button: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/group_calls_share", groupCallIconFg }};
}
button: groupCallShareInner;
}
groupCallVideo: CallButton(groupCallSettings) {
button: groupCallVideoInner;
}
groupCallVideoInnerActive: IconButton(groupCallVideoInner) {
icon: icon {{ "calls/call_camera_active", groupCallIconFg }};
}
groupCallVideoActive: CallButton(groupCallVideo) {
button: groupCallVideoInnerActive;
}
groupCallHangup: CallButton(callHangup) {
button: IconButton(callButton) {
icon: icon {{ "calls/call_discard", groupCallIconFg }};
ripple: RippleAnimation(defaultRippleAnimation) {
color: groupCallLeaveBgRipple;
}
}
button: groupCallHangupInner;
bg: groupCallLeaveBg;
outerBg: groupCallLeaveBg;
label: callButtonLabel;
}
groupCallButtonSkip: 43px;
groupCallButtonBottomSkip: 145px;
groupCallMuteBottomSkip: 160px;
groupCallSettingsSmall: CallButton(groupCallSettings) {
button: IconButton(groupCallSettingsInner) {
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
bgPosition: point(8px, 12px);
}
groupCallHangupSmall: CallButton(groupCallHangup) {
button: IconButton(groupCallHangupInner) {
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
bgPosition: point(8px, 12px);
}
groupCallVideoSmall: CallButton(groupCallSettingsSmall) {
button: IconButton(groupCallVideoInner) {
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
}
groupCallVideoActiveSmall: CallButton(groupCallVideoSmall) {
button: IconButton(groupCallVideoInnerActive) {
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
}
groupCallScreenShareSmall: CallButton(groupCallSettingsSmall) {
button: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/calls_present", groupCallIconFg }};
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
}
groupCallMenuToggleSmall: CallButton(groupCallSettingsSmall) {
button: IconButton(groupCallSettingsInner) {
icon: icon {{ "calls/calls_more", groupCallIconFg }};
width: 60px;
height: 68px;
rippleAreaPosition: point(8px, 12px);
}
}
groupCallButtonSkip: 40px;
groupCallButtonSkipSmall: 5px;
groupCallButtonBottomSkip: 113px;
groupCallButtonBottomSkipSmall: 95px;
groupCallButtonBottomSkipWide: 108px;
groupCallControlsBackMargin: margins(10px, 0px, 10px, 0px);
groupCallControlsBackRadius: 12px;
groupCallMuteBottomSkip: 116px;
groupCallMembersMargin: margins(16px, 16px, 16px, 60px);
groupCallMembersTopSkip: 6px;
groupCallMembersBottomSkip: 80px;
groupCallMembersShadowHeight: 160px;
groupCallMembersFadeSkip: 10px;
groupCallMembersFadeHeight: 100px;
groupCallTopBarUserpics: GroupCallUserpics {
size: 28px;
@@ -780,17 +901,18 @@ groupCallTopBarOpen: RoundButton(groupCallTopBarJoin) {
color: shadowFg;
}
}
groupCallBox: Box(defaultBox) {
button: RoundButton(defaultBoxButton) {
textFg: groupCallActiveFg;
textFgOver: groupCallActiveFg;
numbersTextFg: groupCallActiveFg;
numbersTextFgOver: groupCallActiveFg;
textBg: groupCallMembersBg;
textBgOver: groupCallMembersBgOver;
groupCallBoxButton: RoundButton(defaultBoxButton) {
textFg: groupCallActiveFg;
textFgOver: groupCallActiveFg;
numbersTextFg: groupCallActiveFg;
numbersTextFgOver: groupCallActiveFg;
textBg: groupCallMembersBg;
textBgOver: groupCallMembersBgOver;
ripple: groupCallRipple;
}
ripple: groupCallRipple;
}
groupCallBox: Box(defaultBox) {
button: groupCallBoxButton;
margin: margins(0px, 56px, 0px, 10px);
bg: groupCallMembersBg;
title: FlatLabel(boxTitle) {
@@ -807,7 +929,7 @@ groupCallLevelMeter: LevelMeter(defaultLevelMeter) {
lineSpacing: 5px;
lineCount: 44;
activeFg: groupCallActiveFg;
inactiveFg: groupCallMemberNotJoinedStatus;
inactiveFg: groupCallMembersBgRipple;
}
groupCallCheckboxIcon: icon {{ "default_checkbox_check", groupCallMembersFg, point(4px, 7px) }};
groupCallCheck: Check(defaultCheck) {
@@ -960,13 +1082,17 @@ groupCallMuteCrossLine: CrossLineAnimation {
groupCallMenuSpeakerArcsSkip: 1px;
groupCallMenuVolumeSkip: 5px;
groupCallMenuVolumePadding: margins(17px, 6px, 17px, 5px);
groupCallMenuVolumeMargin: margins(55px, 0px, 15px, 0px);
groupCallMenuVolumeSlider: MediaSlider(defaultContinuousSlider) {
activeFg: groupCallMembersFg;
inactiveFg: groupCallMemberInactiveIcon;
inactiveFg: groupCallMembersBgOver;
activeFgOver: groupCallMembersFg;
inactiveFgOver: groupCallMemberInactiveIcon;
activeFgDisabled: groupCallMemberInactiveIcon;
receivedTillFg: groupCallMemberInactiveIcon;
inactiveFgOver: groupCallMembersBgOver;
activeFgDisabled: groupCallMembersBgOver;
receivedTillFg: groupCallMembersBgOver;
width: 7px;
seekSize: size(7px, 7px);
}
groupCallSpeakerArcsAnimation: ArcsAnimation {
@@ -1015,3 +1141,141 @@ groupCallStartsInTop: 10px;
groupCallStartsWhenTop: 160px;
groupCallCountdownFont: font(64px semibold);
groupCallCountdownTop: 52px;
desktopCaptureMargins: margins(12px, 8px, 12px, 6px);
desktopCaptureSourceSize: size(235px, 165px);
desktopCaptureSourceSkips: size(2px, 10px);
desktopCaptureSourceTitle: WindowTitle(groupCallTitle) {
bg: groupCallMembersBgOver;
bgActive: groupCallMembersBgOver;
height: 21px;
}
desktopCapturePadding: margins(7px, 7px, 7px, 33px);
desktopCaptureLabelBottom: 7px;
desktopCaptureLabel: FlatLabel(defaultFlatLabel) {
minWidth: 200px;
maxHeight: 20px;
textFg: groupCallMembersFg;
style: semiboldTextStyle;
}
desktopCaptureCancel: RoundButton(defaultBoxButton) {
textFg: groupCallActiveFg;
textFgOver: groupCallActiveFg;
numbersTextFg: groupCallActiveFg;
numbersTextFgOver: groupCallActiveFg;
textBg: groupCallMembersBg;
textBgOver: groupCallMembersBgOver;
ripple: groupCallRipple;
}
desktopCaptureFinish: RoundButton(desktopCaptureCancel) {
textFg: groupCallMemberMutedIcon;
textFgOver: groupCallMemberMutedIcon;
}
desktopCaptureSubmit: RoundButton(desktopCaptureCancel) {
textFg: groupCallIconFg;
textFgOver: groupCallIconFg;
numbersTextFg: groupCallIconFg;
numbersTextFgOver: groupCallIconFg;
textBg: groupCallMuted1;
textBgOver: groupCallMuted1;
ripple: RippleAnimation(groupCallRipple) {
color: shadowFg;
}
}
groupCallNarrowSkip: 9px;
groupCallNarrowMembersWidth: 204px;
groupCallNarrowVideoHeight: 120px;
groupCallWideModeWidthMin: 600px;
groupCallWideModeSize: size(960px, 580px);
groupCallNarrowInactiveCrossLine: CrossLineAnimation {
fg: groupCallMemberNotJoinedStatus;
icon: icon {{ "calls/video_mini_mute", groupCallMemberNotJoinedStatus }};
startPosition: point(3px, 0px);
endPosition: point(13px, 12px);
stroke: 3px;
strokeDenominator: 2;
}
groupCallNarrowColoredCrossLine: CrossLineAnimation(groupCallNarrowInactiveCrossLine) {
fg: groupCallMemberNotJoinedStatus;
icon: icon {{ "calls/video_mini_mute", groupCallMemberActiveStatus }};
}
groupCallNarrowRaisedHand: icon {{ "calls/video_mini_speak", groupCallMemberInactiveStatus }};
groupCallNarrowCameraIcon: icon {{ "calls/video_mini_video", groupCallMemberNotJoinedStatus }};
groupCallNarrowScreenIcon: icon {{ "calls/video_mini_screencast", groupCallMemberNotJoinedStatus }};
groupCallNarrowIconPosition: point(-4px, 2px);
groupCallNarrowIconSkip: 15px;
groupCallOutline: 2px;
groupCallVideoCrossLine: CrossLineAnimation(groupCallMemberColoredCrossLine) {
fg: groupCallVideoTextFg;
icon: icon {{ "calls/video_over_mute", groupCallVideoTextFg }};
}
GroupCallVideoTile {
shadowHeight: pixels;
namePosition: point;
pin: CrossLineAnimation;
pinPosition: point;
pinPadding: margins;
pinTextPosition: point;
back: icon;
iconPosition: point;
}
groupCallVideoTile: GroupCallVideoTile {
shadowHeight: 40px;
namePosition: point(15px, 8px);
pin: CrossLineAnimation {
fg: groupCallVideoTextFg;
icon: icon {{ "calls/video_over_pin", groupCallVideoTextFg }};
startPosition: point(7px, 4px);
endPosition: point(17px, 14px);
stroke: 3px;
strokeDenominator: 2;
}
pinPosition: point(18px, 18px);
pinPadding: margins(6px, 2px, 12px, 1px);
pinTextPosition: point(1px, 3px);
back: icon {{ "calls/video_back", groupCallVideoTextFg }};
iconPosition: point(10px, 5px);
}
groupCallVideoSmallSkip: 4px;
groupCallVideoLargeSkip: 6px;
groupCallVideoPlaceholderHeight: 212px;
groupCallVideoPlaceholderIconTop: 50px;
groupCallVideoPlaceholderTextTop: 120px;
groupCallTooltip: Tooltip(defaultTooltip) {
textBg: groupCallMembersBg;
textFg: groupCallMembersFg;
textBorder: groupCallMembersBgOver;
}
groupCallNiceTooltip: ImportantTooltip(defaultImportantTooltip) {
bg: importantTooltipBg;
padding: margins(10px, 3px, 10px, 5px);
radius: 4px;
arrow: 4px;
}
groupCallNiceTooltipLabel: FlatLabel(defaultImportantTooltipLabel) {
style: TextStyle(defaultTextStyle) {
font: font(11px);
linkFont: font(11px);
linkFontOver: font(11px underline);
}
}
groupCallStickedTooltip: ImportantTooltip(groupCallNiceTooltip) {
padding: margins(10px, 1px, 6px, 3px);
}
groupCallStickedTooltipClose: IconButton(defaultIconButton) {
width: 20px;
height: 20px;
iconPosition: point(4px, 3px);
icon: icon {{ "calls/video_tooltip", importantTooltipFg }};
iconOver: icon {{ "calls/video_tooltip", importantTooltipFg }};
ripple: emptyRippleAnimation;
}
groupCallNiceTooltipTop: 4px;
groupCallPaused: icon {{ "calls/video_large_paused", groupCallVideoTextFg }};

View File

@@ -357,7 +357,7 @@ base::unique_qptr<Ui::PopupMenu> BoxController::rowContextMenu(
auto result = base::make_unique_q<Ui::PopupMenu>(parent);
result->addAction(tr::lng_context_delete_selected(tr::now), [=] {
Ui::show(
_window->show(
Box<DeleteMessagesBox>(session, base::duplicate(ids)),
Ui::LayerOption::KeepOther);
});

View File

@@ -28,7 +28,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "webrtc/webrtc_create_adm.h"
#include "data/data_user.h"
#include "data/data_session.h"
#include "facades.h"
#include <tgcalls/Instance.h>
#include <tgcalls/VideoCaptureInterface.h>
@@ -161,8 +160,12 @@ Call::Call(
, _user(user)
, _api(&_user->session().mtp())
, _type(type)
, _videoIncoming(std::make_unique<Webrtc::VideoTrack>(StartVideoState(video)))
, _videoOutgoing(std::make_unique<Webrtc::VideoTrack>(StartVideoState(video))) {
, _videoIncoming(
std::make_unique<Webrtc::VideoTrack>(
StartVideoState(video)))
, _videoOutgoing(
std::make_unique<Webrtc::VideoTrack>(
StartVideoState(video))) {
_discardByTimeoutTimer.setCallback([=] { hangup(); });
if (_type == Type::Outgoing) {
@@ -380,7 +383,7 @@ void Call::setupOutgoingVideo() {
// Paused not supported right now.
Assert(state == Webrtc::VideoState::Active);
if (!_videoCapture) {
_videoCapture = _delegate->getVideoCapture();
_videoCapture = _delegate->callGetVideoCapture();
_videoCapture->setOutput(_videoOutgoing->sink());
}
if (_instance) {
@@ -801,16 +804,19 @@ void Call::createAndStartController(const MTPDphoneCall &call) {
AppendServer(descriptor.rtcServers, connection);
}
if (Global::UseProxyForCalls()
&& (Global::ProxySettings() == MTP::ProxyData::Settings::Enabled)) {
const auto &selected = Global::SelectedProxy();
if (selected.supportsCalls() && !selected.host.isEmpty()) {
Assert(selected.type == MTP::ProxyData::Type::Socks5);
descriptor.proxy = std::make_unique<tgcalls::Proxy>();
descriptor.proxy->host = selected.host.toStdString();
descriptor.proxy->port = selected.port;
descriptor.proxy->login = selected.user.toStdString();
descriptor.proxy->password = selected.password.toStdString();
{
auto &settingsProxy = Core::App().settings().proxy();
using ProxyData = MTP::ProxyData;
if (settingsProxy.useProxyForCalls() && settingsProxy.isEnabled()) {
const auto &selected = settingsProxy.selected();
if (selected.supportsCalls() && !selected.host.isEmpty()) {
Assert(selected.type == ProxyData::Type::Socks5);
descriptor.proxy = std::make_unique<tgcalls::Proxy>();
descriptor.proxy->host = selected.host.toStdString();
descriptor.proxy->port = selected.port;
descriptor.proxy->login = selected.user.toStdString();
descriptor.proxy->password = selected.password.toStdString();
}
}
}

View File

@@ -53,6 +53,11 @@ struct Error {
QString details;
};
enum class CallType {
Incoming,
Outgoing,
};
class Call : public base::has_weak_ptr {
public:
class Delegate {
@@ -72,7 +77,7 @@ public:
Fn<void()> onSuccess,
bool video) = 0;
virtual auto getVideoCapture()
virtual auto callGetVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> = 0;
virtual ~Delegate() = default;
@@ -81,11 +86,12 @@ public:
static constexpr auto kSoundSampleMs = 100;
enum class Type {
Incoming,
Outgoing,
};
Call(not_null<Delegate*> delegate, not_null<UserData*> user, Type type, bool video);
using Type = CallType;
Call(
not_null<Delegate*> delegate,
not_null<UserData*> user,
Type type,
bool video);
[[nodiscard]] Type type() const {
return _type;

File diff suppressed because it is too large Load Diff

View File

@@ -1,363 +0,0 @@
/*
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
*/
#pragma once
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "base/bytes.h"
#include "mtproto/sender.h"
#include "mtproto/mtproto_auth_key.h"
class History;
namespace tgcalls {
class GroupInstanceCustomImpl;
struct GroupLevelsUpdate;
struct GroupNetworkState;
struct GroupParticipantDescription;
} // namespace tgcalls
namespace base {
class GlobalShortcutManager;
class GlobalShortcutValue;
} // namespace base
namespace Webrtc {
class MediaDevices;
} // namespace Webrtc
namespace Data {
struct LastSpokeTimes;
struct GroupCallParticipant;
class GroupCall;
} // namespace Data
namespace Calls {
namespace Group {
struct MuteRequest;
struct VolumeRequest;
struct ParticipantState;
struct JoinInfo;
struct RejoinEvent;
} // namespace Group
enum class MuteState {
Active,
PushToTalk,
Muted,
ForceMuted,
RaisedHand,
};
[[nodiscard]] inline auto MapPushToTalkToActive() {
return rpl::map([=](MuteState state) {
return (state == MuteState::PushToTalk) ? MuteState::Active : state;
});
}
[[nodiscard]] bool IsGroupCallAdmin(
not_null<PeerData*> peer,
not_null<PeerData*> participantPeer);
struct LevelUpdate {
uint32 ssrc = 0;
float value = 0.;
bool voice = false;
bool me = false;
};
class GroupCall final : public base::has_weak_ptr {
public:
class Delegate {
public:
virtual ~Delegate() = default;
virtual void groupCallFinished(not_null<GroupCall*> call) = 0;
virtual void groupCallFailed(not_null<GroupCall*> call) = 0;
virtual void groupCallRequestPermissionsOrFail(
Fn<void()> onSuccess) = 0;
enum class GroupCallSound {
Started,
Connecting,
AllowedToSpeak,
Ended,
};
virtual void groupCallPlaySound(GroupCallSound sound) = 0;
};
using GlobalShortcutManager = base::GlobalShortcutManager;
GroupCall(
not_null<Delegate*> delegate,
Group::JoinInfo info,
const MTPInputGroupCall &inputCall);
~GroupCall();
[[nodiscard]] uint64 id() const {
return _id;
}
[[nodiscard]] not_null<PeerData*> peer() const {
return _peer;
}
[[nodiscard]] not_null<PeerData*> joinAs() const {
return _joinAs;
}
[[nodiscard]] bool showChooseJoinAs() const;
[[nodiscard]] TimeId scheduleDate() const {
return _scheduleDate;
}
[[nodiscard]] bool scheduleStartSubscribed() const;
[[nodiscard]] Data::GroupCall *lookupReal() const;
[[nodiscard]] rpl::producer<not_null<Data::GroupCall*>> real() const;
void start(TimeId scheduleDate);
void hangup();
void discard();
void rejoinAs(Group::JoinInfo info);
void rejoinWithHash(const QString &hash);
void join(const MTPInputGroupCall &inputCall);
void handleUpdate(const MTPUpdate &update);
void handlePossibleCreateOrJoinResponse(const MTPDupdateGroupCall &data);
void changeTitle(const QString &title);
void toggleRecording(bool enabled, const QString &title);
[[nodiscard]] bool recordingStoppedByMe() const {
return _recordingStoppedByMe;
}
void startScheduledNow();
void toggleScheduleStartSubscribed(bool subscribed);
void setMuted(MuteState mute);
void setMutedAndUpdate(MuteState mute);
[[nodiscard]] MuteState muted() const {
return _muted.current();
}
[[nodiscard]] rpl::producer<MuteState> mutedValue() const {
return _muted.value();
}
[[nodiscard]] auto otherParticipantStateValue() const
-> rpl::producer<Group::ParticipantState>;
enum State {
Creating,
Waiting,
Joining,
Connecting,
Joined,
FailedHangingUp,
Failed,
HangingUp,
Ended,
};
[[nodiscard]] State state() const {
return _state.current();
}
[[nodiscard]] rpl::producer<State> stateValue() const {
return _state.value();
}
enum class InstanceState {
Disconnected,
TransitionToRtc,
Connected,
};
[[nodiscard]] InstanceState instanceState() const {
return _instanceState.current();
}
[[nodiscard]] rpl::producer<InstanceState> instanceStateValue() const {
return _instanceState.value();
}
[[nodiscard]] rpl::producer<LevelUpdate> levelUpdates() const {
return _levelUpdates.events();
}
[[nodiscard]] rpl::producer<Group::RejoinEvent> rejoinEvents() const {
return _rejoinEvents.events();
}
[[nodiscard]] rpl::producer<> allowedToSpeakNotifications() const {
return _allowedToSpeakNotifications.events();
}
[[nodiscard]] rpl::producer<> titleChanged() const {
return _titleChanged.events();
}
static constexpr auto kSpeakLevelThreshold = 0.2;
void setCurrentAudioDevice(bool input, const QString &deviceId);
//void setAudioVolume(bool input, float level);
void setAudioDuckingEnabled(bool enabled);
void toggleMute(const Group::MuteRequest &data);
void changeVolume(const Group::VolumeRequest &data);
std::variant<int, not_null<UserData*>> inviteUsers(
const std::vector<not_null<UserData*>> &users);
std::shared_ptr<GlobalShortcutManager> ensureGlobalShortcutManager();
void applyGlobalShortcutChanges();
void pushToTalk(bool pressed, crl::time delay);
[[nodiscard]] rpl::lifetime &lifetime() {
return _lifetime;
}
private:
class LoadPartTask;
public:
void broadcastPartStart(std::shared_ptr<LoadPartTask> task);
void broadcastPartCancel(not_null<LoadPartTask*> task);
private:
using GlobalShortcutValue = base::GlobalShortcutValue;
struct LoadingPart {
std::shared_ptr<LoadPartTask> task;
mtpRequestId requestId = 0;
};
enum class FinishType {
None,
Ended,
Failed,
};
enum class InstanceMode {
None,
Rtc,
Stream,
};
enum class SendUpdateType {
Mute,
RaiseHand,
};
void handlePossibleCreateOrJoinResponse(const MTPDgroupCall &data);
void handlePossibleDiscarded(const MTPDgroupCallDiscarded &data);
void handleUpdate(const MTPDupdateGroupCall &data);
void handleUpdate(const MTPDupdateGroupCallParticipants &data);
void handleRequestError(const MTP::Error &error);
void handleControllerError(const QString &error);
void ensureControllerCreated();
void destroyController();
void setState(State state);
void finish(FinishType type);
void maybeSendMutedUpdate(MuteState previous);
void sendSelfUpdate(SendUpdateType type);
void updateInstanceMuteState();
void updateInstanceVolumes();
void applyMeInCallLocally();
void rejoin();
void rejoin(not_null<PeerData*> as);
void setJoinAs(not_null<PeerData*> as);
void saveDefaultJoinAs(not_null<PeerData*> as);
void subscribeToReal(not_null<Data::GroupCall*> real);
void setScheduledDate(TimeId date);
void audioLevelsUpdated(const tgcalls::GroupLevelsUpdate &data);
void setInstanceConnected(tgcalls::GroupNetworkState networkState);
void setInstanceMode(InstanceMode mode);
void checkLastSpoke();
void pushToTalkCancel();
void checkGlobalShortcutAvailability();
void checkJoined();
void checkFirstTimeJoined();
void notifyAboutAllowedToSpeak();
void playConnectingSound();
void stopConnectingSound();
void playConnectingSoundOnce();
void requestParticipantsInformation(const std::vector<uint32_t> &ssrcs);
void addParticipantsToInstance();
void prepareParticipantForAdding(
const Data::GroupCallParticipant &participant);
void addPreparedParticipants();
void addPreparedParticipantsDelayed();
void editParticipant(
not_null<PeerData*> participantPeer,
bool mute,
std::optional<int> volume);
void applyParticipantLocally(
not_null<PeerData*> participantPeer,
bool mute,
std::optional<int> volume);
void applyQueuedSelfUpdates();
void applySelfUpdate(const MTPDgroupCallParticipant &data);
void applyOtherParticipantUpdate(const MTPDgroupCallParticipant &data);
[[nodiscard]] MTPInputGroupCall inputCall() const;
const not_null<Delegate*> _delegate;
not_null<PeerData*> _peer; // Can change in legacy group migration.
rpl::event_stream<PeerData*> _peerStream;
not_null<History*> _history; // Can change in legacy group migration.
MTP::Sender _api;
rpl::event_stream<not_null<Data::GroupCall*>> _realChanges;
rpl::variable<State> _state = State::Creating;
rpl::variable<InstanceState> _instanceState
= InstanceState::Disconnected;
bool _instanceTransitioning = false;
InstanceMode _instanceMode = InstanceMode::None;
base::flat_set<uint32> _unresolvedSsrcs;
std::vector<tgcalls::GroupParticipantDescription> _preparedParticipants;
bool _addPreparedParticipantsScheduled = false;
bool _recordingStoppedByMe = false;
MTP::DcId _broadcastDcId = 0;
base::flat_map<not_null<LoadPartTask*>, LoadingPart> _broadcastParts;
not_null<PeerData*> _joinAs;
std::vector<not_null<PeerData*>> _possibleJoinAs;
QString _joinHash;
rpl::variable<MuteState> _muted = MuteState::Muted;
bool _initialMuteStateSent = false;
bool _acceptFields = false;
rpl::event_stream<Group::ParticipantState> _otherParticipantStateValue;
std::vector<MTPGroupCallParticipant> _queuedSelfUpdates;
uint64 _id = 0;
uint64 _accessHash = 0;
uint32 _mySsrc = 0;
TimeId _scheduleDate = 0;
base::flat_set<uint32> _mySsrcs;
mtpRequestId _createRequestId = 0;
mtpRequestId _updateMuteRequestId = 0;
std::unique_ptr<tgcalls::GroupInstanceCustomImpl> _instance;
rpl::event_stream<LevelUpdate> _levelUpdates;
base::flat_map<uint32, Data::LastSpokeTimes> _lastSpoke;
rpl::event_stream<Group::RejoinEvent> _rejoinEvents;
rpl::event_stream<> _allowedToSpeakNotifications;
rpl::event_stream<> _titleChanged;
base::Timer _lastSpokeCheckTimer;
base::Timer _checkJoinedTimer;
crl::time _lastSendProgressUpdate = 0;
std::shared_ptr<GlobalShortcutManager> _shortcutManager;
std::shared_ptr<GlobalShortcutValue> _pushToTalk;
base::Timer _pushToTalkCancelTimer;
base::Timer _connectingSoundTimer;
bool _hadJoinedState = false;
std::unique_ptr<Webrtc::MediaDevices> _mediaDevices;
QString _audioInputId;
QString _audioOutputId;
rpl::lifetime _lifetime;
};
} // namespace Calls

File diff suppressed because it is too large Load Diff

View File

@@ -1,146 +0,0 @@
/*
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
*/
#pragma once
#include "base/weak_ptr.h"
#include "base/timer.h"
#include "base/object_ptr.h"
#include "calls/calls_group_call.h"
#include "calls/calls_choose_join_as.h"
#include "ui/effects/animations.h"
#include "ui/rp_widget.h"
class Image;
namespace Data {
class PhotoMedia;
class CloudImageView;
class GroupCall;
} // namespace Data
namespace Ui {
class AbstractButton;
class DropdownMenu;
class CallButton;
class CallMuteButton;
class IconButton;
class FlatLabel;
template <typename Widget>
class FadeWrap;
template <typename Widget>
class PaddingWrap;
class Window;
class ScrollArea;
class GenericBox;
class LayerManager;
class GroupCallScheduledLeft;
namespace Platform {
class TitleControls;
} // namespace Platform
} // namespace Ui
namespace style {
struct CallSignalBars;
struct CallBodyLayout;
} // namespace style
namespace Calls::Group {
class Members;
class Panel final {
public:
Panel(not_null<GroupCall*> call);
~Panel();
[[nodiscard]] bool isActive() const;
void minimize();
void close();
void showAndActivate();
void closeBeforeDestroy();
private:
using State = GroupCall::State;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
void paint(QRect clip);
void initWindow();
void initWidget();
void initControls();
void initShareAction();
void initLayout();
void initGeometry();
void setupScheduledLabels(rpl::producer<TimeId> date);
void setupMembers();
void setupJoinAsChangedToasts();
void setupTitleChangedToasts();
void setupAllowedToSpeakToasts();
void setupRealMuteButtonState(not_null<Data::GroupCall*> real);
bool handleClose();
void startScheduledNow();
void updateControlsGeometry();
void updateMembersGeometry();
void showControls();
void refreshLeftButton();
void endCall();
void showMainMenu();
void chooseJoinAs();
void addMembers();
void kickParticipant(not_null<PeerData*> participantPeer);
void kickParticipantSure(not_null<PeerData*> participantPeer);
[[nodiscard]] QRect computeTitleRect() const;
void refreshTitle();
void refreshTitleGeometry();
void setupRealCallViewers();
void subscribeToChanges(not_null<Data::GroupCall*> real);
void migrate(not_null<ChannelData*> channel);
void subscribeToPeerChanges();
const not_null<GroupCall*> _call;
not_null<PeerData*> _peer;
const std::unique_ptr<Ui::Window> _window;
const std::unique_ptr<Ui::LayerManager> _layerBg;
#ifndef Q_OS_MAC
std::unique_ptr<Ui::Platform::TitleControls> _controls;
#endif // !Q_OS_MAC
rpl::lifetime _callLifetime;
object_ptr<Ui::FlatLabel> _title = { nullptr };
object_ptr<Ui::FlatLabel> _subtitle = { nullptr };
object_ptr<Ui::AbstractButton> _recordingMark = { nullptr };
object_ptr<Ui::IconButton> _menuToggle = { nullptr };
object_ptr<Ui::DropdownMenu> _menu = { nullptr };
object_ptr<Ui::AbstractButton> _joinAsToggle = { nullptr };
object_ptr<Members> _members = { nullptr };
object_ptr<Ui::FlatLabel> _startsIn = { nullptr };
object_ptr<Ui::RpWidget> _countdown = { nullptr };
std::shared_ptr<Ui::GroupCallScheduledLeft> _countdownData;
object_ptr<Ui::FlatLabel> _startsWhen = { nullptr };
ChooseJoinAsProcess _joinAsProcess;
object_ptr<Ui::CallButton> _settings = { nullptr };
object_ptr<Ui::CallButton> _share = { nullptr };
std::unique_ptr<Ui::CallMuteButton> _mute;
object_ptr<Ui::CallButton> _hangup;
Fn<void()> _shareLinkCallback;
rpl::lifetime _peerLifetime;
};
} // namespace Calls::Group

View File

@@ -7,7 +7,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "calls/calls_instance.h"
#include "calls/calls_group_common.h"
#include "calls/calls_call.h"
#include "calls/group/calls_group_common.h"
#include "calls/group/calls_choose_join_as.h"
#include "calls/group/calls_group_call.h"
#include "mtproto/mtproto_dh_utils.h"
#include "core/application.h"
#include "main/main_session.h"
@@ -15,10 +18,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "apiwrap.h"
#include "lang/lang_keys.h"
#include "boxes/confirm_box.h"
#include "calls/group/calls_group_call.h"
#include "calls/group/calls_group_panel.h"
#include "calls/calls_call.h"
#include "calls/calls_group_call.h"
#include "calls/calls_panel.h"
#include "calls/calls_group_panel.h"
#include "data/data_user.h"
#include "data/data_group_call.h"
#include "data/data_channel.h"
@@ -41,11 +44,142 @@ namespace {
constexpr auto kServerConfigUpdateTimeoutMs = 24 * 3600 * crl::time(1000);
using CallSound = Call::Delegate::CallSound;
using GroupCallSound = GroupCall::Delegate::GroupCallSound;
} // namespace
Instance::Instance() = default;
class Instance::Delegate final
: public Call::Delegate
, public GroupCall::Delegate {
public:
explicit Delegate(not_null<Instance*> instance);
Instance::~Instance() = default;
DhConfig getDhConfig() const override;
void callFinished(not_null<Call*> call) override;
void callFailed(not_null<Call*> call) override;
void callRedial(not_null<Call*> call) override;
void callRequestPermissionsOrFail(
Fn<void()> onSuccess,
bool video) override;
void callPlaySound(CallSound sound) override;
auto callGetVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
void groupCallFinished(not_null<GroupCall*> call) override;
void groupCallFailed(not_null<GroupCall*> call) override;
void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override;
void groupCallPlaySound(GroupCallSound sound) override;
auto groupCallGetVideoCapture(const QString &deviceId)
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
FnMut<void()> groupCallAddAsyncWaiter() override;
private:
const not_null<Instance*> _instance;
};
Instance::Delegate::Delegate(not_null<Instance*> instance)
: _instance(instance) {
}
DhConfig Instance::Delegate::getDhConfig() const {
return *_instance->_cachedDhConfig;
}
void Instance::Delegate::callFinished(not_null<Call*> call) {
crl::on_main(call, [=] {
_instance->destroyCall(call);
});
}
void Instance::Delegate::callFailed(not_null<Call*> call) {
crl::on_main(call, [=] {
_instance->destroyCall(call);
});
}
void Instance::Delegate::callRedial(not_null<Call*> call) {
if (_instance->_currentCall.get() == call) {
_instance->refreshDhConfig();
}
}
void Instance::Delegate::callRequestPermissionsOrFail(
Fn<void()> onSuccess,
bool video) {
_instance->requestPermissionsOrFail(std::move(onSuccess), video);
}
void Instance::Delegate::callPlaySound(CallSound sound) {
_instance->playSoundOnce([&] {
switch (sound) {
case CallSound::Busy: return "call_busy";
case CallSound::Ended: return "call_end";
case CallSound::Connecting: return "call_connect";
}
Unexpected("CallSound in Instance::callPlaySound.");
}());
}
auto Instance::Delegate::callGetVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> {
return _instance->getVideoCapture();
}
void Instance::Delegate::groupCallFinished(not_null<GroupCall*> call) {
crl::on_main(call, [=] {
_instance->destroyGroupCall(call);
});
}
void Instance::Delegate::groupCallFailed(not_null<GroupCall*> call) {
crl::on_main(call, [=] {
_instance->destroyGroupCall(call);
});
}
void Instance::Delegate::groupCallRequestPermissionsOrFail(
Fn<void()> onSuccess) {
_instance->requestPermissionsOrFail(std::move(onSuccess), false);
}
void Instance::Delegate::groupCallPlaySound(GroupCallSound sound) {
_instance->playSoundOnce([&] {
switch (sound) {
case GroupCallSound::Started: return "group_call_start";
case GroupCallSound::Ended: return "group_call_end";
case GroupCallSound::AllowedToSpeak: return "group_call_allowed";
case GroupCallSound::Connecting: return "group_call_connect";
}
Unexpected("GroupCallSound in Instance::groupCallPlaySound.");
}());
}
auto Instance::Delegate::groupCallGetVideoCapture(const QString &deviceId)
-> std::shared_ptr<tgcalls::VideoCaptureInterface> {
return _instance->getVideoCapture(deviceId);
}
FnMut<void()> Instance::Delegate::groupCallAddAsyncWaiter() {
return _instance->addAsyncWaiter();
}
Instance::Instance()
: _delegate(std::make_unique<Delegate>(this))
, _cachedDhConfig(std::make_unique<DhConfig>())
, _chooseJoinAs(std::make_unique<Group::ChooseJoinAsProcess>()) {
}
Instance::~Instance() {
destroyCurrentCall();
while (!_asyncWaiters.empty()) {
_asyncWaiters.front()->acquire();
_asyncWaiters.erase(_asyncWaiters.begin());
}
}
void Instance::startOutgoingCall(not_null<UserData*> user, bool video) {
if (activateCurrentCall()) {
@@ -72,7 +206,7 @@ void Instance::startOrJoinGroupCall(
: peer->groupCall()
? Group::ChooseJoinAsProcess::Context::Join
: Group::ChooseJoinAsProcess::Context::Create;
_chooseJoinAs.start(peer, context, [=](object_ptr<Ui::BoxContent> box) {
_chooseJoinAs->start(peer, context, [=](object_ptr<Ui::BoxContent> box) {
Ui::show(std::move(box), Ui::LayerOption::KeepOther);
}, [=](QString text) {
Ui::Toast::Show(text);
@@ -85,36 +219,6 @@ void Instance::startOrJoinGroupCall(
});
}
void Instance::callFinished(not_null<Call*> call) {
crl::on_main(call, [=] {
destroyCall(call);
});
}
void Instance::callFailed(not_null<Call*> call) {
crl::on_main(call, [=] {
destroyCall(call);
});
}
void Instance::callRedial(not_null<Call*> call) {
if (_currentCall.get() == call) {
refreshDhConfig();
}
}
void Instance::groupCallFinished(not_null<GroupCall*> call) {
crl::on_main(call, [=] {
destroyGroupCall(call);
});
}
void Instance::groupCallFailed(not_null<GroupCall*> call) {
crl::on_main(call, [=] {
destroyGroupCall(call);
});
}
not_null<Media::Audio::Track*> Instance::ensureSoundLoaded(
const QString &key) {
const auto i = _tracks.find(key);
@@ -132,31 +236,6 @@ void Instance::playSoundOnce(const QString &key) {
ensureSoundLoaded(key)->playOnce();
}
void Instance::callPlaySound(CallSound sound) {
playSoundOnce([&] {
switch (sound) {
case CallSound::Busy: return "call_busy";
case CallSound::Ended: return "call_end";
case CallSound::Connecting: return "call_connect";
}
Unexpected("CallSound in Instance::callPlaySound.");
return "";
}());
}
void Instance::groupCallPlaySound(GroupCallSound sound) {
playSoundOnce([&] {
switch (sound) {
case GroupCallSound::Started: return "group_call_start";
case GroupCallSound::Ended: return "group_call_end";
case GroupCallSound::AllowedToSpeak: return "group_call_allowed";
case GroupCallSound::Connecting: return "group_call_connect";
}
Unexpected("GroupCallSound in Instance::groupCallPlaySound.");
return "";
}());
}
void Instance::destroyCall(not_null<Call*> call) {
if (_currentCall.get() == call) {
_currentCallPanel->closeBeforeDestroy();
@@ -174,7 +253,7 @@ void Instance::destroyCall(not_null<Call*> call) {
}
void Instance::createCall(not_null<UserData*> user, Call::Type type, bool video) {
auto call = std::make_unique<Call>(getCallDelegate(), user, type, video);
auto call = std::make_unique<Call>(_delegate.get(), user, type, video);
const auto raw = call.get();
user->session().account().sessionChanges(
@@ -217,7 +296,7 @@ void Instance::createGroupCall(
destroyCurrentCall();
auto call = std::make_unique<GroupCall>(
getGroupCallDelegate(),
_delegate.get(),
std::move(info),
inputCall);
const auto raw = call.get();
@@ -237,7 +316,7 @@ void Instance::refreshDhConfig() {
const auto weak = base::make_weak(_currentCall);
_currentCall->user()->session().api().request(MTPmessages_GetDhConfig(
MTP_int(_dhConfig.version),
MTP_int(_cachedDhConfig->version),
MTP_int(MTP::ModExpFirst::kRandomPowerSize)
)).done([=](const MTPmessages_DhConfig &result) {
const auto call = weak.get();
@@ -249,14 +328,14 @@ void Instance::refreshDhConfig() {
Assert(random.size() == MTP::ModExpFirst::kRandomPowerSize);
call->start(random);
} else {
callFailed(call);
_delegate->callFailed(call);
}
}).fail([=](const MTP::Error &error) {
const auto call = weak.get();
if (!call) {
return;
}
callFailed(call);
_delegate->callFailed(call);
}).send();
}
@@ -277,13 +356,13 @@ bytes::const_span Instance::updateDhConfig(
} else if (!validRandom(data.vrandom().v)) {
return {};
}
_dhConfig.g = data.vg().v;
_dhConfig.p = std::move(primeBytes);
_dhConfig.version = data.vversion().v;
_cachedDhConfig->g = data.vg().v;
_cachedDhConfig->p = std::move(primeBytes);
_cachedDhConfig->version = data.vversion().v;
return bytes::make_span(data.vrandom().v);
}, [&](const MTPDmessages_dhConfigNotModified &data)
-> bytes::const_span {
if (!_dhConfig.g || _dhConfig.p.empty()) {
if (!_cachedDhConfig->g || _cachedDhConfig->p.empty()) {
LOG(("API Error: dhConfigNotModified on zero version."));
return {};
} else if (!validRandom(data.vrandom().v)) {
@@ -324,6 +403,8 @@ void Instance::handleUpdate(
handleSignalingData(session, data);
}, [&](const MTPDupdateGroupCall &data) {
handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateGroupCallConnection &data) {
handleGroupCallUpdate(session, update);
}, [&](const MTPDupdateGroupCallParticipants &data) {
handleGroupCallUpdate(session, update);
}, [](const auto &) {
@@ -357,6 +438,26 @@ void Instance::setCurrentAudioDevice(bool input, const QString &deviceId) {
}
}
FnMut<void()> Instance::addAsyncWaiter() {
auto semaphore = std::make_unique<crl::semaphore>();
const auto raw = semaphore.get();
const auto weak = base::make_weak(this);
_asyncWaiters.emplace(std::move(semaphore));
return [raw, weak] {
raw->release();
crl::on_main(weak, [raw, weak] {
auto &waiters = weak->_asyncWaiters;
auto wrapped = std::unique_ptr<crl::semaphore>(raw);
const auto i = waiters.find(wrapped);
wrapped.release();
if (i != end(waiters)) {
waiters.erase(i);
}
});
};
}
bool Instance::isQuitPrevent() {
if (!_currentCall || _currentCall->isIncomingWaiting()) {
return false;
@@ -415,10 +516,15 @@ void Instance::handleGroupCallUpdate(
&& (&_currentGroupCall->peer()->session() == session)) {
update.match([&](const MTPDupdateGroupCall &data) {
_currentGroupCall->handlePossibleCreateOrJoinResponse(data);
}, [&](const MTPDupdateGroupCallConnection &data) {
_currentGroupCall->handlePossibleCreateOrJoinResponse(data);
}, [](const auto &) {
});
}
if (update.type() == mtpc_updateGroupCallConnection) {
return;
}
const auto callId = update.match([](const MTPDupdateGroupCall &data) {
return data.vcall().match([](const auto &data) {
return data.vid().v;
@@ -592,14 +698,19 @@ void Instance::requestPermissionOrFail(Platform::PermissionType type, Fn<void()>
}
}
std::shared_ptr<tgcalls::VideoCaptureInterface> Instance::getVideoCapture() {
std::shared_ptr<tgcalls::VideoCaptureInterface> Instance::getVideoCapture(
QString deviceId) {
if (deviceId.isEmpty()) {
deviceId = Core::App().settings().callVideoInputDeviceId();
}
if (auto result = _videoCapture.lock()) {
result->switchToDevice(deviceId.toStdString());
return result;
}
auto result = std::shared_ptr<tgcalls::VideoCaptureInterface>(
tgcalls::VideoCaptureInterface::Create(
tgcalls::StaticThreads::getThreads(),
Core::App().settings().callVideoInputDeviceId().toStdString()));
deviceId.toStdString()));
_videoCapture = result;
return result;
}

View File

@@ -8,9 +8,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "mtproto/sender.h"
#include "calls/calls_call.h"
#include "calls/calls_group_call.h"
#include "calls/calls_choose_join_as.h"
namespace crl {
class semaphore;
} // namespace crl
namespace Platform {
enum class PermissionType;
@@ -27,17 +28,22 @@ class Session;
namespace Calls::Group {
struct JoinInfo;
class Panel;
class ChooseJoinAsProcess;
} // namespace Calls::Group
namespace tgcalls {
class VideoCaptureInterface;
} // namespace tgcalls
namespace Calls {
class Call;
enum class CallType;
class GroupCall;
class Panel;
struct DhConfig;
class Instance
: private Call::Delegate
, private GroupCall::Delegate
, private base::Subscriber
, public base::has_weak_ptr {
class Instance : private base::Subscriber, public base::has_weak_ptr {
public:
Instance();
~Instance();
@@ -69,49 +75,24 @@ public:
bool activateCurrentCall(const QString &joinHash = QString());
bool minimizeCurrentActiveCall();
bool closeCurrentActiveCall();
auto getVideoCapture()
-> std::shared_ptr<tgcalls::VideoCaptureInterface> override;
[[nodiscard]] auto getVideoCapture(QString deviceId = QString())
-> std::shared_ptr<tgcalls::VideoCaptureInterface>;
void requestPermissionsOrFail(Fn<void()> onSuccess, bool video = true);
void setCurrentAudioDevice(bool input, const QString &deviceId);
[[nodiscard]] FnMut<void()> addAsyncWaiter();
[[nodiscard]] bool isQuitPrevent();
private:
using CallSound = Call::Delegate::CallSound;
using GroupCallSound = GroupCall::Delegate::GroupCallSound;
[[nodiscard]] not_null<Call::Delegate*> getCallDelegate() {
return static_cast<Call::Delegate*>(this);
}
[[nodiscard]] not_null<GroupCall::Delegate*> getGroupCallDelegate() {
return static_cast<GroupCall::Delegate*>(this);
}
[[nodiscard]] DhConfig getDhConfig() const override {
return _dhConfig;
}
class Delegate;
friend class Delegate;
not_null<Media::Audio::Track*> ensureSoundLoaded(const QString &key);
void playSoundOnce(const QString &key);
void callFinished(not_null<Call*> call) override;
void callFailed(not_null<Call*> call) override;
void callRedial(not_null<Call*> call) override;
void callRequestPermissionsOrFail(
Fn<void()> onSuccess,
bool video) override {
requestPermissionsOrFail(std::move(onSuccess), video);
}
void callPlaySound(CallSound sound) override;
void groupCallFinished(not_null<GroupCall*> call) override;
void groupCallFailed(not_null<GroupCall*> call) override;
void groupCallRequestPermissionsOrFail(Fn<void()> onSuccess) override {
requestPermissionsOrFail(std::move(onSuccess), false);
}
void groupCallPlaySound(GroupCallSound sound) override;
void createCall(not_null<UserData*> user, Call::Type type, bool video);
void createCall(not_null<UserData*> user, CallType type, bool video);
void destroyCall(not_null<Call*> call);
void createGroupCall(
@@ -138,7 +119,8 @@ private:
not_null<Main::Session*> session,
const MTPUpdate &update);
DhConfig _dhConfig;
const std::unique_ptr<Delegate> _delegate;
const std::unique_ptr<DhConfig> _cachedDhConfig;
crl::time _lastServerConfigUpdateTime = 0;
base::weak_ptr<Main::Session> _serverConfigRequestSession;
@@ -154,7 +136,9 @@ private:
base::flat_map<QString, std::unique_ptr<Media::Audio::Track>> _tracks;
Group::ChooseJoinAsProcess _chooseJoinAs;
const std::unique_ptr<Group::ChooseJoinAsProcess> _chooseJoinAs;
base::flat_set<std::unique_ptr<crl::semaphore>> _asyncWaiters;
};

View File

@@ -18,6 +18,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_signal_bars.h"
#include "calls/calls_userpic.h"
#include "calls/calls_video_bubble.h"
#include "calls/calls_video_incoming.h"
#include "ui/platform/ui_platform_window_title.h"
#include "ui/widgets/call_button.h"
#include "ui/widgets/buttons.h"
@@ -29,6 +30,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/wrap/fade_wrap.h"
#include "ui/wrap/padding_wrap.h"
#include "ui/platform/ui_platform_utility.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_shader.h"
#include "ui/toast/toast.h"
#include "ui/empty_userpic.h"
#include "ui/emoji_config.h"
@@ -39,7 +42,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "platform/platform_specific.h"
#include "base/platform/base_platform_info.h"
#include "window/main_window.h"
#include "media/view/media_view_pip.h" // Utilities for frame rotation.
#include "app.h"
#include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h"
@@ -48,146 +50,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include <QtWidgets/QDesktopWidget>
#include <QtWidgets/QApplication>
#include <QtGui/QWindow>
#include <QtCore/QTimer>
namespace Calls {
namespace {
#if defined Q_OS_MAC && !defined OS_MAC_OLD
#define USE_OPENGL_OVERLAY_WIDGET
#endif // Q_OS_MAC && !OS_MAC_OLD
#ifdef USE_OPENGL_OVERLAY_WIDGET
using IncomingParent = Ui::RpWidgetWrap<QOpenGLWidget>;
#else // USE_OPENGL_OVERLAY_WIDGET
using IncomingParent = Ui::RpWidget;
#endif // USE_OPENGL_OVERLAY_WIDGET
} // namespace
class Panel::Incoming final : public IncomingParent {
public:
Incoming(
not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track);
private:
void paintEvent(QPaintEvent *e) override;
void initBottomShadow();
void fillTopShadow(QPainter &p);
void fillBottomShadow(QPainter &p);
const not_null<Webrtc::VideoTrack*> _track;
QPixmap _bottomShadow;
};
Panel::Incoming::Incoming(
not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track)
: IncomingParent(parent)
, _track(track) {
initBottomShadow();
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_TransparentForMouseEvents);
}
void Panel::Incoming::paintEvent(QPaintEvent *e) {
QPainter p(this);
const auto [image, rotation] = _track->frameOriginalWithRotation();
if (image.isNull()) {
p.fillRect(e->rect(), Qt::black);
} else {
using namespace Media::View;
auto hq = PainterHighQualityEnabler(p);
if (UsePainterRotation(rotation)) {
if (rotation) {
p.save();
p.rotate(rotation);
}
p.drawImage(RotatedRect(rect(), rotation), image);
if (rotation) {
p.restore();
}
} else if (rotation) {
p.drawImage(rect(), RotateFrameImage(image, rotation));
} else {
p.drawImage(rect(), image);
}
fillBottomShadow(p);
fillTopShadow(p);
}
_track->markFrameShown();
}
void Panel::Incoming::initBottomShadow() {
auto image = QImage(
QSize(1, st::callBottomShadowSize) * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
const auto colorFrom = uint32(0);
const auto colorTill = uint32(74);
const auto rows = image.height();
const auto step = (uint64(colorTill - colorFrom) << 32) / rows;
auto accumulated = uint64();
auto bytes = image.bits();
for (auto y = 0; y != rows; ++y) {
accumulated += step;
const auto color = (colorFrom + uint32(accumulated >> 32)) << 24;
for (auto x = 0; x != image.width(); ++x) {
*(reinterpret_cast<uint32*>(bytes) + x) = color;
}
bytes += image.bytesPerLine();
}
_bottomShadow = Images::PixmapFast(std::move(image));
}
void Panel::Incoming::fillTopShadow(QPainter &p) {
#ifdef Q_OS_WIN
const auto width = parentWidget()->width();
const auto position = QPoint(width - st::callTitleShadow.width(), 0);
const auto shadowArea = QRect(
position,
st::callTitleShadow.size());
const auto fill = shadowArea.intersected(geometry()).translated(-pos());
if (fill.isEmpty()) {
return;
}
p.save();
p.setClipRect(fill);
st::callTitleShadow.paint(p, position - pos(), width);
p.restore();
#endif // Q_OS_WIN
}
void Panel::Incoming::fillBottomShadow(QPainter &p) {
const auto shadowArea = QRect(
0,
parentWidget()->height() - st::callBottomShadowSize,
parentWidget()->width(),
st::callBottomShadowSize);
const auto fill = shadowArea.intersected(geometry()).translated(-pos());
if (fill.isEmpty()) {
return;
}
const auto factor = cIntRetinaFactor();
p.drawPixmap(
fill,
_bottomShadow,
QRect(
0,
factor * (fill.y() - shadowArea.translated(-pos()).y()),
factor,
factor * fill.height()));
}
Panel::Panel(not_null<Call*> call)
: _call(call)
, _user(call->user())
, _window(std::make_unique<Ui::Window>())
#ifndef Q_OS_MAC
, _controls(std::make_unique<Ui::Platform::TitleControls>(
_window->body(),
widget(),
st::callTitle,
[=](bool maximized) { toggleFullScreen(maximized); }))
#endif // !Q_OS_MAC
@@ -214,26 +86,26 @@ Panel::Panel(not_null<Call*> call)
Panel::~Panel() = default;
bool Panel::isActive() const {
return _window->isActiveWindow()
&& _window->isVisible()
&& !(_window->windowState() & Qt::WindowMinimized);
return window()->isActiveWindow()
&& window()->isVisible()
&& !(window()->windowState() & Qt::WindowMinimized);
}
void Panel::showAndActivate() {
if (_window->isHidden()) {
_window->show();
if (window()->isHidden()) {
window()->show();
}
const auto state = _window->windowState();
const auto state = window()->windowState();
if (state & Qt::WindowMinimized) {
_window->setWindowState(state & ~Qt::WindowMinimized);
window()->setWindowState(state & ~Qt::WindowMinimized);
}
_window->raise();
_window->activateWindow();
_window->setFocus();
window()->raise();
window()->activateWindow();
window()->setFocus();
}
void Panel::minimize() {
_window->setWindowState(_window->windowState() | Qt::WindowMinimized);
window()->setWindowState(window()->windowState() | Qt::WindowMinimized);
}
void Panel::replaceCall(not_null<Call*> call) {
@@ -242,26 +114,26 @@ void Panel::replaceCall(not_null<Call*> call) {
}
void Panel::initWindow() {
_window->setAttribute(Qt::WA_OpaquePaintEvent);
_window->setAttribute(Qt::WA_NoSystemBackground);
_window->setWindowIcon(
window()->setAttribute(Qt::WA_OpaquePaintEvent);
window()->setAttribute(Qt::WA_NoSystemBackground);
window()->setWindowIcon(
QIcon(QPixmap::fromImage(Image::Empty()->original(), Qt::ColorOnly)));
_window->setTitle(u" "_q);
_window->setTitleStyle(st::callTitle);
window()->setTitle(u" "_q);
window()->setTitleStyle(st::callTitle);
_window->events(
window()->events(
) | rpl::start_with_next([=](not_null<QEvent*> e) {
if (e->type() == QEvent::Close) {
handleClose();
} else if (e->type() == QEvent::KeyPress) {
if ((static_cast<QKeyEvent*>(e.get())->key() == Qt::Key_Escape)
&& _window->isFullScreen()) {
_window->showNormal();
&& window()->isFullScreen()) {
window()->showNormal();
}
}
}, _window->lifetime());
}, window()->lifetime());
_window->setBodyTitleArea([=](QPoint widgetPoint) {
window()->setBodyTitleArea([=](QPoint widgetPoint) {
using Flag = Ui::WindowTitleHitTestFlag;
if (!widget()->rect().contains(widgetPoint)) {
return Flag::None | Flag(0);
@@ -287,28 +159,31 @@ void Panel::initWindow() {
: (Flag::Move | Flag::FullScreen);
});
#ifdef Q_OS_WIN
// On Windows we replace snap-to-top maximizing with fullscreen.
//
// We have to switch first to showNormal, so that showFullScreen
// will remember correct normal window geometry and next showNormal
// will show it instead of a moving maximized window.
//
// We have to do it in InvokeQueued, otherwise it still captures
// the maximized window geometry and saves it.
//
// I couldn't find a less glitchy way to do that *sigh*.
const auto object = _window->windowHandle();
const auto signal = &QWindow::windowStateChanged;
QObject::connect(object, signal, [=](Qt::WindowState state) {
if (state == Qt::WindowMaximized) {
InvokeQueued(object, [=] {
_window->showNormal();
_window->showFullScreen();
});
}
});
#endif // Q_OS_WIN
// Don't do that, it looks awful :(
//#ifdef Q_OS_WIN
// // On Windows we replace snap-to-top maximizing with fullscreen.
// //
// // We have to switch first to showNormal, so that showFullScreen
// // will remember correct normal window geometry and next showNormal
// // will show it instead of a moving maximized window.
// //
// // We have to do it in InvokeQueued, otherwise it still captures
// // the maximized window geometry and saves it.
// //
// // I couldn't find a less glitchy way to do that *sigh*.
// const auto object = window()->windowHandle();
// const auto signal = &QWindow::windowStateChanged;
// QObject::connect(object, signal, [=](Qt::WindowState state) {
// if (state == Qt::WindowMaximized) {
// InvokeQueued(object, [=] {
// window()->showNormal();
// InvokeQueued(object, [=] {
// window()->showFullScreen();
// });
// });
// }
// });
//#endif // Q_OS_WIN
}
void Panel::initWidget() {
@@ -392,7 +267,7 @@ void Panel::refreshIncomingGeometry() {
Expects(_incoming != nullptr);
if (_incomingFrameSize.isEmpty()) {
_incoming->hide();
_incoming->widget()->hide();
return;
}
const auto to = widget()->size();
@@ -401,7 +276,7 @@ void Panel::refreshIncomingGeometry() {
to,
Qt::KeepAspectRatioByExpanding);
// If we cut out no more than 0.33 of the original, let's use expanding.
// If we cut out no more than 0.25 of the original, let's use expanding.
const auto use = ((big.width() * 3 <= to.width() * 4)
&& (big.height() * 3 <= to.height() * 4))
? big
@@ -409,8 +284,8 @@ void Panel::refreshIncomingGeometry() {
const auto pos = QPoint(
(to.width() - use.width()) / 2,
(to.height() - use.height()) / 2);
_incoming->setGeometry(QRect(pos, use));
_incoming->show();
_incoming->widget()->setGeometry(QRect(pos, use));
_incoming->widget()->show();
}
void Panel::reinitWithCall(Call *call) {
@@ -446,8 +321,9 @@ void Panel::reinitWithCall(Call *call) {
_call->videoOutgoing());
_incoming = std::make_unique<Incoming>(
widget(),
_call->videoIncoming());
_incoming->hide();
_call->videoIncoming(),
_window.backend());
_incoming->widget()->hide();
_call->mutedValue(
) | rpl::start_with_next([=](bool mute) {
@@ -474,28 +350,34 @@ void Panel::reinitWithCall(Call *call) {
_call->videoIncoming()->renderNextFrame(
) | rpl::start_with_next([=] {
const auto track = _call->videoIncoming();
const auto [frame, rotation] = track->frameOriginalWithRotation();
setIncomingSize((rotation == 90 || rotation == 270)
? QSize(frame.height(), frame.width())
: frame.size());
if (_incoming->isHidden()) {
setIncomingSize(track->state() == Webrtc::VideoState::Active
? track->frameSize()
: QSize());
if (_incoming->widget()->isHidden()) {
return;
}
const auto incoming = incomingFrameGeometry();
const auto outgoing = outgoingFrameGeometry();
_incoming->update();
_incoming->widget()->update();
if (incoming.intersects(outgoing)) {
widget()->update(outgoing);
}
}, _callLifetime);
_call->videoIncoming()->stateValue(
) | rpl::start_with_next([=](Webrtc::VideoState state) {
setIncomingSize((state == Webrtc::VideoState::Active)
? _call->videoIncoming()->frameSize()
: QSize());
}, _callLifetime);
_call->videoOutgoing()->renderNextFrame(
) | rpl::start_with_next([=] {
const auto incoming = incomingFrameGeometry();
const auto outgoing = outgoingFrameGeometry();
widget()->update(outgoing);
if (incoming.intersects(outgoing)) {
_incoming->update();
_incoming->widget()->update();
}
}, _callLifetime);
@@ -539,7 +421,13 @@ void Panel::reinitWithCall(Call *call) {
_name->setText(_user->name);
updateStatusText(_call->state());
_incoming->lower();
_answerHangupRedial->raise();
_decline->raise();
_cancel->raise();
_camera->raise();
_mute->raise();
_incoming->widget()->lower();
}
void Panel::createRemoteAudioMute() {
@@ -604,7 +492,7 @@ void Panel::showControls() {
_cancel->setVisible(_cancel->toggled());
const auto shown = !_incomingFrameSize.isEmpty();
_incoming->setVisible(shown);
_incoming->widget()->setVisible(shown);
_name->setVisible(!shown);
_status->setVisible(!shown);
_userpic->setVisible(!shown);
@@ -614,16 +502,20 @@ void Panel::showControls() {
}
void Panel::closeBeforeDestroy() {
_window->close();
window()->close();
reinitWithCall(nullptr);
}
rpl::lifetime &Panel::lifetime() {
return window()->lifetime();
}
void Panel::initGeometry() {
const auto center = Core::App().getPointForCallPanelCenter();
const auto initRect = QRect(0, 0, st::callWidth, st::callHeight);
_window->setGeometry(initRect.translated(center - initRect.center()));
_window->setMinimumSize({ st::callWidthMin, st::callHeightMin });
_window->show();
window()->setGeometry(initRect.translated(center - initRect.center()));
window()->setMinimumSize({ st::callWidthMin, st::callHeightMin });
window()->show();
updateControlsGeometry();
}
@@ -641,16 +533,16 @@ void Panel::refreshOutgoingPreviewInBody(State state) {
void Panel::toggleFullScreen(bool fullscreen) {
if (fullscreen) {
_window->showFullScreen();
window()->showFullScreen();
} else {
_window->showNormal();
window()->showNormal();
}
}
QRect Panel::incomingFrameGeometry() const {
return (!_incoming || _incoming->isHidden())
return (!_incoming || _incoming->widget()->isHidden())
? QRect()
: _incoming->geometry();
: _incoming->widget()->geometry();
}
QRect Panel::outgoingFrameGeometry() const {
@@ -666,15 +558,31 @@ void Panel::updateControlsGeometry() {
}
if (_fingerprint) {
#ifndef Q_OS_MAC
const auto minRight = _controls->geometry().width()
+ st::callFingerprintTop;
const auto controlsGeometry = _controls->geometry();
const auto halfWidth = widget()->width() / 2;
const auto minLeft = (controlsGeometry.center().x() < halfWidth)
? (controlsGeometry.width() + st::callFingerprintTop)
: 0;
const auto minRight = (controlsGeometry.center().x() >= halfWidth)
? (controlsGeometry.width() + st::callFingerprintTop)
: 0;
_incoming->setControlsAlignment(minLeft
? style::al_left
: style::al_right);
#else // !Q_OS_MAC
const auto minLeft = 0;
const auto minRight = 0;
#endif // _controls
const auto desired = (widget()->width() - _fingerprint->width()) / 2;
_fingerprint->moveToRight(
std::max(desired, minRight),
st::callFingerprintTop);
if (minLeft) {
_fingerprint->moveToLeft(
std::max(desired, minLeft),
st::callFingerprintTop);
} else {
_fingerprint->moveToRight(
std::max(desired, minRight),
st::callFingerprintTop);
}
}
const auto innerHeight = std::max(widget()->height(), st::callHeightMin);
const auto innerWidth = widget()->width() - 2 * st::callInnerPadding;
@@ -786,13 +694,13 @@ void Panel::paint(QRect clip) {
Painter p(widget());
auto region = QRegion(clip);
if (!_incoming->isHidden()) {
region = region.subtracted(QRegion(_incoming->geometry()));
if (!_incoming->widget()->isHidden()) {
region = region.subtracted(QRegion(_incoming->widget()->geometry()));
}
for (const auto rect : region) {
p.fillRect(rect, st::callBgOpaque);
}
if (_incoming && _incoming->isHidden()) {
if (_incoming && _incoming->widget()->isHidden()) {
_call->videoIncoming()->markFrameShown();
}
}
@@ -803,8 +711,12 @@ void Panel::handleClose() {
}
}
not_null<Ui::Window*> Panel::window() const {
return _window.window();
}
not_null<Ui::RpWidget*> Panel::widget() const {
return _window->body();
return _window.widget();
}
void Panel::stateChanged(State state) {
@@ -820,7 +732,7 @@ void Panel::stateChanged(State state) {
auto toggleButton = [&](auto &&button, bool visible) {
button->toggle(
visible,
_window->isHidden()
window()->isHidden()
? anim::type::instant
: anim::type::normal);
};

View File

@@ -12,6 +12,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/object_ptr.h"
#include "calls/calls_call.h"
#include "ui/effects/animations.h"
#include "ui/gl/gl_window.h"
#include "ui/rp_widget.h"
class Image;
@@ -30,6 +31,9 @@ class FadeWrap;
template <typename Widget>
class PaddingWrap;
class Window;
namespace GL {
enum class Backend;
} // namespace GL
namespace Platform {
class TitleControls;
} // namespace Platform
@@ -57,6 +61,8 @@ public:
void replaceCall(not_null<Call*> call);
void closeBeforeDestroy();
rpl::lifetime &lifetime();
private:
class Incoming;
using State = Call::State;
@@ -67,6 +73,7 @@ private:
Redial,
};
[[nodiscard]] not_null<Ui::Window*> window() const;
[[nodiscard]] not_null<Ui::RpWidget*> widget() const;
void paint(QRect clip);
@@ -80,9 +87,6 @@ private:
void handleClose();
QRect signalBarsRect() const;
void paintSignalBarsBg(Painter &p);
void updateControlsGeometry();
void updateHangupGeometry();
void updateStatusGeometry();
@@ -105,7 +109,7 @@ private:
Call *_call = nullptr;
not_null<UserData*> _user;
const std::unique_ptr<Ui::Window> _window;
Ui::GL::Window _window;
std::unique_ptr<Incoming> _incoming;
#ifndef Q_OS_MAC

View File

@@ -22,7 +22,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "calls/calls_call.h"
#include "calls/calls_instance.h"
#include "calls/calls_signal_bars.h"
#include "calls/calls_group_menu.h" // Group::LeaveBox.
#include "calls/group/calls_group_call.h"
#include "calls/group/calls_group_menu.h" // Group::LeaveBox.
#include "history/view/history_view_group_call_tracker.h" // ContentByCall.
#include "data/data_user.h"
#include "data/data_group_call.h"
@@ -279,8 +280,7 @@ void TopBar::initControls() {
if (const auto call = _call.get()) {
call->setMuted(!call->muted());
} else if (const auto group = _groupCall.get()) {
if (group->muted() == MuteState::ForceMuted
|| group->muted() == MuteState::RaisedHand) {
if (group->mutedByAdmin()) {
Ui::Toast::Show(tr::lng_group_call_force_muted_sub(tr::now));
} else {
group->setMuted((group->muted() == MuteState::Muted)

View File

@@ -0,0 +1,577 @@
/*
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_video_incoming.h"
#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_shader.h"
#include "ui/gl/gl_image.h"
#include "ui/gl/gl_primitives.h"
#include "media/view/media_view_pip.h"
#include "webrtc/webrtc_video_track.h"
#include "styles/style_calls.h"
#include <QtGui/QOpenGLShader>
#include <QtGui/QOpenGLBuffer>
namespace Calls {
namespace {
constexpr auto kBottomShadowAlphaMax = 74;
using namespace Ui::GL;
[[nodiscard]] ShaderPart FragmentBottomShadow() {
return {
.header = R"(
uniform vec3 shadow; // fullHeight, shadowTop, maxOpacity
)",
.body = R"(
float shadowCoord = shadow.y - gl_FragCoord.y;
float shadowValue = clamp(shadowCoord / shadow.x, 0., 1.);
float shadowShown = shadowValue * shadow.z;
result = vec4(min(result.rgb, vec3(1.)) * (1. - shadowShown), result.a);
)",
};
}
} // namespace
class Panel::Incoming::RendererGL final : public Ui::GL::Renderer {
public:
explicit RendererGL(not_null<Incoming*> owner);
void init(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
void deinit(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
void paint(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) override;
private:
void uploadTexture(
QOpenGLFunctions &f,
GLint internalformat,
GLint format,
QSize size,
QSize hasSize,
int stride,
const void *data) const;
void validateShadowImage();
const not_null<Incoming*> _owner;
QSize _viewport;
float _factor = 1.;
QVector2D _uniformViewport;
std::optional<QOpenGLBuffer> _contentBuffer;
std::optional<QOpenGLShaderProgram> _argb32Program;
QOpenGLShader *_texturedVertexShader = nullptr;
std::optional<QOpenGLShaderProgram> _yuv420Program;
std::optional<QOpenGLShaderProgram> _imageProgram;
Ui::GL::Textures<4> _textures;
QSize _rgbaSize;
QSize _lumaSize;
QSize _chromaSize;
int _trackFrameIndex = 0;
Ui::GL::Image _controlsShadowImage;
QRect _controlsShadowLeft;
QRect _controlsShadowRight;
rpl::lifetime _lifetime;
};
class Panel::Incoming::RendererSW final : public Ui::GL::Renderer {
public:
explicit RendererSW(not_null<Incoming*> owner);
void paintFallback(
Painter &&p,
const QRegion &clip,
Ui::GL::Backend backend) override;
private:
void initBottomShadow();
void fillTopShadow(QPainter &p);
void fillBottomShadow(QPainter &p);
const not_null<Incoming*> _owner;
QImage _bottomShadow;
};
Panel::Incoming::RendererGL::RendererGL(not_null<Incoming*> owner)
: _owner(owner) {
style::PaletteChanged(
) | rpl::start_with_next([=] {
_controlsShadowImage.invalidate();
}, _lifetime);
}
void Panel::Incoming::RendererGL::init(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
constexpr auto kQuads = 2;
constexpr auto kQuadVertices = kQuads * 4;
constexpr auto kQuadValues = kQuadVertices * 4;
_contentBuffer.emplace();
_contentBuffer->setUsagePattern(QOpenGLBuffer::DynamicDraw);
_contentBuffer->create();
_contentBuffer->bind();
_contentBuffer->allocate(kQuadValues * sizeof(GLfloat));
_textures.ensureCreated(f);
_imageProgram.emplace();
_texturedVertexShader = LinkProgram(
&*_imageProgram,
VertexShader({
VertexViewportTransform(),
VertexPassTextureCoord(),
}),
FragmentShader({
FragmentSampleARGB32Texture(),
})).vertex;
_argb32Program.emplace();
LinkProgram(
&*_argb32Program,
_texturedVertexShader,
FragmentShader({
FragmentSampleARGB32Texture(),
FragmentBottomShadow(),
}));
_yuv420Program.emplace();
LinkProgram(
&*_yuv420Program,
_texturedVertexShader,
FragmentShader({
FragmentSampleYUV420Texture(),
FragmentBottomShadow(),
}));
}
void Panel::Incoming::RendererGL::deinit(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
_textures.destroy(f);
_imageProgram = std::nullopt;
_texturedVertexShader = nullptr;
_argb32Program = std::nullopt;
_yuv420Program = std::nullopt;
_contentBuffer = std::nullopt;
}
void Panel::Incoming::RendererGL::paint(
not_null<QOpenGLWidget*> widget,
QOpenGLFunctions &f) {
const auto markGuard = gsl::finally([&] {
_owner->_track->markFrameShown();
});
const auto data = _owner->_track->frameWithInfo(false);
if (data.format == Webrtc::FrameFormat::None) {
return;
}
const auto factor = widget->devicePixelRatio();
if (_factor != factor) {
_factor = factor;
_controlsShadowImage.invalidate();
}
_viewport = widget->size();
_uniformViewport = QVector2D(
_viewport.width() * _factor,
_viewport.height() * _factor);
const auto rgbaFrame = (data.format == Webrtc::FrameFormat::ARGB32);
const auto upload = (_trackFrameIndex != data.index);
_trackFrameIndex = data.index;
auto &program = rgbaFrame ? _argb32Program : _yuv420Program;
program->bind();
if (rgbaFrame) {
Assert(!data.original.isNull());
f.glActiveTexture(GL_TEXTURE0);
_textures.bind(f, 0);
if (upload) {
uploadTexture(
f,
GL_RGBA,
GL_RGBA,
data.original.size(),
_rgbaSize,
data.original.bytesPerLine() / 4,
data.original.constBits());
_rgbaSize = data.original.size();
}
program->setUniformValue("s_texture", GLint(0));
} else {
Assert(data.format == Webrtc::FrameFormat::YUV420);
Assert(!data.yuv420->size.isEmpty());
const auto yuv = data.yuv420;
const auto format = Ui::GL::CurrentSingleComponentFormat();
f.glActiveTexture(GL_TEXTURE0);
_textures.bind(f, 1);
if (upload) {
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
uploadTexture(
f,
format,
format,
yuv->size,
_lumaSize,
yuv->y.stride,
yuv->y.data);
_lumaSize = yuv->size;
}
f.glActiveTexture(GL_TEXTURE1);
_textures.bind(f, 2);
if (upload) {
uploadTexture(
f,
format,
format,
yuv->chromaSize,
_chromaSize,
yuv->u.stride,
yuv->u.data);
}
f.glActiveTexture(GL_TEXTURE2);
_textures.bind(f, 3);
if (upload) {
uploadTexture(
f,
format,
format,
yuv->chromaSize,
_chromaSize,
yuv->v.stride,
yuv->v.data);
_chromaSize = yuv->chromaSize;
f.glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
}
program->setUniformValue("y_texture", GLint(0));
program->setUniformValue("u_texture", GLint(1));
program->setUniformValue("v_texture", GLint(2));
}
const auto rect = TransformRect(
widget->rect(),
_viewport,
_factor);
std::array<std::array<GLfloat, 2>, 4> texcoords = { {
{ { 0.f, 1.f } },
{ { 1.f, 1.f } },
{ { 1.f, 0.f } },
{ { 0.f, 0.f } },
} };
if (const auto shift = (data.rotation / 90); shift != 0) {
std::rotate(
begin(texcoords),
begin(texcoords) + shift,
end(texcoords));
}
const auto width = widget->parentWidget()->width();
const auto left = (_owner->_topControlsAlignment == style::al_left);
validateShadowImage();
const auto position = left
? QPoint()
: QPoint(width - st::callTitleShadowRight.width(), 0);
const auto translated = position - widget->pos();
const auto shadowArea = QRect(translated, st::callTitleShadowLeft.size());
const auto shadow = _controlsShadowImage.texturedRect(
shadowArea,
(left ? _controlsShadowLeft : _controlsShadowRight),
widget->rect());
const auto shadowRect = TransformRect(
shadow.geometry,
_viewport,
_factor);
const GLfloat coords[] = {
rect.left(), rect.top(),
texcoords[0][0], texcoords[0][1],
rect.right(), rect.top(),
texcoords[1][0], texcoords[1][1],
rect.right(), rect.bottom(),
texcoords[2][0], texcoords[2][1],
rect.left(), rect.bottom(),
texcoords[3][0], texcoords[3][1],
shadowRect.left(), shadowRect.top(),
shadow.texture.left(), shadow.texture.bottom(),
shadowRect.right(), shadowRect.top(),
shadow.texture.right(), shadow.texture.bottom(),
shadowRect.right(), shadowRect.bottom(),
shadow.texture.right(), shadow.texture.top(),
shadowRect.left(), shadowRect.bottom(),
shadow.texture.left(), shadow.texture.top(),
};
_contentBuffer->write(0, coords, sizeof(coords));
const auto bottomShadowArea = QRect(
0,
widget->parentWidget()->height() - st::callBottomShadowSize,
widget->parentWidget()->width(),
st::callBottomShadowSize);
const auto bottomShadowFill = bottomShadowArea.intersected(
widget->geometry()).translated(-widget->pos());
const auto shadowHeight = bottomShadowFill.height();
const auto shadowAlpha = (shadowHeight * kBottomShadowAlphaMax)
/ (st::callBottomShadowSize * 255.);
program->setUniformValue("viewport", _uniformViewport);
program->setUniformValue("shadow", QVector3D(
shadowHeight * _factor,
TransformRect(bottomShadowFill, _viewport, _factor).bottom(),
shadowAlpha));
FillTexturedRectangle(f, &*program);
#ifndef Q_OS_MAC
if (!shadowRect.empty()) {
f.glEnable(GL_BLEND);
f.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
const auto guard = gsl::finally([&] {
f.glDisable(GL_BLEND);
});
_imageProgram->bind();
_imageProgram->setUniformValue("viewport", _uniformViewport);
_imageProgram->setUniformValue("s_texture", GLint(0));
f.glActiveTexture(GL_TEXTURE0);
_controlsShadowImage.bind(f);
FillTexturedRectangle(f, &*_imageProgram, 4);
}
#endif // Q_OS_MAC
}
void Panel::Incoming::RendererGL::validateShadowImage() {
if (_controlsShadowImage) {
return;
}
const auto size = st::callTitleShadowLeft.size();
const auto full = QSize(size.width(), 2 * size.height()) * int(_factor);
auto image = QImage(full, QImage::Format_ARGB32_Premultiplied);
image.setDevicePixelRatio(_factor);
image.fill(Qt::transparent);
{
auto p = QPainter(&image);
st::callTitleShadowLeft.paint(p, 0, 0, size.width());
_controlsShadowLeft = QRect(0, 0, full.width(), full.height() / 2);
st::callTitleShadowRight.paint(p, 0, size.height(), size.width());
_controlsShadowRight = QRect(
0,
full.height() / 2,
full.width(),
full.height() / 2);
}
_controlsShadowImage.setImage(std::move(image));
}
void Panel::Incoming::RendererGL::uploadTexture(
QOpenGLFunctions &f,
GLint internalformat,
GLint format,
QSize size,
QSize hasSize,
int stride,
const void *data) const {
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
if (hasSize != size) {
f.glTexImage2D(
GL_TEXTURE_2D,
0,
internalformat,
size.width(),
size.height(),
0,
format,
GL_UNSIGNED_BYTE,
data);
} else {
f.glTexSubImage2D(
GL_TEXTURE_2D,
0,
0,
0,
size.width(),
size.height(),
format,
GL_UNSIGNED_BYTE,
data);
}
f.glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
Panel::Incoming::RendererSW::RendererSW(not_null<Incoming*> owner)
: _owner(owner) {
initBottomShadow();
}
void Panel::Incoming::RendererSW::paintFallback(
Painter &&p,
const QRegion &clip,
Ui::GL::Backend backend) {
const auto markGuard = gsl::finally([&] {
_owner->_track->markFrameShown();
});
const auto data = _owner->_track->frameWithInfo(true);
const auto &image = data.original;
const auto rotation = data.rotation;
if (image.isNull()) {
p.fillRect(clip.boundingRect(), Qt::black);
} else {
const auto rect = _owner->widget()->rect();
using namespace Media::View;
auto hq = PainterHighQualityEnabler(p);
if (UsePainterRotation(rotation)) {
if (rotation) {
p.save();
p.rotate(rotation);
}
p.drawImage(RotatedRect(rect, rotation), image);
if (rotation) {
p.restore();
}
} else if (rotation) {
p.drawImage(rect, RotateFrameImage(image, rotation));
} else {
p.drawImage(rect, image);
}
fillBottomShadow(p);
fillTopShadow(p);
}
}
void Panel::Incoming::RendererSW::initBottomShadow() {
auto image = QImage(
QSize(1, st::callBottomShadowSize) * cIntRetinaFactor(),
QImage::Format_ARGB32_Premultiplied);
const auto colorFrom = uint32(0);
const auto colorTill = uint32(kBottomShadowAlphaMax);
const auto rows = image.height();
const auto step = (uint64(colorTill - colorFrom) << 32) / rows;
auto accumulated = uint64();
auto bytes = image.bits();
for (auto y = 0; y != rows; ++y) {
accumulated += step;
const auto color = (colorFrom + uint32(accumulated >> 32)) << 24;
for (auto x = 0; x != image.width(); ++x) {
*(reinterpret_cast<uint32*>(bytes) + x) = color;
}
bytes += image.bytesPerLine();
}
_bottomShadow = std::move(image);
}
void Panel::Incoming::RendererSW::fillTopShadow(QPainter &p) {
#ifndef Q_OS_MAC
const auto widget = _owner->widget();
const auto width = widget->parentWidget()->width();
const auto left = (_owner->_topControlsAlignment == style::al_left);
const auto &icon = left
? st::callTitleShadowLeft
: st::callTitleShadowRight;
const auto position = left
? QPoint()
: QPoint(width - icon.width(), 0);
const auto shadowArea = QRect(position, icon.size());
const auto fill = shadowArea.intersected(
widget->geometry()).translated(-widget->pos());
if (fill.isEmpty()) {
return;
}
p.save();
p.setClipRect(fill);
icon.paint(p, position - widget->pos(), width);
p.restore();
#endif // Q_OS_MAC
}
void Panel::Incoming::RendererSW::fillBottomShadow(QPainter &p) {
const auto widget = _owner->widget();
const auto shadowArea = QRect(
0,
widget->parentWidget()->height() - st::callBottomShadowSize,
widget->parentWidget()->width(),
st::callBottomShadowSize);
const auto fill = shadowArea.intersected(
widget->geometry()).translated(-widget->pos());
if (fill.isEmpty()) {
return;
}
const auto factor = cIntRetinaFactor();
p.drawImage(
fill,
_bottomShadow,
QRect(
0,
(factor
* (fill.y() - shadowArea.translated(-widget->pos()).y())),
factor,
factor * fill.height()));
}
Panel::Incoming::Incoming(
not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track,
Ui::GL::Backend backend)
: _surface(Ui::GL::CreateSurface(parent, chooseRenderer(backend)))
, _track(track) {
widget()->setAttribute(Qt::WA_OpaquePaintEvent);
widget()->setAttribute(Qt::WA_TransparentForMouseEvents);
}
not_null<QWidget*> Panel::Incoming::widget() const {
return _surface->rpWidget();
}
not_null<Ui::RpWidgetWrap*> Panel::Incoming::rp() const {
return _surface.get();
}
void Panel::Incoming::setControlsAlignment(style::align align) {
if (_topControlsAlignment != align) {
_topControlsAlignment = align;
widget()->update();
}
}
Ui::GL::ChosenRenderer Panel::Incoming::chooseRenderer(
Ui::GL::Backend backend) {
_opengl = (backend == Ui::GL::Backend::OpenGL);
return {
.renderer = (_opengl
? std::unique_ptr<Ui::GL::Renderer>(
std::make_unique<RendererGL>(this))
: std::make_unique<RendererSW>(this)),
.backend = backend,
};
}
} // namespace Calls

View File

@@ -0,0 +1,45 @@
/*
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
*/
#pragma once
#include "calls/calls_panel.h"
namespace Ui::GL {
enum class Backend;
struct ChosenRenderer;
} // namespace Ui::GL
namespace Calls {
class Panel::Incoming final {
public:
Incoming(
not_null<QWidget*> parent,
not_null<Webrtc::VideoTrack*> track,
Ui::GL::Backend backend);
[[nodiscard]] not_null<QWidget*> widget() const;
[[nodiscard]] not_null<Ui::RpWidgetWrap*> rp() const;
void setControlsAlignment(style::align align);
private:
class RendererGL;
class RendererSW;
[[nodiscard]] Ui::GL::ChosenRenderer chooseRenderer(
Ui::GL::Backend backend);
const std::unique_ptr<Ui::RpWidgetWrap> _surface;
const not_null<Webrtc::VideoTrack*> _track;
style::align _topControlsAlignment = style::al_left;
bool _opengl = false;
};
} // namespace Calls

View File

@@ -5,10 +5,10 @@ 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_choose_join_as.h"
#include "calls/group/calls_choose_join_as.h"
#include "calls/calls_group_common.h"
#include "calls/calls_group_menu.h"
#include "calls/group/calls_group_common.h"
#include "calls/group/calls_group_menu.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "data/data_channel.h"

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